SMetric3 metric_based_on_surface_curvature(const GFace *gf, double u, double v, bool surface_isotropic, double d_normal , double d_tangent_max) { if (gf->geomType() == GEntity::Plane)return SMetric3(1.e-12); double cmax, cmin; SVector3 dirMax,dirMin; cmax = gf->curvatures(SPoint2(u, v),&dirMax, &dirMin, &cmax,&cmin); if (cmin == 0)cmin =1.e-12; if (cmax == 0)cmax =1.e-12; double lambda1 = ((2 * M_PI) /( fabs(cmin) * CTX::instance()->mesh.minCircPoints ) ); double lambda2 = ((2 * M_PI) /( fabs(cmax) * CTX::instance()->mesh.minCircPoints ) ); SVector3 Z = crossprod(dirMax,dirMin); if (surface_isotropic) lambda2 = lambda1 = std::min(lambda2,lambda1); dirMin.normalize(); dirMax.normalize(); Z.normalize(); lambda1 = std::max(lambda1, CTX::instance()->mesh.lcMin); lambda2 = std::max(lambda2, CTX::instance()->mesh.lcMin); lambda1 = std::min(lambda1, CTX::instance()->mesh.lcMax); lambda2 = std::min(lambda2, CTX::instance()->mesh.lcMax); double lambda3 = std::min(d_normal, CTX::instance()->mesh.lcMax); lambda3 = std::max(lambda3, CTX::instance()->mesh.lcMin); lambda1 = std::min(lambda1, d_tangent_max); lambda2 = std::min(lambda2, d_tangent_max); SMetric3 curvMetric (1./(lambda1*lambda1),1./(lambda2*lambda2), 1./(lambda3*lambda3), dirMin, dirMax, Z ); return curvMetric; }
SMetric3 LC_MVertex_CURV_ANISO(GEntity *ge, double U, double V) { bool iso_surf = CTX::instance()->mesh.lcFromCurvature == 2; switch(ge->dim()){ case 0: return metric_based_on_surface_curvature((const GVertex *)ge, iso_surf); case 1: return metric_based_on_surface_curvature((const GEdge *)ge, U, iso_surf); case 2: return metric_based_on_surface_curvature((const GFace *)ge, U, V, iso_surf); } Msg::Error("Curvature control impossible to compute for a volume!"); return SMetric3(); }
// anisotropic version of the background field SMetric3 BGM_MeshMetric(GEntity *ge, double U, double V, double X, double Y, double Z) { // Metrics based on element size // Element size = min. between default lc and lc from point (if applicable), // constrained by lcMin and lcMax double lc = CTX::instance()->lc; if(CTX::instance()->mesh.lcFromPoints && ge->dim() < 2) lc = std::min(lc, LC_MVertex_PNTS(ge, U, V)); lc = std::min(lc, ge->getMeshSize()); lc = std::max(lc, CTX::instance()->mesh.lcMin); lc = std::min(lc, CTX::instance()->mesh.lcMax); if(lc <= 0.){ Msg::Error("Wrong mesh element size lc = %g (lcmin = %g, lcmax = %g)", lc, CTX::instance()->mesh.lcMin, CTX::instance()->mesh.lcMax); lc = CTX::instance()->lc; } SMetric3 m0(1./(lc*lc)); // Intersect with metrics from fields if applicable FieldManager *fields = ge->model()->getFields(); SMetric3 m1 = m0; if(fields->getBackgroundField() > 0){ Field *f = fields->get(fields->getBackgroundField()); if(f) { SMetric3 l4; if (!f->isotropic()) (*f)(X, Y, Z, l4, ge); else { const double L = (*f)(X, Y, Z, ge); l4 = SMetric3(1/(L*L)); } m1 = intersection(l4, m0); } } // Intersect with metrics from curvature if applicable SMetric3 m = (CTX::instance()->mesh.lcFromCurvature && ge->dim() < 3) ? intersection(m1, LC_MVertex_CURV_ANISO(ge, U, V)) : m1; return m; }
SMetric3 buildMetricTangentToCurve(SVector3 &t, double l_t, double l_n) { if (l_t == 0.0) return SMetric3(1.e-22); SVector3 a; if (fabs(t(0)) <= fabs(t(1)) && fabs(t(0)) <= fabs(t(2))){ a = SVector3(1,0,0); } else if (fabs(t(1)) <= fabs(t(0)) && fabs(t(1)) <= fabs(t(2))){ a = SVector3(0,1,0); } else{ a = SVector3(0,0,1); } SVector3 b = crossprod (t,a); SVector3 c = crossprod (b,t); b.normalize(); c.normalize(); t.normalize(); SMetric3 Metric (1./(l_t*l_t),1./(l_n*l_n),1./(l_n*l_n),t,b,c); // printf("bmttc %g %g %g %g %g\n",l_t,l_n,Metric(0,0),Metric(0,1),Metric(1,1)); return Metric; }
void Centerline::operator() (double x, double y, double z, SMetric3 &metr, GEntity *ge) { if (update_needed){ std::ifstream input; input.open(fileName.c_str()); if(StatFile(fileName)) Msg::Fatal("Centerline file '%s' does not exist", fileName.c_str()); importFile(fileName); buildKdTree(); update_needed = false; } //take xyz = closest point on boundary in case we are on //the planar IN/OUT FACES or in VOLUME double xyz[3] = {x,y,z}; bool onTubularSurface = true; double ds = 0.0; bool isCompound = (ge->dim() == 2 && ge->geomType() == GEntity::CompoundSurface) ? true : false; bool onInOutlets = (ge->geomType() == GEntity::Plane) ? true: false; std::list<GFace*> cFaces; if (isCompound) cFaces = ((GFaceCompound*)ge)->getCompounds(); if ( ge->dim() == 3 || (ge->dim() == 2 && ge->geomType() == GEntity::Plane) || (isCompound && (*cFaces.begin())->geomType() == GEntity::Plane) ){ onTubularSurface = false; } ANNidx index[1]; ANNdist dist[1]; kdtreeR->annkSearch(xyz, 1, index, dist); if (! onTubularSurface){ ANNpointArray nodesR = kdtreeR->thePoints(); ds = sqrt(dist[0]); xyz[0] = nodesR[index[0]][0]; xyz[1] = nodesR[index[0]][1]; xyz[2] = nodesR[index[0]][2]; } ANNidx index2[2]; ANNdist dist2[2]; kdtree->annkSearch(xyz, 2, index2, dist2); double radMax = sqrt(dist2[0]); ANNpointArray nodes = kdtree->thePoints(); SVector3 p0(nodes[index2[0]][0], nodes[index2[0]][1], nodes[index2[0]][2]); SVector3 p1(nodes[index2[1]][0], nodes[index2[1]][1], nodes[index2[1]][2]); //dir_a = direction along the centerline //dir_n = normal direction of the disk //dir_t = tangential direction of the disk SVector3 dir_a = p1-p0; dir_a.normalize(); SVector3 dir_n(xyz[0]-p0.x(), xyz[1]-p0.y(), xyz[2]-p0.z()); dir_n.normalize(); SVector3 dir_cross = crossprod(dir_a,dir_n); dir_cross.normalize(); // if (ge->dim()==3){ // printf("coucou dim ==3 !!!!!!!!!!!!!!! \n"); // SVector3 d1,d2,d3; // computeCrossField(x,y,z,d1,d2,d3); // exit(1); // } //find discrete curvature at closest vertex Curvature& curvature = Curvature::getInstance(); if( !Curvature::valueAlreadyComputed() ) { Msg::Info("Need to compute discrete curvature"); Curvature::typeOfCurvature type = Curvature::RUSIN; curvature.computeCurvature(current, type); } double curv, cMin, cMax; SVector3 dMin, dMax; int isAbs = 1.0; curvature.vertexNodalValuesAndDirections(vertices[index[0]],&dMax, &dMin, &cMax, &cMin, isAbs); curvature.vertexNodalValues(vertices[index[0]], curv, 1); if (cMin == 0) cMin =1.e-12; if (cMax == 0) cMax =1.e-12; double rhoMin = 1./cMin; double rhoMax = 1./cMax; //double signMin = (rhoMin > 0.0) ? -1.0: 1.0; //double signMax = (rhoMax > 0.0) ? -1.0: 1.0; //user-defined parameters //define h_n, h_t1, and h_t2 double thickness = radMax/3.; double h_far = radMax/5.; double beta = (ds <= thickness) ? 1.2 : 2.1; //CTX::instance()->mesh.smoothRatio; double ddist = (ds <= thickness) ? ds: thickness; double h_n_0 = thickness/20.; double h_n = std::min( (h_n_0+ds*log(beta)), h_far); double betaMin = 10.0; double betaMax = 3.1; double oneOverD2_min = 1./(2.*rhoMin*rhoMin*(betaMin*betaMin-1)) * (sqrt(1+ (4.*rhoMin*rhoMin*(betaMin*betaMin-1))/(h_n*h_n))-1.); double oneOverD2_max = 1./(2.*rhoMax*rhoMax*(betaMax*betaMax-1)) * (sqrt(1+ (4.*rhoMax*rhoMax*(betaMax*betaMax-1))/(h_n*h_n))-1.); double h_t1_0 = sqrt(1./oneOverD2_min); double h_t2_0 = sqrt(1./oneOverD2_max); //double h_t1 = h_t1_0*(rhoMin+signMin*ddist)/rhoMin ; //double h_t2 = h_t2_0*(rhoMax+signMax*ddist)/rhoMax ; double h_t1 = std::min( (h_t1_0+(ddist*log(beta))), radMax); double h_t2 = std::min( (h_t2_0+(ddist*log(beta))), h_far); double dCenter = radMax-ds; double h_a_0 = 0.5*radMax; double h_a = h_a_0 - (h_a_0-h_t1_0)/(radMax)*dCenter; //length between min and max double lcMin = ((2 * M_PI *radMax) /( 50*nbPoints )); //CTX::instance()->mesh.lcMin; double lcMax = lcMin*2000.; //CTX::instance()->mesh.lcMax; h_n = std::max(h_n, lcMin); h_n = std::min(h_n, lcMax); h_t1 = std::max(h_t1, lcMin); h_t1 = std::min(h_t1, lcMax); h_t2 = std::max(h_t2, lcMin); h_t2 = std::min(h_t2, lcMax); //curvature metric SMetric3 curvMetric, curvMetric1, curvMetric2; SMetric3 centMetric1, centMetric2, centMetric; if (onInOutlets){ metr = buildMetricTangentToCurve(dir_n,h_n,h_t2); } else { //on surface and in volume boundary layer if ( ds < thickness ){ metr = metricBasedOnSurfaceCurvature(dMin, dMax, cMin, cMax, h_n, h_t1, h_t2); } //in volume else { //curvMetric = metricBasedOnSurfaceCurvature(dMin, dMax, cMin, cMax, h_n, h_t1, h_t2); metr = SMetric3( 1./(h_a*h_a), 1./(h_n*h_n), 1./(h_n*h_n), dir_a, dir_n, dir_cross); //metr = intersection_conserveM1_bis(metr, curvMetric); //metr = intersection_conserveM1(metr,curvMetric); //metr = intersection_conserve_mostaniso(metr, curvMetric); //metr = intersection(metr,curvMetric); } } return; }
bool frameFieldBackgroundMesh2D::compute_RK_infos(double u,double v, double x, double y, double z, RK_form &infos) { // check if point is in domain if (!inDomain(u,v)) return false; // get stored angle double angle_current = angle(u,v); // compute t1,t2: cross field directions // get the unit normal at that point GFace *face = dynamic_cast<GFace*>(gf); if(!face) { Msg::Error("Entity is not a face in background mesh"); return false; } Pair<SVector3, SVector3> der = face->firstDer(SPoint2(u,v)); SVector3 s1 = der.first(); SVector3 s2 = der.second(); SVector3 n = crossprod(s1,s2); n.normalize(); SVector3 basis_u = s1; basis_u.normalize(); SVector3 basis_v = crossprod(n,basis_u); // normalize vector t1 that is tangent to gf at uv SVector3 t1 = basis_u * cos(angle_current) + basis_v * sin(angle_current) ; t1.normalize(); // compute the second direction t2 and normalize (t1,t2,n) is the tangent frame SVector3 t2 = crossprod(n,t1); t2.normalize(); // get metric double L = size(u,v); infos.metricField = SMetric3(1./(L*L)); FieldManager *fields = gf->model()->getFields(); if(fields->getBackgroundField() > 0) { Field *f = fields->get(fields->getBackgroundField()); if (!f->isotropic()) { (*f)(x,y,z, infos.metricField,gf); } else { L = (*f)(x,y,z,gf); infos.metricField = SMetric3(1./(L*L)); } } double M = dot(s1,s1); double N = dot(s2,s2); double E = dot(s1,s2); // compute the first fundamental form i.e. the metric tensor at the point // M_{ij} = s_i \cdot s_j double metric[2][2] = {{M,E},{E,N}}; // get sizes double size_1 = sqrt(1. / dot(t1,infos.metricField,t1)); double size_2 = sqrt(1. / dot(t2,infos.metricField,t2)); // compute covariant coordinates of t1 and t2 - cross field directions in parametric domain double covar1[2],covar2[2]; // t1 = a s1 + b s2 --> // t1 . s1 = a M + b E // t1 . s2 = a E + b N --> solve the 2 x 2 system // and get covariant coordinates a and b double rhs1[2] = {dot(t1,s1),dot(t1,s2)}; bool singular = false; if (!sys2x2(metric,rhs1,covar1)) { Msg::Info("Argh surface %d %g %g %g -- %g %g %g -- %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z(),size_1,size_2); covar1[1] = 1.0; covar1[0] = 0.0; singular = true; } double rhs2[2] = {dot(t2,s1),dot(t2,s2)}; if (!sys2x2(metric,rhs2,covar2)) { Msg::Info("Argh surface %d %g %g %g -- %g %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z()); covar2[0] = 1.0; covar2[1] = 0.0; singular = true; } // transform the sizes with respect to the metric // consider a vector v of size 1 in the parameter plane // its length is sqrt (v^T M v) --> if I want a real size // of size1 in direction v, it should be sqrt(v^T M v) * size1 double l1 = sqrt(covar1[0]*covar1[0]+covar1[1]*covar1[1]); double l2 = sqrt(covar2[0]*covar2[0]+covar2[1]*covar2[1]); covar1[0] /= l1; covar1[1] /= l1; covar2[0] /= l2; covar2[1] /= l2; double size_param_1 = size_1 / sqrt ( M*covar1[0]*covar1[0]+ 2*E*covar1[1]*covar1[0]+ N*covar1[1]*covar1[1]); double size_param_2 = size_2 / sqrt ( M*covar2[0]*covar2[0]+ 2*E*covar2[1]*covar2[0]+ N*covar2[1]*covar2[1]); if (singular) { size_param_1 = size_param_2 = std::min (size_param_1,size_param_2); } // filling form... infos.t1 = t1; infos.h.first = size_1; infos.h.second = size_2; infos.paramh.first = size_param_1; infos.paramh.second = size_param_2; infos.paramt1 = SPoint2(covar1[0],covar1[1]); infos.paramt2 = SPoint2(covar2[0],covar2[1]); infos.angle = angle_current; infos.localsize = L; infos.normal = n; return true; }