From 47d0ef334d246cd1e97134703ce80c7a34e6824a Mon Sep 17 00:00:00 2001 From: Thomas Toulorge <thomas.toulorge@mines-paristech.fr> Date: Fri, 8 Jun 2012 18:19:50 +0000 Subject: [PATCH] Improved Hessian computation in MeshMetric --- Mesh/meshMetric.cpp | 163 +++++++++++++++++++++++++++++++++++++++++--- Mesh/meshMetric.h | 2 + 2 files changed, 157 insertions(+), 8 deletions(-) diff --git a/Mesh/meshMetric.cpp b/Mesh/meshMetric.cpp index cbf0b6c7ec..cc27a87cca 100644 --- a/Mesh/meshMetric.cpp +++ b/Mesh/meshMetric.cpp @@ -301,6 +301,7 @@ void meshMetric::computeHessian_FE(){ } + //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( ){ @@ -366,13 +367,156 @@ void meshMetric::computeHessian_LS( ){ } } + + +// Determines set of vertices to use for least squares +std::vector<MVertex*> getLSBlob(unsigned int minNbPt, v2t_cont::iterator it, v2t_cont &adj) { + +// static const double RADFACT = 3; +// +// SPoint3 p0 = it->first->point(); // Vertex coordinates (center of circle) +// +// double rad = 0.; +// for (std::vector<MElement*>::iterator itEl = it->second.begin(); itEl != it->second.end(); itEl++) +// rad = std::max(rad,(*itEl)->getOuterRadius()); +// rad *= RADFACT; + + std::vector<MVertex*> vv(1,it->first), bvv = vv; // Vector of vertices in blob and in boundary of blob + do { + std::set<MVertex*> nbvv; // Set of vertices in new boundary + for (std::vector<MVertex*>::iterator itBV = bvv.begin(); itBV != bvv.end(); itBV++) { // For each boundary vertex... + std::vector<MElement*> &adjBV = adj[*itBV]; + for (std::vector<MElement*>::iterator itBVEl = adjBV.begin(); itBVEl != adjBV.end(); itBVEl++) { + for (int iV=0; iV<(*itBVEl)->getNumVertices(); iV++){ // ... look for adjacent vertices... + MVertex *v = (*itBVEl)->getVertex(iV); +// if ((find(vv.begin(),vv.end(),v) == vv.end()) && (p0.distance(v->point()) <= rad)) nbvv.insert(v); + if (find(vv.begin(),vv.end(),v) == vv.end()) nbvv.insert(v); // ... and add them in the new boundary if they are not already in the blob + } + } + } + if (nbvv.empty()) bvv.clear(); + else { + bvv.assign(nbvv.begin(),nbvv.end()); + vv.insert(vv.end(),nbvv.begin(),nbvv.end()); + } +// } while (!bvv.empty()); + } while (vv.size() < minNbPt); // Repeat until min. number of points is reached + + return vv; + +} + + +// 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( ){ + + unsigned int sysDim = (_dim == 2) ? 6 : 10; + unsigned int minNbPtBlob = 3*sysDim; + + for (v2t_cont::iterator it = _adj.begin(); it != _adj.end(); it++) { + MVertex *ver = it->first; + std::vector<MVertex*> vv = getLSBlob(minNbPtBlob, it, _adj); + fullMatrix<double> A(vv.size(),sysDim), ATA(sysDim,sysDim); + fullVector<double> b(vv.size()), ATb(sysDim), coeffs(sysDim); + for(unsigned int i=0; i<vv.size(); i++) { + const double &x = vv[i]->x(), &y = vv[i]->y(), &z = vv[i]->z(); + if (_dim == 2) { + A(i,0) = x*x; A(i,1) = x*y; A(i,2) = y*y; + A(i,3) = x; A(i,4) = y; A(i,5) = 1.; + } + else { + A(i,0) = x*x; A(i,1) = x*y; A(i,2) = x*z; A(i,3) = y*y; A(i,4) = y*z; A(i,5) = z*z; + A(i,6) = x; A(i,7) = y; A(i,8) = z; A(i,9) = 1.; + } + b(i) = vals[vv[i]]; + } + ATA.gemmWithAtranspose(A,A,1.,0.); + A.multWithATranspose(b,1.,0.,ATb); + ATA.luSolve(ATb,coeffs); + const double &x = ver->x(), &y = ver->y(), &z = ver->z(); + double d2udx2, d2udy2, d2udz2, d2udxy, d2udxz, d2udyz, dudx, dudy, dudz; + if (_dim == 2) { + d2udx2 = 2.*coeffs(0); d2udy2 = 2.*coeffs(2); d2udz2 = 0.; + d2udxy = coeffs(1); d2udxz = 0.; d2udyz = 0.; + dudx = d2udx2*x+d2udxy*y+coeffs(3); + dudy = d2udxy*x+d2udy2*y+coeffs(4); + dudz = 0.; + } + else { + d2udx2 = 2.*coeffs(0); d2udy2 = 2.*coeffs(3); d2udz2 = 2.*coeffs(5); + d2udxy = coeffs(1); d2udxz = coeffs(2); d2udyz = coeffs(4); + dudx = d2udx2*x+d2udxy*y+d2udxz*z+coeffs(6); + dudy = d2udxy*x+d2udy2*y+d2udyz*z+coeffs(7); + dudz = d2udxz*z+d2udyz*z+d2udz2*z+coeffs(8); + } + double duNorm = sqrt(dudx*dudx+dudy*dudy+dudz*dudz); + if (duNorm == 0. || _technique == meshMetric::HESSIAN) duNorm = 1.; + grads[ver] = SVector3(dudx/duNorm,dudy/duNorm,dudz/duNorm); + dgrads[0][ver] = SVector3(d2udx2,d2udxy,d2udxz); + dgrads[1][ver] = SVector3(d2udxy,d2udy2,d2udyz); + dgrads[2][ver] = SVector3(d2udxz,d2udyz,d2udz2); + } + +} + + +//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; + } + if (_technique == meshMetric::LEVELSET) break; + } + +} + + + void meshMetric::computeMetric(){ //printf("%d elements are considered in the meshMetric \n",(int)_elements.size()); computeValues(); - //computeHessian_FE(); - computeHessian_LS(); +// computeHessian_FE(); +// computeHessian_LS(); + computeHessian_LS2(); +// computeHessian_LS3(); int metricNumber = setOfMetrics.size(); @@ -387,12 +531,15 @@ void meshMetric::computeMetric(){ 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(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; } diff --git a/Mesh/meshMetric.h b/Mesh/meshMetric.h index 3433e1ddcb..abcc693b78 100644 --- a/Mesh/meshMetric.h +++ b/Mesh/meshMetric.h @@ -82,6 +82,8 @@ class meshMetric: public Field { void computeMetric() ; void computeValues(); void computeHessian_LS(); + void computeHessian_LS2(); + void computeHessian_LS3(); void computeHessian_FE(); double getLaplacian (MVertex *v); -- GitLab