diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp index e2752279f5d69ab43c507ff5d019ff9275616008..9d1bca04050127bb482df659fdf0da22e57f702a 100644 --- a/Geo/GModel.cpp +++ b/Geo/GModel.cpp @@ -524,15 +524,13 @@ int GModel::mesh(int dimension) #endif } -int GModel::adaptMesh(int technique, simpleFunction<double> *f, - std::vector<double> parameters, bool meshAll) +int GModel::adaptMesh(std::vector<int> technique, std::vector<simpleFunction<double>* > f, std::vector<std::vector<double> > parameters, int niter, bool meshAll) { #if defined(HAVE_MESH) if (getNumMeshElements() == 0) mesh(getDim()); int nbElemsOld = getNumMeshElements(); int nbElems; - int niter = parameters.size() >=4 ? (int) parameters[3] : 3; FieldManager *fields = getFields(); fields->reset(); @@ -544,7 +542,11 @@ int GModel::adaptMesh(int technique, simpleFunction<double> *f, Msg::Info("-- adaptMesh (allDim) ITER =%d ", ITER); fields->reset(); - fields->setBackgroundField(new meshMetric(this, technique, f, parameters)); + meshMetric *metric = new meshMetric(this); + for (int imetric=0;imetric<technique.size();imetric++){; + metric->addMetric(technique[imetric], f[imetric], parameters[imetric]); + } + fields->setBackgroundField(metric); // int id = fields->newId(); // (*fields)[id] = new meshMetric(this, technique, f, parameters); // fields->background_field = id; @@ -564,6 +566,7 @@ int GModel::adaptMesh(int technique, simpleFunction<double> *f, char name[256]; sprintf(name, "meshAdapt-%d.msh", ITER); writeMSH(name); +// metric->exportInfo(name); if (ITER++ >= niter) break; if (ITER > 3 && fabs((double)(nbElems - nbElemsOld)) < 0.01 * nbElemsOld) break; @@ -597,7 +600,11 @@ int GModel::adaptMesh(int technique, simpleFunction<double> *f, if (elements.size() == 0)return -1; fields->reset(); - fields->setBackgroundField(new meshMetric(this, technique, f, parameters)); + meshMetric *metric = new meshMetric(this); + for (int imetric=0;imetric<technique.size();imetric++){; + metric->addMetric(technique[imetric], f[imetric], parameters[imetric]); + } + fields->setBackgroundField(metric); // int id = fields->newId(); // (*fields)[id] = new meshMetric(this, technique, f, parameters); // fields->background_field = id; diff --git a/Geo/GModel.h b/Geo/GModel.h index 2196de1c5db60f61b3f05e909350fc8aa9f0c432..c856ae18d315562deb5429f131ebeaa9f79aab82 100644 --- a/Geo/GModel.h +++ b/Geo/GModel.h @@ -376,23 +376,32 @@ class GModel // mesh the model int mesh(int dimension); - // adapt the mesh anisotropically using a metric that is computed from a scalar function f(x,y,z). - // One can either + // adapt the mesh anisotropically using metrics that are computed from a set of functions f(x,y,z). // For all algorithms // parameters[1] = lcmin (default : in global gmsh options CTX::instance()->mesh.lcMin) // parameters[2] = lcmax (default : in global gmsh options CTX::instance()->mesh.lcMax) - // parameters[3] = nb iterations + // niter is the maximum number of iterations + // Available algorithms: // 1) Assume that the function is a levelset -> adapt using Coupez technique (technique = 1) // parameters[0] = thickness of the interface (mandatory) // 2) Assume that the function is a physical quantity -> adapt using the Hessain (technique = 2) // parameters[0] = N, the final number of elements // 3) A variant of 1) by P. Frey (= Coupez + takes curvature function into account) // parameters[0] = thickness of the interface (mandatory) - // The algorithm first generate a mesh if no one is available + // parameters[3] = the required minimum number of elements to represent a circle - used for curvature-based metric (default: = 15) + // 4) A variant (3), direct implementation in the metric eigendirections, assuming a level set (ls): + // - hmin is imposed in the ls gradient, + // - hmax is imposed in the two eigendirections of the ls hessian that are (almost ?) tangent to the iso-zero plane + // + the latter eigenvalues (1/hmax^2) are modified if necessary to capture the iso-zero curvature + // parameters[0] = thickness of the interface in the positive ls direction (mandatory) + // parameters[4] = thickness of the interface in the negative ls direction (=parameters[0] if not specified) + // parameters[3] = the required minimum number of elements to represent a circle - used for curvature-based metric (default: = 15) + // The algorithm first generate a mesh if no one is available + // In this first attempt, only the highest dimensional mesh is adapted, which is ok if // we assume that boundaries are already adapted. // This should be fixed. - int adaptMesh (int technique, simpleFunction<double> *f, std::vector<double> parameters, bool meshAll=false); + int adaptMesh(std::vector<int> technique, std::vector<simpleFunction<double>*> f, std::vector<std::vector<double> > parameters, int niter, bool meshAll=false); // make the mesh a high order mesh at order N // linear is 1 if the high order points are not placed on the geometry of the model diff --git a/Geo/STensor3.cpp b/Geo/STensor3.cpp index 7436bc7a510317408082580da8388b3a4d9d37fa..0bbe5ee232c39c2a1764f711391a77b8d92eb117 100644 --- a/Geo/STensor3.cpp +++ b/Geo/STensor3.cpp @@ -49,6 +49,29 @@ SMetric3 intersection_conserveM1 (const SMetric3 &m1, const SMetric3 &m2) return iv; } +// preserve orientation of the most anisotropic metric !!! +SMetric3 intersection_conserve_mostaniso (const SMetric3 &m1, const SMetric3 &m2) +{ + fullMatrix<double> V1(3,3); + fullVector<double> S1(3); + m1.eig(V1,S1,true); + double lambda1_min = std::min(std::min(fabs(S1(0)),fabs(S1(1))),fabs(S1(2))); + double lambda1_max = std::max(std::max(fabs(S1(0)),fabs(S1(1))),fabs(S1(2))); + fullMatrix<double> V2(3,3); + fullVector<double> S2(3); + m2.eig(V2,S2,true); + double lambda2_min = std::min(std::min(fabs(S2(0)),fabs(S2(1))),fabs(S2(2))); + double lambda2_max = std::max(std::max(fabs(S2(0)),fabs(S2(1))),fabs(S2(2))); + + double ratio1 = lambda1_min/lambda1_max; + double ratio2 = lambda2_min/lambda2_max; + + if (ratio1<ratio2) + return intersection_conserveM1(m1,m2); + else + return intersection_conserveM1(m2,m1); +} + // (1-t) * m1 + t * m2 SMetric3 interpolation (const SMetric3 &m1, const SMetric3 &m2, diff --git a/Geo/STensor3.h b/Geo/STensor3.h index 6673cc5908b506b7c94f31e36653d862c1f72bce..c99db1b89c3870ec043bfc528fc13748fc087a4b 100644 --- a/Geo/STensor3.h +++ b/Geo/STensor3.h @@ -163,8 +163,11 @@ inline double dot(const SVector3 &a, const SMetric3 &m, const SVector3 &b) b.z() * ( m(0,2) * a.x() + m(1,2) * a.y() + m(2,2) * a.z() ) ; } +// preserve orientation of m1 SMetric3 intersection_conserveM1 (const SMetric3 &m1, const SMetric3 &m2); +// preserve orientation of the most anisotropic metric +SMetric3 intersection_conserve_mostaniso (const SMetric3 &m1, const SMetric3 &m2); // compute the largest inscribed ellipsoid... SMetric3 intersection (const SMetric3 &m1, const SMetric3 &m2); diff --git a/Geo/gmshLevelset.cpp b/Geo/gmshLevelset.cpp index bed67951e91762c7c9cf88c62bb919783e1f4bba..f0515ed706f0e1a1807b4e7cf1b76ae1a6387bbf 100644 --- a/Geo/gmshLevelset.cpp +++ b/Geo/gmshLevelset.cpp @@ -631,6 +631,62 @@ double gLevelsetQuadric::operator()(const double x, const double y, const double + 2. * A[1][2] * y * z + A[2][2] * z * z + B[0] * x + B[1] * y + B[2] * z + C); } +gLevelsetShamrock::gLevelsetShamrock(double _xmid, double _ymid, double _zmid, double _a, double _b, int _c, int tag) : gLevelsetPrimitive(tag), xmid(_xmid), ymid(_ymid), zmid(_zmid), a(_a), b(_b), c(_c) { + // creating the iso-zero + double angle = 0.; + double r; + while (angle<=2.*M_PI){ + r = a+b*sin(c*angle); + iso_x.push_back(r*sin(angle)+xmid); + iso_y.push_back(r*cos(angle)+xmid); + + angle += 2.*M_PI/1000.; + } +} + +double gLevelsetShamrock::operator() (const double x, const double y, const double z) const { + // computing distance to pre-defined (sampled) iso-zero + double dx,dy,xi,yi,d; + dx = x-iso_x[0]; + dy = y-iso_y[0]; + double distance = sqrt(dx*dx+dy*dy); + std::vector<double>::const_iterator itx = iso_x.begin(); + std::vector<double>::const_iterator itxen = iso_x.end(); + std::vector<double>::const_iterator ity = iso_y.begin(); + std::vector<double>::const_iterator itminx = iso_x.begin(); + std::vector<double>::const_iterator itminy = iso_y.begin(); + itx++;ity++; + for (;itx!=itxen;itx++,ity++){ + xi = *itx; + yi = *ity; + dx = x-xi; + dy = y-yi; + d = sqrt(dx*dx+dy*dy); + if (distance>d){ + distance = d; + itminx = itx; + itminy = ity; + } + } + // still need to find the LS sign... using vectorial prod with tangent vector + // if not, the LS gradient is discontinuous on iso-zero... oups ! + SVector3 t,p; + p(0) = (*itminx) - x; + p(1) = (*itminy) - y; + if (itminx==(itxen-1)){ + t(0) = iso_x[0] - (*itminx); + t(1) = iso_y[0] - (*itminy); + } + else{ + t(0) = (*(itminx+1)) - (*itminx); + t(1) = (*(itminy+1)) - (*itminy); + } + double vectprod = (p(0)*t(1) - p(1)*t(0)); + double sign = (vectprod < 0.) ? -1. : 1.; + + return (sign*distance); +} + gLevelsetPopcorn::gLevelsetPopcorn(double _xc, double _yc, double _zc, double _r0, double _A, double _sigma, int tag) : gLevelsetPrimitive(tag) { A = _A; sigma = _sigma; diff --git a/Geo/gmshLevelset.h b/Geo/gmshLevelset.h index 590e25d40b5f5d0b16a5408775119712ddf940f1..2712cc21631e590e1b7f789083e73733d84fb352 100644 --- a/Geo/gmshLevelset.h +++ b/Geo/gmshLevelset.h @@ -267,6 +267,22 @@ public: int type() const { return UNKNOWN; } }; +// creates the 2D (-approximate- signed distance !) level set +// corresponding to the "shamrock-like" iso-zero from +// Dobrzynski and Frey, "Anisotropic delaunay mesh adaptation for unsteady simulations", +// 17th International Meshing Rountable (2008)(177–194) +class gLevelsetShamrock: public gLevelsetPrimitive +{ + double xmid, ymid, zmid,a,b; + int c; + std::vector<double> iso_x,iso_y; +public: + gLevelsetShamrock(double xmid, double ymid, double zmid, double a, double b, int c=3, int tag=1); + ~gLevelsetShamrock(){} + double operator () (const double x, const double y, const double z) const; + int type() const { return UNKNOWN; } +}; + class gLevelsetMathEval: public gLevelsetPrimitive { mathEvaluator *_expr; diff --git a/Mesh/meshMetric.cpp b/Mesh/meshMetric.cpp index eb690c3f925e5bc644a0bf627d14752190bc2db7..766628d747dfcc5049a6c570e6c1328a5604a8d1 100644 --- a/Mesh/meshMetric.cpp +++ b/Mesh/meshMetric.cpp @@ -1,3 +1,5 @@ + + #include "meshMetric.h" #include "meshGFaceOptimize.h" #include "Context.h" @@ -14,39 +16,16 @@ static void increaseStencil(MVertex *v, v2t_cont &adj, std::vector<MElement*> &l for (int j=0;j<lt[i]->getNumVertices();j++){ MVertex *v1 = lt[i]->getVertex(j); if (v1 != v){ - std::vector<MElement*> <2 = adj[v1]; - stencil.insert(lt2.begin(),lt2.end()); + std::vector<MElement*> <2 = adj[v1]; + stencil.insert(lt2.begin(),lt2.end()); } } } lt.clear(); lt.insert(lt.begin(),stencil.begin(),stencil.end()); } -meshMetric::meshMetric(std::vector<MElement*> elements, int technique, simpleFunction<double> *fct, std::vector<double> parameters): _fct(fct){ - - _dim = elements[0]->getDim(); - std::map<MElement*, MElement*> newP; - std::map<MElement*, MElement*> newD; - - for (int i=0;i<elements.size();i++){ - MElement *e = elements[i]; - MElement *copy = e->copy(_vertexMap, newP, newD); - _elements.push_back(copy); - } - - _octree = new MElementOctree(_elements); - hmin = parameters.size() >=3 ? parameters[1] : CTX::instance()->mesh.lcMin; - hmax = parameters.size() >=3 ? parameters[2] : CTX::instance()->mesh.lcMax; - - _E = parameters[0]; - _epsilon = parameters[0]; - _technique = (MetricComputationTechnique)technique; - - computeMetric(); -} - -meshMetric::meshMetric(GModel *gm, int technique, simpleFunction<double> *fct, std::vector<double> parameters): _fct(fct){ +meshMetric::meshMetric(GModel *gm){ _dim = gm->getDim(); std::map<MElement*, MElement*> newP; std::map<MElement*, MElement*> newD; @@ -54,40 +33,142 @@ meshMetric::meshMetric(GModel *gm, int technique, simpleFunction<double> *fct, s if (_dim == 2){ for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); ++fit){ for (int i=0;i<(*fit)->getNumMeshElements();i++){ - MElement *e = (*fit)->getMeshElement(i); - MElement *copy = e->copy(_vertexMap, newP, newD); - _elements.push_back(copy); + MElement *e = (*fit)->getMeshElement(i); + MElement *copy = e->copy(_vertexMap, newP, newD); + _elements.push_back(copy); } } } else if (_dim == 3){ for (GModel::riter rit = gm->firstRegion(); rit != gm->lastRegion(); ++rit){ for (int i=0;i<(*rit)->getNumMeshElements();i++){ - MElement *e = (*rit)->getMeshElement(i); - MElement *copy = e->copy(_vertexMap, newP, newD); - _elements.push_back(copy); + MElement *e = (*rit)->getMeshElement(i); + MElement *copy = e->copy(_vertexMap, newP, newD); + _elements.push_back(copy); } } } + _octree = new MElementOctree(_elements); +} + +meshMetric::meshMetric(std::vector<MElement*> elements){ + _dim = elements[0]->getDim(); + std::map<MElement*, MElement*> newP; + std::map<MElement*, MElement*> newD; + + for (int i=0;i<elements.size();i++){ + MElement *e = elements[i]; + MElement *copy = e->copy(_vertexMap, newP, newD); + _elements.push_back(copy); + } _octree = new MElementOctree(_elements); +} + +void meshMetric::addMetric(int technique, simpleFunction<double> *fct, std::vector<double> parameters){ + needMetricUpdate=true; + _fct = fct; hmin = parameters.size() >=3 ? parameters[1] : CTX::instance()->mesh.lcMin; hmax = parameters.size() >=3 ? parameters[2] : CTX::instance()->mesh.lcMax; - + _E = parameters[0]; + _E_moins = (parameters.size() >= 5) ? parameters[4] : -parameters[0]; _epsilon = parameters[0]; _technique = (MetricComputationTechnique)technique; - + _Np = (parameters.size() >= 4) ? parameters[3] : 15.; + computeMetric(); +} + +void meshMetric::intersectMetrics(){ + if (!setOfMetrics.size()){ + std::cout << " meshMetric::intersectMetrics: Can't intersect metrics, no metric registered ! " << std::endl; + return; + } + + v2t_cont adj; + buildVertexToElement (_elements,adj); + v2t_cont :: iterator it = adj.begin(); + for (;it != adj.end();it++) { + MVertex *ver = it->first; + _nodalMetrics[ver] = setOfMetrics[0][ver]; + _detMetric[ver] = setOfDetMetric[0][ver]; + _nodalSizes[ver] = setOfSizes[0][ver]; + for (int i=1;i<setOfMetrics.size();i++){ + _nodalMetrics[ver] = intersection_conserve_mostaniso(_nodalMetrics[ver],setOfMetrics[i][ver]); + _nodalSizes[ver] = std::min(_nodalSizes[ver],setOfSizes[i][ver]); + } + _detMetric[ver] = sqrt(_nodalMetrics[ver].determinant()); + } + needMetricUpdate=false; - printMetric("toto.pos"); - //exit(1); +} +void meshMetric::exportInfo(const char * fileendname){ + if (needMetricUpdate) intersectMetrics(); + std::stringstream sg,sm,sl; + sg << "meshmetric_gradients" << fileendname; + sm << "meshmetric_metric" << fileendname; + sl << "meshmetric_levelset" << fileendname; + std::ofstream out_grad(sg.str().c_str()); + std::ofstream out_metric(sm.str().c_str()); + std::ofstream out_ls(sl.str().c_str()); + out_grad << "View \"ls_gradient\"{" << std::endl; + out_metric << "View \"metric\"{" << std::endl; + out_ls << "View \"ls\"{" << std::endl; + std::vector<MElement*>::iterator itelem = _elements.begin(); + std::vector<MElement*>::iterator itelemen = _elements.end(); + for (;itelem!=itelemen;itelem++){ + MElement* e = *itelem; + out_metric << "TT("; + out_grad << "VT("; + out_ls << "ST("; + for ( int i = 0; i < e->getNumVertices(); i++) { + MVertex *ver = e->getVertex(i); + out_metric << ver->x() << "," << ver->y() << "," << ver->z(); + out_grad << ver->x() << "," << ver->y() << "," << ver->z(); + out_ls << ver->x() << "," << ver->y() << "," << ver->z(); + if (i!=e->getNumVertices()-1){ + out_metric << ","; + out_grad << ","; + out_ls << ","; + } + else{ + out_metric << "){"; + out_grad << "){"; + out_ls << "){"; + } + } + for ( int i = 0; i < e->getNumVertices(); i++) { + MVertex *ver = e->getVertex(i); + out_ls << vals[ver]; + if ((i==(e->getNumVertices()-1))) out_ls << "};" << std::endl; + else out_ls << ","; + for (int k=0;k<3;k++){ + out_grad << grads[ver](k); + if ((k==2)&&(i==(e->getNumVertices()-1))) out_grad << "};" << std::endl; + else out_grad << ","; + for (int l=0;l<3;l++){ + out_metric << _nodalMetrics[ver](k,l); + if ((k==2)&&(l==2)&&(i==(e->getNumVertices()-1))) out_metric << "};" << std::endl; + else out_metric << ","; + } + } + } + } + out_grad << "};" << std::endl; + out_metric << "};" << std::endl; + out_ls << "};" << std::endl; + out_grad.close(); + out_metric.close(); + out_ls.close(); } + + meshMetric::~meshMetric(){ if (_octree) delete _octree; for (int i=0; i< _elements.size(); i++) - delete _elements[i]; + delete _elements[i]; } void meshMetric::computeValues( v2t_cont adj){ @@ -116,7 +197,7 @@ void meshMetric::computeHessian( v2t_cont adj){ // increaseStencil(ver,adj,lt); // } // } - + fullMatrix<double> A (lt.size(),DIM); fullMatrix<double> AT (DIM,lt.size()); fullMatrix<double> ATA (DIM,DIM); @@ -125,51 +206,51 @@ void meshMetric::computeHessian( v2t_cont adj){ fullVector<double> result (DIM); fullMatrix<double> f (1,1); for(int i = 0; i < lt.size(); i++) { - MElement *e = lt[i]; - int npts; IntPt *pts; - SPoint3 p; - e->getIntegrationPoints(0,&npts,&pts); - if (ITER == 0){ - SPoint3 p; - e->pnt(pts[0].pt[0],pts[0].pt[1],pts[0].pt[2],p); - b(i) = (*_fct)(p.x(),p.y(),p.z()); - } - else { - double value = 0.0; - for (int j=0;j<e->getNumVertices();j++){ - SVector3 gr = grads[e->getVertex(j)]; - value += gr(ITER-1); - } - b(i) = value/(double)e->getNumVertices(); - } - e->pnt(pts[0].pt[0],pts[0].pt[1],pts[0].pt[2],p); - A(i,0) = 1.0; - A(i,1) = p.x() - ver->x(); - A(i,2) = p.y() - ver->y(); - if (_dim == 3) A(i,3) = p.z() - ver->z(); + MElement *e = lt[i]; + int npts; IntPt *pts; + SPoint3 p; + e->getIntegrationPoints(0,&npts,&pts); + if (ITER == 0){ + SPoint3 p; + e->pnt(pts[0].pt[0],pts[0].pt[1],pts[0].pt[2],p); + b(i) = (*_fct)(p.x(),p.y(),p.z()); + } + else { + double value = 0.0; + for (int j=0;j<e->getNumVertices();j++){ + SVector3 gr = grads[e->getVertex(j)]; + value += gr(ITER-1); + } + b(i) = value/(double)e->getNumVertices(); + } + e->pnt(pts[0].pt[0],pts[0].pt[1],pts[0].pt[2],p); + A(i,0) = 1.0; + A(i,1) = p.x() - ver->x(); + A(i,2) = p.y() - ver->y(); + if (_dim == 3) A(i,3) = p.z() - ver->z(); } AT = A.transpose(); AT.mult(A,ATA); AT.mult(b,ATb); ATA.luSolve(ATb,result); if (ITER == 0){ - double gr1 = result(1); - double gr2 = result(2); - double gr3 = (_dim==2) ? 0.0:result(3); - double norm = sqrt(gr1*gr1+gr2*gr2+gr3*gr3); - if (norm == 0.0 || _technique == meshMetric::HESSIAN) norm = 1.0; - grads[ver] = SVector3(gr1/norm,gr2/norm,gr3/norm); + double gr1 = result(1); + double gr2 = result(2); + double gr3 = (_dim==2) ? 0.0:result(3); + double norm = sqrt(gr1*gr1+gr2*gr2+gr3*gr3); + if (norm == 0.0 || _technique == meshMetric::HESSIAN) norm = 1.0; + grads[ver] = SVector3(gr1/norm,gr2/norm,gr3/norm); } else - dgrads[ITER-1][ver] = SVector3(result(1),result(2),_dim==2? 0.0:result(3)); + dgrads[ITER-1][ver] = SVector3(result(1),result(2),_dim==2? 0.0:result(3)); ++it; } if (_technique == meshMetric::LEVELSET) break; } - + } void meshMetric::computeMetric(){ - + v2t_cont adj; buildVertexToElement (_elements,adj); @@ -178,38 +259,41 @@ void meshMetric::computeMetric(){ computeValues(adj); computeHessian(adj); + int metricNumber = setOfMetrics.size(); + v2t_cont :: iterator it = adj.begin(); while (it != adj.end()) { - MVertex *ver = it->first; - double dist = fabs(vals[ver]); - - SMetric3 H; - SVector3 gradudx = dgrads[0][ver]; - SVector3 gradudy = dgrads[1][ver]; - SVector3 gradudz = dgrads[2][ver]; - SMetric3 hessian; - hessian(0,0) = gradudx(0); - hessian(1,1) = gradudy(1); - hessian(2,2) = gradudz(2); - hessian(1,0) = hessian(0,1) = 0.5 * (gradudx(1) +gradudy(0)); - hessian(2,0) = hessian(0,2) = 0.5 * (gradudx(2) +gradudz(0)); - hessian(2,1) = hessian(1,2) = 0.5 * (gradudy(2) +gradudz(1)); - if (_technique == meshMetric::HESSIAN){ + MVertex *ver = it->first; + double signed_dist = vals[ver]; + double dist = fabs(signed_dist); + + SMetric3 H; + SVector3 gradudx = dgrads[0][ver]; + SVector3 gradudy = dgrads[1][ver]; + SVector3 gradudz = dgrads[2][ver]; + SMetric3 hessian; + hessian(0,0) = gradudx(0); + hessian(1,1) = gradudy(1); + hessian(2,2) = gradudz(2); + hessian(1,0) = hessian(0,1) = 0.5 * (gradudx(1) +gradudy(0)); + hessian(2,0) = hessian(0,2) = 0.5 * (gradudx(2) +gradudz(0)); + hessian(2,1) = hessian(1,2) = 0.5 * (gradudy(2) +gradudz(1)); + if (_technique == meshMetric::HESSIAN){ H = hessian; } - else if (_technique == meshMetric::LEVELSET ){ + else if (_technique == meshMetric::LEVELSET ){ SVector3 gr = grads[ver]; SMetric3 hlevelset(1./(hmax*hmax)); double norm = gr(0)*gr(0)+gr(1)*gr(1)+gr(2)*gr(2); if (dist < _E && norm != 0.0){ - double h = hmin*(hmax/hmin-1)*dist/_E + hmin; - double C = 1./(h*h) -1./(hmax*hmax); - hlevelset(0,0) += C*gr(0)*gr(0)/norm ; - hlevelset(1,1) += C*gr(1)*gr(1)/norm ; - hlevelset(2,2) += C*gr(2)*gr(2)/norm ; - hlevelset(1,0) = hlevelset(0,1) = C*gr(1)*gr(0)/norm ; - hlevelset(2,0) = hlevelset(0,2) = C*gr(2)*gr(0)/norm ; - hlevelset(2,1) = hlevelset(1,2) = C*gr(2)*gr(1)/norm ; + double h = hmin*(hmax/hmin-1)*dist/_E + hmin; + double C = 1./(h*h) -1./(hmax*hmax); + hlevelset(0,0) += C*gr(0)*gr(0)/norm ; + hlevelset(1,1) += C*gr(1)*gr(1)/norm ; + hlevelset(2,2) += C*gr(2)*gr(2)/norm ; + hlevelset(1,0) = hlevelset(0,1) = C*gr(1)*gr(0)/norm ; + hlevelset(2,0) = hlevelset(0,2) = C*gr(2)*gr(0)/norm ; + hlevelset(2,1) = hlevelset(1,2) = C*gr(2)*gr(1)/norm ; } // else if (dist > _E && dist < 2.*_E && norm != 0.0){ // double hmid = (hmax-hmin)/(1.*_E)*dist+(2.*hmin-1.*hmax); @@ -223,90 +307,163 @@ void meshMetric::computeMetric(){ // } H = hlevelset; } - //See paper Ducrot and Frey: - //Anisotropic levelset adaptation for accurate interface capturing, - //ijnmf, 2010 - else if (_technique == meshMetric::FREY ){ - SVector3 gr = grads[ver]; - SMetric3 hfrey(1./(hmax*hmax)); - double norm = gr(0)*gr(0)+gr(1)*gr(1)+gr(2)*gr(2); - if (dist < _E && norm != 0.0){ - double h = hmin*(hmax/hmin-1.0)*dist/_E + hmin; - double C = 1./(h*h) -1./(hmax*hmax); - double kappa = hessian(0,0)+hessian(1,1)+hessian(2,2); - double Np = 15.0; - double epsGeom = 4.0*3.14*3.14/(kappa*Np); - hfrey(0,0) += C*gr(0)*gr(0)/(norm) + hessian(0,0)/epsGeom; - hfrey(1,1) += C*gr(1)*gr(1)/(norm) + hessian(1,1)/epsGeom; - hfrey(2,2) += C*gr(2)*gr(2)/(norm) + hessian(2,2)/epsGeom; - hfrey(1,0) = hfrey(0,1) = C*gr(1)*gr(0)/(norm) + hessian(1,0)/epsGeom; - hfrey(2,0) = hfrey(0,2) = C*gr(2)*gr(0)/(norm) + hessian(2,0)/epsGeom; - hfrey(2,1) = hfrey(1,2) = C*gr(2)*gr(1)/(norm) + hessian(2,1)/epsGeom; - // hfrey(0,0) += C*gr(0)*gr(0)/norm; - // hfrey(1,1) += C*gr(1)*gr(1)/norm; - // hfrey(2,2) += C*gr(2)*gr(2)/norm; - // hfrey(1,0) = hfrey(0,1) = gr(1)*gr(0)/(norm) ; - // hfrey(2,0) = hfrey(0,2) = gr(2)*gr(0)/(norm) ; - // hfrey(2,1) = hfrey(1,2) = gr(2)*gr(1)/(norm) ; - } - // SMetric3 sss=hessian; - // sss *= divEps; - // sss(0,0) += 1/(hmax*hmax); - // sss(1,1) += 1/(hmax*hmax); - // sss(2,2) += 1/(hmax*hmax); - // H = intersection(sss,hfrey); - // if (dist < _E) H = intersection(sss,hfrey); - // else H = hfrey; - H = hfrey; - } - //See paper Hachem and Coupez: - //Finite element solution to handle complex heat and fluid flows in - //industrial furnaces using the immersed volume technique, ijnmf, 2010 - - fullMatrix<double> V(3,3); - fullVector<double> S(3); - H.eig(V,S); - - double lambda1, lambda2, lambda3; - // if (dist < _E && _technique == meshMetric::FREY){ - // fullMatrix<double> Vhess(3,3); - // fullVector<double> Shess(3); - // hessian.eig(Vhess,Shess); - // double h = hmin*(hmax/hmin-1)*dist/_E + hmin; - // double lam1 = Shess(0); - // double lam2 = Shess(1); - // double lam3 = (_dim == 3)? Shess(2) : 1.; - // lambda1 = lam1; - // lambda2 = lam2/lambda1; - // lambda3 = (_dim == 3)? lam3/lambda1: 1.0; - // } - // else{ + //See paper Ducrot and Frey: + //Anisotropic levelset adaptation for accurate interface capturing, + //ijnmf, 2010 + else if (_technique == meshMetric::FREY ){ + SVector3 gr = grads[ver]; + SMetric3 hfrey(1./(hmax*hmax)); + double norm = gr(0)*gr(0)+gr(1)*gr(1)+gr(2)*gr(2); + if (dist < _E && norm != 0.0){ + double h = hmin*(hmax/hmin-1.0)*dist/_E + hmin; + double C = 1./(h*h) -1./(hmax*hmax); + double kappa = hessian(0,0)+hessian(1,1)+hessian(2,2); + double epsGeom = 4.0*3.14*3.14/(kappa*_Np*_Np); + hfrey(0,0) += C*gr(0)*gr(0)/(norm) + hessian(0,0)/epsGeom; + hfrey(1,1) += C*gr(1)*gr(1)/(norm) + hessian(1,1)/epsGeom; + hfrey(2,2) += C*gr(2)*gr(2)/(norm) + hessian(2,2)/epsGeom; + hfrey(1,0) = hfrey(0,1) = C*gr(1)*gr(0)/(norm) + hessian(1,0)/epsGeom; + hfrey(2,0) = hfrey(0,2) = C*gr(2)*gr(0)/(norm) + hessian(2,0)/epsGeom; + hfrey(2,1) = hfrey(1,2) = C*gr(2)*gr(1)/(norm) + hessian(2,1)/epsGeom; + // hfrey(0,0) += C*gr(0)*gr(0)/norm; + // hfrey(1,1) += C*gr(1)*gr(1)/norm; + // hfrey(2,2) += C*gr(2)*gr(2)/norm; + // hfrey(1,0) = hfrey(0,1) = gr(1)*gr(0)/(norm) ; + // hfrey(2,0) = hfrey(0,2) = gr(2)*gr(0)/(norm) ; + // hfrey(2,1) = hfrey(1,2) = gr(2)*gr(1)/(norm) ; + } + // SMetric3 sss=hessian; + // sss *= divEps; + // sss(0,0) += 1/(hmax*hmax); + // sss(1,1) += 1/(hmax*hmax); + // sss(2,2) += 1/(hmax*hmax); + // H = intersection(sss,hfrey); + // if (dist < _E) H = intersection(sss,hfrey); + // else H = hfrey; + H = hfrey; + } + else if (_technique == meshMetric::EIGENDIRECTIONS ){ + double metric_value_hmax = 1./hmax/hmax; + SVector3 gr = grads[ver]; + double norm = gr.normalize(); + SMetric3 metric; + + if (signed_dist < _E && signed_dist > _E_moins && norm != 0.0){ + // first, compute the eigenvectors of the hessian, for a curvature-based metric + fullMatrix<double> eigvec_hessian(3,3); + fullVector<double> lambda_hessian(3); + hessian.eig(eigvec_hessian,lambda_hessian); + std::vector<SVector3> ti; + ti.push_back(SVector3(eigvec_hessian(0,0),eigvec_hessian(1,0),eigvec_hessian(2,0))); + ti.push_back(SVector3(eigvec_hessian(0,1),eigvec_hessian(1,1),eigvec_hessian(2,1))); + ti.push_back(SVector3(eigvec_hessian(0,2),eigvec_hessian(1,2),eigvec_hessian(2,2))); + + // compute the required characteristic length relative to the curvature and the distance to iso + double maxkappa = std::max(std::max(fabs(lambda_hessian(0)),fabs(lambda_hessian(1))),fabs(lambda_hessian(2))); + // epsilon is set such that the characteristic element size in the tangent direction is h = 2pi R_min/_Np = sqrt(1/metric_maxmax) = sqrt(epsilon/kappa_max) + double un_sur_epsilon = maxkappa/((2.*3.14/_Np)*(2.*3.14/_Np)); + // metric curvature-based eigenvalues + std::vector<double> eigenvals_curvature; + eigenvals_curvature.push_back(fabs(lambda_hessian(0))*un_sur_epsilon); + eigenvals_curvature.push_back(fabs(lambda_hessian(1))*un_sur_epsilon); + eigenvals_curvature.push_back(fabs(lambda_hessian(2))*un_sur_epsilon); + // metric distance-based eigenvalue, in gradient direction + double metric_value_hmin = 1./hmin/hmin; + // 1/ linear interpolation between h_min and h_max... + //double h_dist = hmin + ((hmax-hmin)/_E)*dist;// the charcteristic element size in the normal direction - linear interp between hmin and hmax + //eigenval_direction = 1./h_dist/h_dist; + // 2/ ... or linear interpolation between 1/h_min^2 and 1/h_max^2 + double maximum_distance = (signed_dist>0.) ? _E : fabs(_E_moins); + double eigenval_direction = metric_value_hmin + ((metric_value_hmax-metric_value_hmin)/maximum_distance)*dist; + + // now, consider only three eigenvectors (i.e. (grad(LS), u1, u2) with u1 and u2 orthogonal vectors in the tangent plane to the LS) + // and imposing directly eigenvalues and directions, instead of intersecting the two metrics based on direction and curvature + // need to find out which one of ti's is the closest to gr, to known which eigenvalue to discard... + std::vector<double> grad_dot_ti; + for (int i=0;i<3;i++) + grad_dot_ti.push_back(fabs(dot(gr,ti[i]))); + std::vector<double>::iterator itbegin = grad_dot_ti.begin(); + std::vector<double>::iterator itmax = std::max_element(itbegin,grad_dot_ti.end()); + int grad_index = std::distance(itbegin,itmax); + std::vector<int> ti_index; + for (int i=0;i<3;i++) + if (i!=grad_index) ti_index.push_back(i); +// std::cout << "gr tgr t1 t2 dots_tgr_gr_t1_t2 (" << gr(0) << "," << gr(1) << "," << gr(2) << ") (" << ti[grad_index](0) << "," << ti[grad_index](1) << "," << ti[grad_index](2) << ") (" << ti[ti_index[0]](0) << "," << ti[ti_index[0]](1) << "," << ti[ti_index[0]](2) << ") (" << ti[ti_index[1]](0) << "," << ti[ti_index[1]](1) << "," << ti[ti_index[1]](2) << ") " << fabs(dot(ti[grad_index],gr)) << " " << (dot(ti[grad_index],ti[ti_index[0]])) << " " << (dot(ti[grad_index],ti[ti_index[1]])) << std::endl; + + // finally, creating the metric + std::vector<double> eigenvals; + eigenvals.push_back(std::min(std::max(eigenval_direction,metric_value_hmax),metric_value_hmin));// in gradient direction + eigenvals.push_back(std::min(std::max(eigenvals_curvature[ti_index[0]],metric_value_hmax),metric_value_hmin)); + eigenvals.push_back(std::min(std::max(eigenvals_curvature[ti_index[1]],metric_value_hmax),metric_value_hmin)); +// eigenvals.push_back(std::min(std::max(metric_value_hmax,metric_value_hmax),metric_value_hmin)); +// eigenvals.push_back(std::min(std::max(metric_value_hmax,metric_value_hmax),metric_value_hmin)); + + metric = SMetric3(eigenvals[0],eigenvals[1],eigenvals[2],gr,ti[ti_index[0]],ti[ti_index[1]]); + setOfSizes[metricNumber].insert(std::make_pair(ver, std::min(std::min(1/sqrt(eigenvals[0]),1/sqrt(eigenvals[1])),1/sqrt(eigenvals[2])))); + } + else{// isotropic metric ! + SMetric3 mymetric(metric_value_hmax); + metric = mymetric; + setOfSizes[metricNumber].insert(std::make_pair(ver, hmax)); + } + _hessian[ver] = hessian; + setOfMetrics[metricNumber].insert(std::make_pair(ver,metric)); + setOfDetMetric[metricNumber].insert(std::make_pair(ver,sqrt(metric.determinant()))); + + it++; + } + + if (_technique != meshMetric::EIGENDIRECTIONS ){ + + //See paper Hachem and Coupez: + //Finite element solution to handle complex heat and fluid flows in + //industrial furnaces using the immersed volume technique, ijnmf, 2010 + + fullMatrix<double> V(3,3); + fullVector<double> S(3); + H.eig(V,S); + + double lambda1, lambda2, lambda3; + // if (dist < _E && _technique == meshMetric::FREY){ + // fullMatrix<double> Vhess(3,3); + // fullVector<double> Shess(3); + // hessian.eig(Vhess,Shess); + // double h = hmin*(hmax/hmin-1)*dist/_E + hmin; + // double lam1 = Shess(0); + // double lam2 = Shess(1); + // double lam3 = (_dim == 3)? Shess(2) : 1.; + // lambda1 = lam1; + // lambda2 = lam2/lambda1; + // lambda3 = (_dim == 3)? lam3/lambda1: 1.0; + // } + // else{ lambda1 = S(0); lambda2 = S(1); lambda3 = (_dim == 3)? S(2) : 1.; - //} + //} - if (_technique == meshMetric::HESSIAN || (dist < _E && _technique == meshMetric::FREY)){ - lambda1 = std::min(std::max(fabs(S(0))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)); - lambda2 = std::min(std::max(fabs(S(1))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)); - lambda3 = (_dim == 3) ? std::min(std::max(fabs(S(2))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)) : 1.; - } + if (_technique == meshMetric::HESSIAN || (dist < _E && _technique == meshMetric::FREY)){ + lambda1 = std::min(std::max(fabs(S(0))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)); + lambda2 = std::min(std::max(fabs(S(1))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)); + lambda3 = (_dim == 3) ? std::min(std::max(fabs(S(2))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)) : 1.; + } - SVector3 t1 (V(0,0),V(1,0),V(2,0)); - SVector3 t2 (V(0,1),V(1,1),V(2,1)); - SVector3 t3 (V(0,2),V(1,2),V(2,2)); - - SMetric3 metric(lambda1,lambda2,lambda3,t1,t2,t3); + SVector3 t1 (V(0,0),V(1,0),V(2,0)); + SVector3 t2 (V(0,1),V(1,1),V(2,1)); + SVector3 t3 (V(0,2),V(1,2),V(2,2)); - _hessian[ver] = hessian; - _nodalMetrics[ver] = metric; - _nodalSizes[ver] = std::min(std::min(1/sqrt(lambda1),1/sqrt(lambda2)),1/sqrt(lambda3)); + SMetric3 metric(lambda1,lambda2,lambda3,t1,t2,t3); - _detMetric[ver] = sqrt(metric.determinant()); + _hessian[ver] = hessian; + setOfSizes[metricNumber].insert(std::make_pair(ver, std::min(std::min(1/sqrt(lambda1),1/sqrt(lambda2)),1/sqrt(lambda3)))); + setOfMetrics[metricNumber].insert(std::make_pair(ver,metric)); + setOfDetMetric[metricNumber].insert(std::make_pair(ver,sqrt(metric.determinant()))); - it++; + it++; + } } + //Adapt epsilon //----------------- // dgDofContainer dofDet(groups, 1); @@ -326,7 +483,7 @@ void meshMetric::computeMetric(){ // dgFunctionIntegrator integ(groups, dofDet.getFunction()); // integ.compute(res); //fprintf("integ =%g \n", res(0,0)) - + //Smoothing //----------- //smoothMetric (sol); @@ -335,6 +492,11 @@ void meshMetric::computeMetric(){ } double meshMetric::operator() (double x, double y, double z, GEntity *ge) { + if (needMetricUpdate) intersectMetrics(); + if (!setOfMetrics.size()){ + std::cout << "meshMetric::operator() : No metric defined ! " << std::endl; + throw; + } SPoint3 xyz(x,y,z), uvw; double initialTol = MElement::getTolerance(); MElement::setTolerance(1.e-4); @@ -354,6 +516,11 @@ double meshMetric::operator() (double x, double y, double z, GEntity *ge) { } void meshMetric::operator() (double x, double y, double z, SMetric3 &metr, GEntity *ge) { + if (needMetricUpdate) intersectMetrics(); + if (!setOfMetrics.size()){ + std::cout << "meshMetric::operator() : No metric defined ! " << std::endl; + throw; + } metr = SMetric3(1.e-22); SPoint3 xyz(x,y,z), uvw; double initialTol = MElement::getTolerance(); @@ -378,25 +545,30 @@ void meshMetric::operator() (double x, double y, double z, SMetric3 &metr, GEnti } } -void meshMetric::printMetric(const char* n) const{ +void meshMetric::printMetric(const char* n){ + if (needMetricUpdate) intersectMetrics(); + if (!setOfMetrics.size()){ + std::cout << "meshMetric::printMetric : No metric defined ! " << std::endl; + throw; + } FILE *f = fopen (n,"w"); fprintf(f,"View \"\"{\n"); - std::map<MVertex*,SMetric3 >::const_iterator it = _hessian.begin(); - //std::map<MVertex*,SMetric3>::const_iterator it= _nodalMetrics.begin(); + //std::map<MVertex*,SMetric3 >::const_iterator it = _hessian.begin(); + std::map<MVertex*,SMetric3>::const_iterator it= _nodalMetrics.begin(); //for (; it != _nodalMetrics.end(); ++it){ - for (; it != _hessian.end(); ++it){ - MVertex *v = it->first; - SMetric3 h = it->second; - double lapl = h(0,0)+h(1,1)+h(2,2); - fprintf(f, "SP(%g,%g,%g){%g};\n", it->first->x(),it->first->y(),it->first->z(),lapl); - // fprintf(f,"TP(%g,%g,%g){%g,%g,%g,%g,%g,%g,%g,%g,%g};\n", - // it->first->x(),it->first->y(),it->first->z(), - // it->second(0,0),it->second(0,1),it->second(0,2), - // it->second(1,0),it->second(1,1),it->second(1,2), - // it->second(2,0),it->second(2,1),it->second(2,2) - // ); + for (; it != _hessian.end(); ++it){ + MVertex *v = it->first; + SMetric3 h = it->second; + double lapl = h(0,0)+h(1,1)+h(2,2); + //fprintf(f, "SP(%g,%g,%g){%g};\n", it->first->x(),it->first->y(),it->first->z(),lapl); + fprintf(f,"TP(%g,%g,%g){%g,%g,%g,%g,%g,%g,%g,%g,%g};\n", + it->first->x(),it->first->y(),it->first->z(), + h(0,0),h(0,1),h(0,2), + h(1,0),h(1,1),h(1,2), + h(2,0),h(2,1),h(2,2) + ); } fprintf(f,"};\n"); @@ -432,43 +604,43 @@ double meshMetric::getLaplacian (MVertex *v) { }*/ /* - void meshMetric::smoothMetric (dgDofContainer *sol){ - return; - dgGroupCollection *groups = sol->getGroups(); - std::set<MEdge,Less_Edge> edges; - for (int i=0;i<groups->getNbElementGroups();i++){ - dgGroupOfElements *group = groups->getElementGroup(i); - for (int j=0;j<group->getNbElements();j++){ - MElement *e = group->getElement(j); - for (int k=0;k<e->getNumEdges();k++){ - edges.insert(e->getEdge(k)); - } - } - } - - std::set<MEdge,Less_Edge>::iterator it = edges.begin(); - double logRatio = log (CTX::instance()->mesh.smoothRatio); - for ( ; it !=edges.end(); ++it){ - MEdge e = *it; - std::map<MVertex*,SMetric3>::iterator it1 = _nodalMetrics.find(e.getVertex(0)); - std::map<MVertex*,SMetric3>::iterator it2 = _nodalMetrics.find(e.getVertex(1)); - SVector3 aij (e.getVertex(1)->x()-e.getVertex(0)->x(), - e.getVertex(1)->y()-e.getVertex(0)->y(), - e.getVertex(1)->z()-e.getVertex(0)->z()); - SMetric3 m1 = it1->second; - double al1 = sqrt(dot(aij,m1,aij)); - SMetric3 m2 = it2->second; - double al2 = sqrt(dot(aij,m2,aij)); - // it1->second.print("m1"); - // it2->second.print("m2"); - m1 *= 1./((1+logRatio*al1)*(1+logRatio*al1)); - m2 *= 1./((1+logRatio*al2)*(1+logRatio*al2)); - it1->second = intersection (it1->second,m2); - it2->second = intersection (it2->second,m1); - // it1->second.print("m1 after"); - // it2->second.print("m2 after"); - // getchar(); - } - } -*/ + void meshMetric::smoothMetric (dgDofContainer *sol){ + return; + dgGroupCollection *groups = sol->getGroups(); + std::set<MEdge,Less_Edge> edges; + for (int i=0;i<groups->getNbElementGroups();i++){ + dgGroupOfElements *group = groups->getElementGroup(i); + for (int j=0;j<group->getNbElements();j++){ + MElement *e = group->getElement(j); + for (int k=0;k<e->getNumEdges();k++){ + edges.insert(e->getEdge(k)); + } + } + } + + std::set<MEdge,Less_Edge>::iterator it = edges.begin(); + double logRatio = log (CTX::instance()->mesh.smoothRatio); + for ( ; it !=edges.end(); ++it){ + MEdge e = *it; + std::map<MVertex*,SMetric3>::iterator it1 = _nodalMetrics.find(e.getVertex(0)); + std::map<MVertex*,SMetric3>::iterator it2 = _nodalMetrics.find(e.getVertex(1)); + SVector3 aij (e.getVertex(1)->x()-e.getVertex(0)->x(), + e.getVertex(1)->y()-e.getVertex(0)->y(), + e.getVertex(1)->z()-e.getVertex(0)->z()); + SMetric3 m1 = it1->second; + double al1 = sqrt(dot(aij,m1,aij)); + SMetric3 m2 = it2->second; + double al2 = sqrt(dot(aij,m2,aij)); +// it1->second.print("m1"); +// it2->second.print("m2"); +m1 *= 1./((1+logRatio*al1)*(1+logRatio*al1)); +m2 *= 1./((1+logRatio*al2)*(1+logRatio*al2)); +it1->second = intersection (it1->second,m2); +it2->second = intersection (it2->second,m1); +// it1->second.print("m1 after"); +// it2->second.print("m2 after"); +// getchar(); +} +} + */ diff --git a/Mesh/meshMetric.h b/Mesh/meshMetric.h index 9460b6cb3fdeb8e7423d0e40e1010ff7cdf35911..820b3a148edfe2f21b257e7e75a928bf389a3459 100644 --- a/Mesh/meshMetric.h +++ b/Mesh/meshMetric.h @@ -1,6 +1,7 @@ #ifndef _MESH_METRIC_H_ #define _MESH_METRIC_H_ #include <map> +#include <algorithm> #include "STensor3.h" #include "Field.h" #include "meshGFaceOptimize.h" @@ -13,10 +14,13 @@ class STensor3; /**Anisotropic mesh size field based on a metric */ class meshMetric: public Field { public: - typedef enum {LEVELSET=1,HESSIAN=2, FREY=3} MetricComputationTechnique; + typedef enum {LEVELSET=1,HESSIAN=2, FREY=3, EIGENDIRECTIONS=4} MetricComputationTechnique; private: + // intersect all metrics added in "setOfMetrics", preserve eigendirections of the "most anisotropic" metric + void intersectMetrics(); int _dim; - double _epsilon, _E; + double _epsilon, _E, _E_moins, _Np; + bool needMetricUpdate; meshMetric::MetricComputationTechnique _technique; double hmin, hmax; simpleFunction<double> *_fct; @@ -28,16 +32,43 @@ class meshMetric: public Field { std::map<MVertex*,double> vals; std::map<MVertex*,SVector3> grads,dgrads[3]; - std::map<MVertex*,SMetric3> _nodalMetrics; - std::map<MVertex*,double> _nodalSizes, _detMetric; - std::map<MVertex*,SMetric3 > _hessian; + typedef std::map<MVertex*,SMetric3> nodalMetricTensor; + typedef std::map<MVertex*,double> nodalField; + + nodalMetricTensor _nodalMetrics,_hessian; + nodalField _nodalSizes, _detMetric; + + std::map<int,nodalMetricTensor> setOfMetrics; + std::map<int,nodalField> setOfSizes; + std::map<int,nodalField> setOfDetMetric; + public: - meshMetric(std::vector<MElement*> elements, int technique, - simpleFunction<double> *fct, std::vector<double> parameters); - meshMetric(GModel *gm, int technique, - simpleFunction<double> *fct, std::vector<double> parameters); + meshMetric(std::vector<MElement*> elements); + meshMetric(GModel *gm); + ~meshMetric(); - inline SMetric3 metricAtVertex (MVertex* v) {return _nodalMetrics[v];} + + // compute a new metric and add it to the set of metrics + // parameters[1] = lcmin (default : in global gmsh options CTX::instance()->mesh.lcMin) + // parameters[2] = lcmax (default : in global gmsh options CTX::instance()->mesh.lcMax) + // Available algorithms ("techniques"): + // 1: fct is a LS, metric based on Coupez technique + // parameters[0] = thickness of the interface (mandatory) + // 2: metric based on the hessian of fct + // parameters[0] = the final number of elements + // 3: fct is a LS, variant of (1) based on Frey technique (combines Coupez and curvature) + // parameters[0] = thickness of the interface (mandatory) + // parameters[3] = the required minimum number of elements to represent a circle - used for curvature-based metric (default: = 15) + // 4: fct is a LS, variant of (3), metric computed in LS eigendirections + // parameters[0] = thickness of the interface in the positive ls direction (mandatory) + // parameters[4] = thickness of the interface in the negative ls direction (default: =parameters[0] if not specified) + // parameters[3] = the required minimum number of elements to represent a circle - used for curvature-based metric (default: = 15) + void addMetric(int technique, simpleFunction<double> *fct, std::vector<double> parameters); + + inline SMetric3 metricAtVertex (MVertex* v) { + if (needMetricUpdate) intersectMetrics(); + return _nodalMetrics[v]; + } void computeMetric() ; void computeValues( v2t_cont adj); void computeHessian( v2t_cont adj); @@ -52,9 +83,13 @@ class meshMetric: public Field { { return "Anisotropic size field based on hessian of a given function"; } + + // get metric at point(x,y,z) (previously computes intersection of metrics if not done yet) virtual double operator() (double x, double y, double z, GEntity *ge=0) ; virtual void operator() (double x, double y, double z, SMetric3 &metr, GEntity *ge=0); - void printMetric(const char* n) const; + void printMetric(const char* n); + // export pos files of fct, fct gradients (fct is the lattest fct passed to meshMetric !!) and resulting metric (intersection of all computed metrics) + void exportInfo(const char *fileendname); }; #endif diff --git a/gmshpy/gmshGeo.i b/gmshpy/gmshGeo.i index 2fbcf2a9639e04ddc91b7e8cdf8c716998dcd263..a57ccb2dec132ebe00ccf7c4fe1d8aa5a088a25f 100644 --- a/gmshpy/gmshGeo.i +++ b/gmshpy/gmshGeo.i @@ -36,6 +36,7 @@ #include "SPoint2.h" #include "SBoundingBox3d.h" #include "Curvature.h" + #include "simpleFunction.h" %} namespace std { @@ -54,6 +55,12 @@ namespace std { } %include "GmshConfig.h" +%include "simpleFunction.h" +%template(simpleFunctionDouble) simpleFunction<double>; +%include std_vector.i +namespace std { + %template(simpleFunctionDoubleVector) vector<simpleFunction<double>*, std::allocator<simpleFunction<double>*> >; +} %include "GModel.h" %include "GPoint.h" @@ -83,3 +90,4 @@ namespace std { %include "Curvature.h" %include "gmshLevelset.h" +