From 8cf298d7716e55241b77eb30450758c62ce5be9d Mon Sep 17 00:00:00 2001 From: Thomas Toulorge <thomas.toulorge@mines-paristech.fr> Date: Thu, 14 Jun 2012 15:03:41 +0000 Subject: [PATCH] Cleaned code for computation of metrics. Added "scaled Hessian" metric. --- Mesh/meshMetric.cpp | 717 ++++++++++++++++++++------------------------ Mesh/meshMetric.h | 19 +- 2 files changed, 345 insertions(+), 391 deletions(-) diff --git a/Mesh/meshMetric.cpp b/Mesh/meshMetric.cpp index cc27a87cca..cb61ef8ab9 100644 --- a/Mesh/meshMetric.cpp +++ b/Mesh/meshMetric.cpp @@ -209,164 +209,6 @@ void meshMetric::computeValues(){ } } -//compute derivatives and second order derivatives using linear finite elements -void meshMetric::computeHessian_FE(){ - - //compute FE Gradients - std::map<MElement*,SPoint3> gradElems; - for ( std::vector<MElement*>::iterator ite = _elements.begin(); - ite != _elements.end(); ite++){ - MElement *e = *ite; - int npts; - IntPt *GP; - e->getIntegrationPoints(0, &npts, &GP); - const double u = GP[0].pt[0]; - const double v = GP[0].pt[1]; - const double w = GP[0].pt[2]; - double grade[3]; - double fj[256]; - for (int k = 0; k < e->getNumVertices(); k++){ - MVertex *v = e->getVertex(k); - fj[k] = (*_fct)(v->x(),v->y(),v->z()); - } - e->interpolateGrad(fj, u, v, w, grade); - SPoint3 gr(grade[0], grade[1],grade[2]); - gradElems.insert(std::make_pair(e,gr)); - } - - //smooth element gradients at vertices - for(v2t_cont::const_iterator itv = _adj.begin(); itv!= _adj.end(); ++itv){ - MVertex *ver = itv->first; - std::vector<MElement*> vElems= itv->second; - SVector3 gradv; - for (unsigned int i=0;i<vElems.size();i++){ - MElement *e = vElems[i]; - gradv += gradElems[e]; - } - gradv *= (1./vElems.size());; - double nn = norm(gradv); - if (nn == 0.0 || _technique == meshMetric::HESSIAN) nn = 1.0; - grads[ver] =gradv*(1./nn); - } - - if (_technique == meshMetric::LEVELSET) return; - - //compute FE Hessians - std::map<MElement*,STensor3> hessElems; - for ( std::vector<MElement*>::iterator ite = _elements.begin(); - ite != _elements.end(); ite++){ - MElement *e = *ite; - int npts; - IntPt *GP; - e->getIntegrationPoints(0, &npts, &GP); - const double u = GP[0].pt[0]; - const double v = GP[0].pt[1]; - const double w = GP[0].pt[2]; - double gradgradx[3]; - double gradgrady[3]; - double gradgradz[3]; - double gradxj[256]; - double gradyj[256]; - double gradzj[256]; - for (int k = 0; k < e->getNumVertices(); k++){ - MVertex *v = e->getVertex(k); - gradxj[k] = grads[v].x(); - gradyj[k] = grads[v].y(); - gradzj[k] = grads[v].z(); - } - e->interpolateGrad(gradxj, u, v, w, gradgradx); - e->interpolateGrad(gradyj, u, v, w, gradgrady); - e->interpolateGrad(gradzj, u, v, w, gradgradz); - STensor3 hess; - hess(0,0) = gradgradx[0]; hess(0,1)= gradgrady[0]; hess(0,2) =gradgradz[0]; - hess(1,0) = gradgradx[1]; hess(1,1)= gradgrady[1]; hess(1,2) =gradgradz[1]; - hess(2,0) = gradgradx[2]; hess(2,1)= gradgradz[2]; hess(2,2) =gradgradz[2]; - hessElems.insert(std::make_pair(e,hess)); - } - - //smooth element hessians at vertices - for(v2t_cont::const_iterator itv = _adj.begin(); itv!= _adj.end(); ++itv){ - MVertex *ver = itv->first; - std::vector<MElement*> vElems= itv->second; - STensor3 hessv(0.0); - for (unsigned int i=0;i<vElems.size();i++){ - MElement *e = vElems[i]; - hessv += hessElems[e]; - } - hessv *= (1./vElems.size()); - dgrads[0][ver] = SVector3(hessv(0,0), hessv(0,1),hessv(0,2)); - dgrads[1][ver] = SVector3(hessv(1,0), hessv(1,1),hessv(1,2)); - dgrads[2][ver] = SVector3(hessv(2,0), hessv(2,1),hessv(2,2)); - } - -} - - -//compute derivatives and second order derivatives using least squares -// u = a + b(x-x_0) + c(y-y_0) + d(z-z_0) -void meshMetric::computeHessian_LS( ){ - - //double error = 0.0; - - int DIM = _dim + 1; - for (int ITER=0;ITER<DIM;ITER++){ - v2t_cont :: iterator it = _adj.begin(); - while (it != _adj.end()) { - std::vector<MElement*> lt = it->second; - MVertex *ver = it->first; - while (lt.size() < 13) increaseStencil(ver,_adj,lt); - fullMatrix<double> A (lt.size(),DIM); - fullMatrix<double> AT (DIM,lt.size()); - fullMatrix<double> ATA (DIM,DIM); - fullVector<double> b (lt.size()); - fullVector<double> ATb (DIM); - fullVector<double> result (DIM); - fullMatrix<double> f (1,1); - for(unsigned 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(); - } - 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); - } - else{ - dgrads[ITER-1][ver] = SVector3(result(1),result(2),(_dim==2)?0.0:result(3)); - } - ++it; - } - if (_technique == meshMetric::LEVELSET) break; - } - -} // Determines set of vertices to use for least squares @@ -407,10 +249,11 @@ std::vector<MVertex*> getLSBlob(unsigned int minNbPt, v2t_cont::iterator it, v2t } + // Compute derivatives and second order derivatives using least squares // 2D LS system: a_i0*x^2+a_i1*x*y+a_i2*y^2+a_i3*x+a_i4*y+a_i5=b_i // 3D LS system: a_i0*x^2+a_i1*x*y+a_i2*x*z+a_i3*y^2+a_i4*y*z+a_i5*z^2+a_i6*x+a_i7*y+a_i8*z+a_i9=b_i -void meshMetric::computeHessian_LS2( ){ +void meshMetric::computeHessian(){ unsigned int sysDim = (_dim == 2) ? 6 : 10; unsigned int minNbPtBlob = 3*sysDim; @@ -462,278 +305,382 @@ void meshMetric::computeHessian_LS2( ){ } -//compute derivatives and second order derivatives using least squares -// u = a + b(x-x_0) + c(y-y_0) + d(z-z_0) -void meshMetric::computeHessian_LS3( ){ - //double error = 0.0; - unsigned int sysDim = (_dim == 2) ? 6 : 10; - unsigned int minNbPtBlob = 2*sysDim; - - int DIM = _dim + 1; - for (int ITER=0;ITER<DIM;ITER++){ - v2t_cont :: iterator it = _adj.begin(); - while (it != _adj.end()) { - MVertex *ver = it->first; - std::vector<MVertex*> vv = getLSBlob(minNbPtBlob, it, _adj); - fullMatrix<double> A(vv.size(),DIM), ATA(DIM,DIM); - fullVector<double> b(vv.size()), ATb (DIM), result(DIM); - for(unsigned int i = 0; i < vv.size(); i++) { - b(i) = (ITER == 0) ? vals[vv[i]] : grads[vv[i]](ITER-1); - A(i,0) = 1.0; - A(i,1) = vv[i]->x() - ver->x(); - A(i,2) = vv[i]->y() - ver->y(); - if (_dim == 3) A(i,3) = vv[i]->z() - ver->z(); - } - ATA.gemmWithAtranspose(A,A,1.,0.); - A.multWithATranspose(b,1.,0.,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); - } - else{ - dgrads[ITER-1][ver] = SVector3(result(1),result(2),(_dim==2)?0.0:result(3)); - } - ++it; +void meshMetric::computeMetricLevelSet(){ + + int metricNumber = setOfMetrics.size(); + + for (v2t_cont::iterator it=_adj.begin(); it!=_adj.end(); it++) { + + MVertex *ver = it->first; + double signed_dist = vals[ver]; + double dist = fabs(signed_dist); + + SVector3 gradudx = dgrads[0][ver]; + SVector3 gradudy = dgrads[1][ver]; + SVector3 gradudz = dgrads[2][ver]; + SMetric3 hessian; + hessian(0,0) = gradudx(0); hessian(0,1) = gradudx(1); hessian(0,2) = gradudx(2); + hessian(1,0) = gradudy(0); hessian(1,1) = gradudy(1); hessian(1,2) = gradudy(2); + hessian(2,0) = gradudz(0); hessian(2,1) = gradudz(1); hessian(2,2) = gradudz(2); + + SVector3 gr = grads[ver]; + SMetric3 H; + 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); + H(0,0) += C*gr(0)*gr(0)/norm ; + H(1,1) += C*gr(1)*gr(1)/norm ; + H(2,2) += C*gr(2)*gr(2)/norm ; + H(1,0) = H(0,1) = C*gr(1)*gr(0)/norm ; + H(2,0) = H(0,2) = C*gr(2)*gr(0)/norm ; + H(2,1) = H(1,2) = C*gr(2)*gr(1)/norm ; } - if (_technique == meshMetric::LEVELSET) break; + + fullMatrix<double> V(3,3); + fullVector<double> S(3); + H.eig(V,S); + + double lambda1, lambda2, lambda3; + lambda1 = S(0); + lambda2 = S(1); + lambda3 = (_dim == 3)? S(2) : 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); + + _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()))); + } } -void meshMetric::computeMetric(){ +void meshMetric::computeMetricHessian(){ - //printf("%d elements are considered in the meshMetric \n",(int)_elements.size()); + int metricNumber = setOfMetrics.size(); + + for (v2t_cont::iterator it=_adj.begin(); it!=_adj.end(); it++) { + + MVertex *ver = it->first; + + SMetric3 H; + SVector3 gradudx = dgrads[0][ver]; + SVector3 gradudy = dgrads[1][ver]; + SVector3 gradudz = dgrads[2][ver]; + H(0,0) = gradudx(0); H(0,1) = gradudx(1); H(0,2) = gradudx(2); + H(1,0) = gradudy(0); H(1,1) = gradudy(1); H(1,2) = gradudy(2); + H(2,0) = gradudz(0); H(2,1) = gradudz(1); H(2,2) = gradudz(2); + + fullMatrix<double> V(3,3); + fullVector<double> S(3); + H.eig(V,S); + + double lambda1 = std::min(std::max(fabs(S(0))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)); + double lambda2 = std::min(std::max(fabs(S(1))/_epsilon,1./(hmax*hmax)),1./(hmin*hmin)); + double 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); + + _hessian[ver] = H; + 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()))); + + } + +} + + + +void meshMetric::computeMetricFrey(){ - computeValues(); -// computeHessian_FE(); -// computeHessian_LS(); - computeHessian_LS2(); -// computeHessian_LS3(); - int metricNumber = setOfMetrics.size(); - v2t_cont :: iterator it = _adj.begin(); - while (it != _adj.end()) { + for (v2t_cont::iterator it=_adj.begin(); it!=_adj.end(); it++) { + 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)); hessian(0,0) = gradudx(0); hessian(0,1) = gradudx(1); hessian(0,2) = gradudx(2); hessian(1,0) = gradudy(0); hessian(1,1) = gradudy(1); hessian(1,2) = gradudy(2); hessian(2,0) = gradudz(0); hessian(2,1) = gradudz(1); hessian(2,2) = gradudz(2); - if (_technique == meshMetric::HESSIAN){ - H = hessian; - } - 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 ; - } - // else if (dist > _E && dist < 2.*_E && norm != 0.0){ - // double hmid = (hmax-hmin)/(1.*_E)*dist+(2.*hmin-1.*hmax); - // double C = 1./(hmid*hmid) -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 ; - // } - H = hlevelset; + + SVector3 gr = grads[ver]; + SMetric3 H(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); + H(0,0) += C*gr(0)*gr(0)/(norm) + hessian(0,0)/epsGeom; + H(1,1) += C*gr(1)*gr(1)/(norm) + hessian(1,1)/epsGeom; + H(2,2) += C*gr(2)*gr(2)/(norm) + hessian(2,2)/epsGeom; + H(1,0) = H(0,1) = C*gr(1)*gr(0)/(norm) + hessian(1,0)/epsGeom; + H(2,0) = H(0,2) = C*gr(2)*gr(0)/(norm) + hessian(2,0)/epsGeom; + H(2,1) = H(1,2) = C*gr(2)*gr(1)/(norm) + hessian(2,1)/epsGeom; } - //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; - } - H = hfrey; + + fullMatrix<double> V(3,3); + fullVector<double> S(3); + H.eig(V,S); + + double lambda1, lambda2, lambda3; + lambda1 = S(0); + lambda2 = S(1); + lambda3 = (_dim == 3)? S(2) : 1.; + + if (dist < _E) { + 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.; } - else if ((_technique == meshMetric::EIGENDIRECTIONS )||(_technique == meshMetric::EIGENDIRECTIONS_LINEARINTERP_H )){ - - 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; - double eigenval_direction; - if (_technique==meshMetric::EIGENDIRECTIONS_LINEARINTERP_H){ - 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; - } - else if(_technique==meshMetric::EIGENDIRECTIONS){ - // ... or linear interpolation between 1/h_min^2 and 1/h_max^2 - double maximum_distance = (signed_dist>0.) ? _E : fabs(_E_moins); - 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); - // 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)); - 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])))); + 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); + + _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()))); + + } + +} + + + +void meshMetric::computeMetricEigenDir(){ + + int metricNumber = setOfMetrics.size(); + + for (v2t_cont::iterator it=_adj.begin(); it!=_adj.end(); it++) { + + MVertex *ver = it->first; + double signed_dist = vals[ver]; + double dist = fabs(signed_dist); + + SVector3 gradudx = dgrads[0][ver]; + SVector3 gradudy = dgrads[1][ver]; + SVector3 gradudz = dgrads[2][ver]; + SMetric3 hessian; + hessian(0,0) = gradudx(0); hessian(0,1) = gradudx(1); hessian(0,2) = gradudx(2); + hessian(1,0) = gradudy(0); hessian(1,1) = gradudy(1); hessian(1,2) = gradudy(2); + hessian(2,0) = gradudz(0); hessian(2,1) = gradudz(1); hessian(2,2) = gradudz(2); + + 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; + double eigenval_direction; + if (_technique==meshMetric::EIGENDIRECTIONS_LINEARINTERP_H){ + 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; } - else{// isotropic metric ! - SMetric3 mymetric(metric_value_hmax); - metric = mymetric; - setOfSizes[metricNumber].insert(std::make_pair(ver, hmax)); + else if(_technique==meshMetric::EIGENDIRECTIONS){ + // ... or linear interpolation between 1/h_min^2 and 1/h_max^2 + double maximum_distance = (signed_dist>0.) ? _E : fabs(_E_moins); + eigenval_direction = metric_value_hmin + ((metric_value_hmax-metric_value_hmin)/maximum_distance)*dist; } - _hessian[ver] = hessian; - setOfMetrics[metricNumber].insert(std::make_pair(ver,metric)); - setOfDetMetric[metricNumber].insert(std::make_pair(ver,sqrt(metric.determinant()))); - it++; + // 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); + // 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)); + 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 if (_technique == meshMetric::ISOTROPIC_LINEARINTERP_H){ - SVector3 gr = grads[ver]; - double norm = gr.normalize(); - double h_dist = (signed_dist < _E && signed_dist > _E_moins && norm != 0.0) ? hmin + ((hmax-hmin)/_E)*dist : hmax; // the charcteristic element size in all directions - linear interp between hmin and hmax - H = SMetric3(1./h_dist/h_dist); + 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()))); + } - if (_technique != meshMetric::EIGENDIRECTIONS && _technique!=meshMetric::EIGENDIRECTIONS_LINEARINTERP_H){ +} - //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; - lambda1 = S(0); - lambda2 = S(1); - lambda3 = (_dim == 3)? S(2) : 1.; +void meshMetric::computeMetricIsoLinInterp(){ + + int metricNumber = setOfMetrics.size(); - 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.; - } + for (v2t_cont::iterator it=_adj.begin(); it!=_adj.end(); it++) { - 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)); + MVertex *ver = it->first; + double signed_dist = vals[ver]; + double dist = fabs(signed_dist); - SMetric3 metric(lambda1,lambda2,lambda3,t1,t2,t3); + SVector3 gr = grads[ver]; + double norm = gr.normalize(); + double h_dist = (signed_dist < _E && signed_dist > _E_moins && norm != 0.0) ? hmin + ((hmax-hmin)/_E)*dist : hmax; // the charcteristic element size in all directions - linear interp between hmin and hmax - _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()))); + double lambda = 1./h_dist/h_dist; + SMetric3 H; + H(0,0) = H(1,1) = lambda; + H(2,2) = (_dim == 3)? lambda : 1.; + + _hessian[ver] = H; + setOfSizes[metricNumber].insert(std::make_pair(ver, lambda)); + setOfMetrics[metricNumber].insert(std::make_pair(ver,H)); + setOfDetMetric[metricNumber].insert(std::make_pair(ver,sqrt(H.determinant()))); - it++; - } } - //exportInfo("EMI"); - //exit(1); - - //Adapt epsilon - //----------------- - // dgDofContainer dofDet(groups, 1); - // for (int iGroup = 0; iGroup < groups->getNbElementGroups(); iGroup++){ - // dgGroupOfElements *group = groups->getElementGroup(iGroup); - // fullMatrix<double> & detgroup = dofDet.getGroupProxy(group); - // for (int iElement = 0 ; iElement < group->getNbElements(); iElement++){ - // MElement* e = group->getElement(iElement); - // for ( int i = 0; i < e->getNumVertices(); i++) { - // MVertex *ver = e->getVertex(i); - // std::map<MVertex*, double >::iterator it = _detMetric.find(ver); - // detgroup (i, iElement) = it->second; - // } - // } - // } - // fullMatrix<double> res(1,1); - // dgFunctionIntegrator integ(groups, dofDet.getFunction()); - // integ.compute(res); - //fprintf("integ =%g \n", res(0,0)) - - //Smoothing - //----------- - //smoothMetric (sol); - //curvatureContributionToMetric(); +} + + + +void meshMetric::computeMetricScaledHessian(){ + + int metricNumber = setOfMetrics.size(); + + std::list<double> lambda1, lambda2, lambda3; + std::list<SVector3> t1, t2, t3; + + // Compute and store eignvalues and eigenvectors of Hessian + for (v2t_cont::iterator it=_adj.begin(); it!=_adj.end(); it++) { + + MVertex *ver = it->first; + + SMetric3 H; + SVector3 gradudx = dgrads[0][ver]; + SVector3 gradudy = dgrads[1][ver]; + SVector3 gradudz = dgrads[2][ver]; + H(0,0) = gradudx(0); H(0,1) = gradudx(1); H(0,2) = gradudx(2); + H(1,0) = gradudy(0); H(1,1) = gradudy(1); H(1,2) = gradudy(2); + H(2,0) = gradudz(0); H(2,1) = gradudz(1); H(2,2) = gradudz(2); + + fullMatrix<double> V(3,3); + fullVector<double> S(3); + H.eig(V,S); + + lambda1.push_back(fabs(S(0))); + lambda2.push_back(fabs(S(1))); + if (_dim == 3) lambda3.push_back(fabs(S(2))); + + t1.push_back(SVector3(V(0,0),V(1,0),V(2,0))); + t2.push_back(SVector3(V(0,1),V(1,1),V(2,1))); + t3.push_back(SVector3(V(0,2),V(1,2),V(2,2))); + + _hessian[ver] = H; + + } + + // Calculate scale factor based on max. eigenvalue and min. element length + const double maxLambda1 = *std::max_element(lambda1.begin(), lambda1.end()); + const double maxLambda2 = *std::max_element(lambda2.begin(), lambda2.end()); + double maxLambda; + if (_dim == 3) { + const double maxLambda3 = *std::max_element(lambda3.begin(),lambda3.end()); + maxLambda = std::max(std::max(maxLambda1, maxLambda2), maxLambda3); + } + else maxLambda = std::max(maxLambda1, maxLambda2); + const double factor = 1./(hmin*hmin*maxLambda); + + // Rescale metric + const double lMinBound = 1./(hmax*hmax); + std::list<double>::iterator itL1 = lambda1.begin(), itL2 = lambda2.begin(), itL3 = lambda3.begin(); + std::list<SVector3>::iterator itT1 = t1.begin(), itT2 = t2.begin(), itT3 = t3.begin(); + for (v2t_cont::iterator it=_adj.begin(); it!=_adj.end(); it++) { + MVertex *ver = it->first; + const double l1 = std::max(*itL1*factor, lMinBound); + const double l2 = std::max(*itL2*factor, lMinBound); + const double l3 = (_dim == 3) ? std::max(*itL3*factor, lMinBound) : 1.; + const double lMax = (_dim == 3) ? std::max(std::max(l1, l2), l3) : std::max(l1, l2); + SMetric3 metric(l1,l2,l3,*itT1,*itT2,*itT3); + setOfSizes[metricNumber].insert(std::make_pair(ver, 1./sqrt(lMax))); + setOfMetrics[metricNumber].insert(std::make_pair(ver,metric)); + setOfDetMetric[metricNumber].insert(std::make_pair(ver,sqrt(metric.determinant()))); + itL1++; itL2++; if (_dim == 3) itL3++; + itT1++; itT2++; itT3++; + } + +} + + + +void meshMetric::computeMetric(){ + + //printf("%d elements are considered in the meshMetric \n",(int)_elements.size()); + + computeValues(); + computeHessian(); + + switch(_technique) { + case (LEVELSET) : computeMetricLevelSet(); break; + case (HESSIAN) : computeMetricHessian(); break; + case (FREY) : computeMetricFrey(); break; + case (EIGENDIRECTIONS) : computeMetricEigenDir(); break; + case (EIGENDIRECTIONS_LINEARINTERP_H) : computeMetricEigenDir(); break; + case (ISOTROPIC_LINEARINTERP_H) : computeMetricIsoLinInterp(); break; + case (SCALED_HESSIAN) : computeMetricScaledHessian(); break; + } } + + double meshMetric::operator() (double x, double y, double z, GEntity *ge) { if (needMetricUpdate) intersectMetrics(); if (!setOfMetrics.size()){ diff --git a/Mesh/meshMetric.h b/Mesh/meshMetric.h index abcc693b78..b2eed0f41b 100644 --- a/Mesh/meshMetric.h +++ b/Mesh/meshMetric.h @@ -21,7 +21,8 @@ class STensor3; /**Anisotropic mesh size field based on a metric */ class meshMetric: public Field { public: - typedef enum {LEVELSET=1,HESSIAN=2, FREY=3, EIGENDIRECTIONS=4, EIGENDIRECTIONS_LINEARINTERP_H=5, ISOTROPIC_LINEARINTERP_H=6} MetricComputationTechnique; + typedef enum {LEVELSET=1,HESSIAN=2, FREY=3, EIGENDIRECTIONS=4, EIGENDIRECTIONS_LINEARINTERP_H=5, + ISOTROPIC_LINEARINTERP_H=6, SCALED_HESSIAN=7} MetricComputationTechnique; private: // intersect all metrics added in "setOfMetrics", preserve eigendirections of the "most anisotropic" metric void intersectMetrics(); @@ -73,18 +74,24 @@ class meshMetric: public Field { // parameters[3] = the required minimum number of elements to represent a circle - used for curvature-based metric (default: = 15) // 5: same as 4, except that the transition in band E uses linear interpolation of h, instead of linear interpolation of metric // 6: fct is a LS, metric is isotropic with linear interpolation of h in band E + // 7: metric based on the Hessian of fct, scaled so that the smallest element has size lcmin 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 computeMetric(); + void computeMetricLevelSet(); + void computeMetricHessian(); + void computeMetricFrey(); + void computeMetricEigenDir(); + void computeMetricIsoLinInterp(); + void computeMetricScaledHessian(); + void computeValues(); - void computeHessian_LS(); - void computeHessian_LS2(); - void computeHessian_LS3(); - void computeHessian_FE(); + void computeHessian(); double getLaplacian (MVertex *v); virtual bool isotropic () const {return false;} -- GitLab