// Implementation of knupp metric untangling void knuppMetric::optimizeNodePosition(const scalar tolObsolete) { if( !bb_.contains(p_) ) p_ = 0.5 * (bb_.min() + bb_.max()); const scalar tol = Foam::sqr(2.0 * SMALL) * magSqr(bb_.min() - bb_.max()); label iterI, outerIter(0); vector gradF, disp; tensor gradGradF; scalar func, lastFunc; # ifdef DEBUGSmooth forAll(normals_, nI) { const scalar fx = normals_[nI] & (p_ - centres_[nI]); Info << "Tet " << nI << " has distance " << fx << " func " << Foam::sqr(mag(fx) - fx) << endl; } Info << "BoundBox size " << (bb_.max() - bb_.min()) << endl; Info << "Tolerance " << tol << endl; # endif bool finished; do { finished = true; lastFunc = evaluateMetric(); iterI = 0; do { # ifdef DEBUGSmooth Info << "Iteration " << iterI << endl; Info << "Initial metric value " << lastFunc << endl; # endif //- store previous value const point pOrig = p_; //- evaluate gradients evaluateGradients(gradF, gradGradF); //- calculate displacement const scalar determinant = det(gradGradF); if( determinant > SMALL ) { disp = (inv(gradGradF, determinant) & gradF); for(direction i=0;i<vector::nComponents;++i) { const scalar& val = disp[i]; if( (val != val) || ((val - val) != (val - val)) ) { disp = vector::zero; break; } } p_ -= disp; func = evaluateMetric(); # ifdef DEBUGSmooth Info << "Second grad " << gradGradF << endl; Info << "inv(gradGradF, determinant) " << inv(gradGradF, determinant) << endl; Info << "Gradient " << gradF << endl; Info << "Determinant " << determinant << endl; Info << "Displacement " << disp << endl; Info << "New metric value " << func << endl; # endif scalar relax(0.8); label nLoops(0); while( func > lastFunc ) { p_ = pOrig - relax * disp; relax *= 0.5; func = evaluateMetric(); if( func < lastFunc ) continue; //- it seems that this direction is wrong if( ++nLoops == 5 ) { p_ = pOrig; disp = vector::zero; func = 0.0; } } lastFunc = func; } else { disp = vector::zero; } } while( (magSqr(disp) > tol) && (++iterI < 10) ); if( (lastFunc < VSMALL) && (evaluateMetricNoBeta() > VSMALL) ) { beta_ /= 2.0; finished = false; } } while( !finished && (++outerIter < 5) ); # ifdef DEBUGSmooth Info << "Last value " << lastFunc << endl; Info << "Beta " << beta_ << endl; Info << "Metric with no beta " << evaluateMetricNoBeta() << endl; forAll(normals_, nI) { const scalar fx = normals_[nI] & (p_ - centres_[nI]); Info << "Tet " << nI << " has distance " << fx << " func " << Foam::sqr(mag(fx) - fx) << endl; } //::exit(1); # endif }
scalar volumeOptimizer::optimiseSteepestDescent(const scalar tol) { label iter(0); point& p = points_[pointI_]; # ifdef DEBUGSmooth Info << nl << "Smoothing point " << pointI_ << " with coordinates " << p << endl; scalar Vmina(VGREAT); forAll(tets_, tetI) Vmina = Foam::min(Vmina, tets_[tetI].mag(points_)); Info << "Vmin before " << Vmina << endl; # endif vector gradF; vector disp(vector::zero); tensor gradGradF; point pOrig; scalar funcBefore, funcAfter(evaluateFunc()); bool finished; do { finished = false; pOrig = p; funcBefore = funcAfter; evaluateGradientsExact(gradF, gradGradF); const scalar determinant = Foam::det(gradGradF); if( determinant > SMALL ) { disp = (inv(gradGradF, determinant) & gradF); p -= disp; funcAfter = evaluateFunc(); # ifdef DEBUGSmooth Info << nl << "gradF " << gradF << endl; Info << "gradGradF " << gradGradF << endl; Info << "det(gradGradF) " << determinant << endl; Info << "disp " << disp << endl; Info << "Func before " << funcBefore << endl; Info << "Func after " << funcAfter << endl; # endif scalar relax(0.8); label nLoops(0); while( funcAfter > funcBefore ) { p = pOrig - relax * disp; relax *= 0.5; funcAfter = evaluateFunc(); if( funcAfter < funcBefore ) continue; if( ++nLoops == 5 ) { //- it seems that this direction is wrong, stop the loop p = pOrig; disp = vector::zero; finished = true; funcAfter = funcBefore; } } if( mag(funcBefore - funcAfter) / funcBefore < tol ) finished = true; } else { //- move in random direction //- this is usually needed to move the point off the zero volume disp = vector::zero; forAll(tets_, tetI) { const partTet& tet = tets_[tetI]; const scalar Vtri = tet.mag(points_); if( Vtri < SMALL ) { triangle<point, point> tri ( points_[tet.a()], points_[tet.b()], points_[tet.c()] ); vector n = tri.normal(); const scalar d = mag(n); if( d > VSMALL ) disp += 0.01 * (n / d); } } p += disp; funcAfter = evaluateFunc(); } } while( (++iter < 100) && !finished ); # ifdef DEBUGSmooth scalar Vmin(VGREAT); forAll(tets_, tetI) Vmin = Foam::min(Vmin, tets_[tetI].mag(points_)); Info << nl << "New coordinates for point " << pointI_ << " are " << p << endl; Info << "Num iterations " << iter << " gradient " << gradF << endl; Info << "Vmin " << Vmin << endl; # endif return funcAfter; }