From d289aae9e11645e5cb83cd5610c091450a33a77b Mon Sep 17 00:00:00 2001 From: Thomas Toulorge <thomas.toulorge@mines-paristech.fr> Date: Tue, 23 Apr 2013 00:18:25 +0000 Subject: [PATCH] Added analytical gradients and Hessian for NACA00 level-set --- Geo/gmshLevelset.cpp | 103 ++++++++++++++++++++++++++++++++++++------- Geo/gmshLevelset.h | 12 ++++- 2 files changed, 99 insertions(+), 16 deletions(-) diff --git a/Geo/gmshLevelset.cpp b/Geo/gmshLevelset.cpp index 6d82c1cd2c..97be674aee 100644 --- a/Geo/gmshLevelset.cpp +++ b/Geo/gmshLevelset.cpp @@ -1229,41 +1229,114 @@ gLevelsetConrod::gLevelsetConrod(const gLevelsetConrod &lv) // Level-set for NACA0012 airfoil, last coeff. modified for zero-thickness trailing edge // cf. http://en.wikipedia.org/wiki/NACA_airfoil -double gLevelsetNACA00::operator() (const double x, const double y, const double z) const +gLevelsetNACA00::gLevelsetNACA00(double x0, double y0, double c, double t) + : _x0(x0), _y0(y0), _c(c), _t(t) +{ + _hasDerivatives = true; +} + + +void gLevelsetNACA00::getClosestBndPoint(const double x, const double y, const double z, + double &xb, double &yb, double &curvRad, bool &in) const { static const int maxIter = 100; static const double tol = 1.e-8; const double tolr = tol/_c; // Tolerance (scaled bu chord) - double distSq; // Square of dist. between point and boundary - bool in = false; // Whether the point is inside the airfoil + in = false; // Whether the point is inside the airfoil const double xt = x-_x0, yt = fabs(y-_y0); // Point translated according to airfoil origin and symmetry - if (xt-_c > 1.21125*_t*yt) // Behind line normal to airfoil at trailing edge, closest - distSq = (xt-_c)*(xt-_c)+yt*yt; // boundary point is trailing edge - else { // Otherwise Newton-Raphson to find closest boundary point + if (xt-_c > 1.21125*_t*yt) { // Behind line normal to airfoil at trailing edge, closest + xb = _x0+_c; // boundary point is trailing edge... + yb = _y0; + curvRad = 0.; + } + else { // ...otherwise Newton-Raphson to find closest boundary point const double fact = 5.*_t*_c; - double xb = std::max(xt,tolr); + double xtb = std::max(xt,tolr), ytb; + double dyb, ddyb; for (int it=0; it<maxIter; it++) { - const double xbr = xb/_c, sxbr = sqrt(xbr), xbr32 = xbr*sxbr, + const double xbr = xtb/_c, sxbr = sqrt(xbr), xbr32 = xbr*sxbr, xbr2 = xbr*xbr, xbr3 = xbr2*xbr, xbr4 = xbr2*xbr2; - double yb = fact*(0.2969*sxbr-0.1260*xbr-0.3516*xbr2+0.2843*xbr3-0.1036*xbr4); - const double dyb = fact*(0.14845/sxbr-0.4144*xbr3+0.8529*xbr2-0.7032*xbr-0.126)/_c; - const double ddyb = fact*(-0.074225/xbr32-1.2432*xbr2+1.7058*xbr-0.7032)/(_c*_c); - const double xx = xt-xb, yy = yt-yb; + ytb = fact*(0.2969*sxbr-0.1260*xbr-0.3516*xbr2+0.2843*xbr3-0.1036*xbr4); + dyb = fact*(0.14845/sxbr-0.4144*xbr3+0.8529*xbr2-0.7032*xbr-0.126)/_c; + ddyb = fact*(-0.074225/xbr32-1.2432*xbr2+1.7058*xbr-0.7032)/(_c*_c); + const double xx = xt-xtb, yy = yt-ytb; in = (xt > 0) && (yy < 0); - distSq = xx*xx+yy*yy; const double dDistSq = -2.*(xx+dyb*yy); const double ddDistSq = 2.*(1.-ddyb*yy+dyb*dyb); const double mIncr = dDistSq/ddDistSq; if (fabs(mIncr) < tolr) break; - else xb -= mIncr; - if (xb < tolr) xb = tolr; + else xtb -= mIncr; + if (xtb < tolr) xtb = tolr; } + xb = _x0+xtb; + yb = (y >= _y0) ? _y0+ytb : -(_y0+ytb); + const double norm = sqrt(1.+dyb*dyb); + curvRad = norm*norm*norm/fabs(ddyb); } +} + + +double gLevelsetNACA00::operator() (const double x, const double y, const double z) const +{ + + double xb, yb, curvRadb; + bool in; + + getClosestBndPoint(x, y, z, xb, yb, curvRadb, in); + const double xx = x-xb, yy = y-yb, distSq = xx*xx+yy*yy; + return in ? -sqrt(distSq) : sqrt(distSq); } + + +void gLevelsetNACA00::gradient (double x, double y, double z, + double & dfdx, double & dfdy, double & dfdz) const +{ + + double xb, yb, curvRadb; + bool in; + + getClosestBndPoint(x, y, z, xb, yb, curvRadb, in); + const double xx = x-xb, yy = y-yb, distSq = xx*xx+yy*yy; + const double dist = in ? -sqrt(distSq) : sqrt(distSq); + + dfdx = xx/dist; + dfdy = yy/dist; + dfdz = 0.; + +} + + +void gLevelsetNACA00::hessian (double x, double y, double z, + double & dfdxx, double & dfdxy, double & dfdxz, + double & dfdyx, double & dfdyy, double & dfdyz, + double & dfdzx, double & dfdzy, double & dfdzz) const +{ + + + double xb, yb, curvRadb; + bool in; + + getClosestBndPoint(x, y, z, xb, yb, curvRadb, in); + + const double xx = x-xb, yy = y-yb, distSq = xx*xx+yy*yy; + const double dist = in ? -sqrt(distSq) : sqrt(distSq); + const double oneOverCurvRad = 1./(curvRadb+dist); + + dfdxx = yy*yy*oneOverCurvRad; + dfdxy = -xx*yy*oneOverCurvRad; + dfdxz = 0.; + dfdyx = dfdxy; + dfdyy = xx*xx*oneOverCurvRad; + dfdyz = 0.; + dfdzx = 0.; + dfdzy = 0.; + dfdzz = 0.; + +} diff --git a/Geo/gmshLevelset.h b/Geo/gmshLevelset.h index 609af08581..d40cb9c239 100644 --- a/Geo/gmshLevelset.h +++ b/Geo/gmshLevelset.h @@ -621,10 +621,20 @@ class gLevelsetNACA00: public gLevelsetPrimitive { double _x0, _y0, _c, _t; public: - gLevelsetNACA00(double x0, double y0, double c, double t) : _x0(x0), _y0(y0), _c(c), _t(t) {} + gLevelsetNACA00(double x0, double y0, double c, double t); ~gLevelsetNACA00() {} double operator () (const double x, const double y, const double z) const; +// std::vector<double> getValueAndGradients(const double x, const double y, const double z) const; + void gradient (double x, double y, double z, + double & dfdx, double & dfdy, double & dfdz) const; + void hessian (double x, double y, double z, + double & dfdxx, double & dfdxy, double & dfdxz, + double & dfdyx, double & dfdyy, double & dfdyz, + double & dfdzx, double & dfdzy, double & dfdzz ) const; int type() const { return UNKNOWN; } +private: + void getClosestBndPoint(const double x, const double y, const double z, + double &xb, double &yb, double &curvRad, bool &in) const; }; #endif -- GitLab