00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "SundanceUnaryFunctor.hpp"
00043 #include "PlayaTabs.hpp"
00044 #include "SundanceOut.hpp"
00045
00046 using namespace Sundance;
00047 using namespace Teuchos;
00048
00049 void UnaryFunctor::eval1(const double* const x,
00050 int nx,
00051 double* f,
00052 double* df_dx) const
00053 {
00054 evalFDDerivs1(x, nx, f, df_dx);
00055 }
00056
00057
00058 void UnaryFunctor::eval2(const double* const x,
00059 int nx,
00060 double* f,
00061 double* df_dx,
00062 double* d2f_dxx) const
00063 {
00064 evalFDDerivs2(x, nx, f, df_dx, d2f_dxx);
00065 }
00066
00067 void UnaryFunctor::eval3(const double* const x,
00068 int nx,
00069 double* f,
00070 double* df_dx,
00071 double* d2f_dxx,
00072 double* d3f_dxxx) const
00073 {
00074 evalFDDerivs3(x, nx, f, df_dx, d2f_dxx, d3f_dxxx);
00075 }
00076
00077
00078 void UnaryFunctor::evalFDDerivs1(const double* const x,
00079 int nx,
00080 double* f,
00081 double* df_dx) const
00082 {
00083 eval0(x, nx, f);
00084
00085 double w1 = 1.0/h_/12.0;
00086
00087 for (int i=0; i<nx; i++)
00088 {
00089 double xPlus1 = x[i] + h_;
00090 double xMinus1 = x[i] - h_;
00091 double fPlus1;
00092 double fMinus1;
00093 double xPlus2 = x[i] + 2.0*h_;
00094 double xMinus2 = x[i] - 2.0*h_;
00095 double fPlus2;
00096 double fMinus2;
00097 eval0(&xPlus1, 1, &fPlus1);
00098 eval0(&xMinus1, 1, &fMinus1);
00099 eval0(&xPlus2, 1, &fPlus2);
00100 eval0(&xMinus2, 1, &fMinus2);
00101 df_dx[i] = w1*( 8.0*(fPlus1-fMinus1) - (fPlus2 - fMinus2) );
00102 }
00103 }
00104
00105 void UnaryFunctor::evalFDDerivs2(const double* const x,
00106 int nx,
00107 double* f,
00108 double* df_dx,
00109 double* d2f_dxx) const
00110 {
00111 eval0(x, nx, f);
00112
00113 double w1 = 1.0/h_/12.0;
00114 double w2 = w1/h_;
00115
00116 for (int i=0; i<nx; i++)
00117 {
00118 double xPlus1 = x[i] + h_;
00119 double xMinus1 = x[i] - h_;
00120 double fPlus1;
00121 double fMinus1;
00122 double xPlus2 = x[i] + 2.0*h_;
00123 double xMinus2 = x[i] - 2.0*h_;
00124 double fPlus2;
00125 double fMinus2;
00126 eval0(&xPlus1, 1, &fPlus1);
00127 eval0(&xMinus1, 1, &fMinus1);
00128 eval0(&xPlus2, 1, &fPlus2);
00129 eval0(&xMinus2, 1, &fMinus2);
00130 df_dx[i] = w1*( 8.0*(fPlus1-fMinus1) - (fPlus2 - fMinus2) );
00131 d2f_dxx[i] = w2*(16.0*(fPlus1 + fMinus1)
00132 - 30.0*f[i] - (fPlus2+fMinus2));
00133 }
00134 }
00135
00136 void UnaryFunctor::evalFDDerivs3(const double* const x,
00137 int nx,
00138 double* f,
00139 double* df_dx,
00140 double* d2f_dxx,
00141 double* d3f_dxxx) const
00142 {
00143 eval0(x, nx, f);
00144
00145 double w1 = 1.0/h_/12.0;
00146 double w2 = w1/h_;
00147 double w3 = 0.5/h_/h_/h_;
00148
00149 for (int i=0; i<nx; i++)
00150 {
00151 double xPlus1 = x[i] + h_;
00152 double xMinus1 = x[i] - h_;
00153 double fPlus1;
00154 double fMinus1;
00155 double xPlus2 = x[i] + 2.0*h_;
00156 double xMinus2 = x[i] - 2.0*h_;
00157 double fPlus2;
00158 double fMinus2;
00159 eval0(&xPlus1, 1, &fPlus1);
00160 eval0(&xMinus1, 1, &fMinus1);
00161 eval0(&xPlus2, 1, &fPlus2);
00162 eval0(&xMinus2, 1, &fMinus2);
00163 df_dx[i] = w1*( 8.0*(fPlus1-fMinus1) - (fPlus2 - fMinus2) );
00164 d2f_dxx[i] = w2*(16.0*(fPlus1 + fMinus1)
00165 - 30.0*f[i] - (fPlus2+fMinus2));
00166 d3f_dxxx[i] = w3*(fPlus2 - 2.0*fPlus1 + 2.0*fMinus1 - fMinus2);
00167 }
00168 }
00169
00170 bool UnaryFunctor::testDerivs(const double& x, const double& tol) const
00171 {
00172 Tabs tabs;
00173 Out::os() << tabs << std::endl << tabs
00174 << "comparing exact derivs to FD derivs for functor "
00175 << name() << std::endl;
00176
00177 double fExact;
00178 double fxExact;
00179 double fxxExact;
00180
00181 double fFD;
00182 double fxFD;
00183 double fxxFD;
00184
00185 bool isOK = true;
00186
00187
00188 Out::os() << tabs << "computing first derivatives at x=" << x << std::endl;
00189 {
00190 Tabs tabs1;
00191
00192 eval1(&x, 1, &fExact, &fxExact);
00193 Out::os() << tabs1 << "Exact: f=" << fExact << " df_dx=" << fxExact << std::endl;
00194 evalFDDerivs1(&x, 1, &fFD, &fxFD);
00195 Out::os() << tabs1 << "FD: f=" << fFD << " df_dx=" << fxFD << std::endl;
00196
00197 double fError = fabs(fFD - fExact)/(fabs(fExact) + h_);
00198 double fxError = fabs(fxFD - fxExact)/(fabs(fxExact)+h_);
00199 {
00200 Tabs tabs2;
00201 Out::os() << tabs2 << "| f-f_FD |=" << fError
00202 << " | df-df_FD |=" << fxError << std::endl;
00203 if (fError > tol)
00204 {
00205 Out::os() << tabs << "ERROR: function value mismatch!" << std::endl;
00206 isOK = false;
00207 }
00208 if (fxError > tol)
00209 {
00210 Out::os() << tabs << "ERROR: first derivative mismatch!" << std::endl;
00211 isOK = false;
00212 }
00213 }
00214 }
00215
00216 Out::os() << tabs << std::endl;
00217
00218
00219
00220 Out::os() << tabs << "computing first and second derivatives at x=" << x << std::endl;
00221 {
00222 Tabs tabs1;
00223
00224 eval2(&x, 1, &fExact, &fxExact, &fxxExact);
00225 Out::os() << tabs1 << "Exact: f=" << fExact
00226 << " df_dx=" << fxExact
00227 << " d2f_dx2=" << fxxExact
00228 << std::endl;
00229
00230 evalFDDerivs2(&x, 1, &fFD, &fxFD, &fxxFD);
00231 Out::os() << tabs1 << "FD: f=" << fFD << " df_dx=" << fxFD
00232 << " d2f_dx2=" << fxxFD << std::endl;
00233
00234 double fError = fabs(fFD - fExact)/(fabs(fExact) + h_);
00235 double fxError = fabs(fxFD - fxExact)/(fabs(fxExact)+h_);
00236 double fxxError = fabs(fxxFD - fxxExact)/(fabs(fxxExact)+h_);
00237 {
00238 Tabs tabs2;
00239 Out::os() << tabs2 << "| f-f_FD |=" << fError
00240 << " | df-df_FD |=" << fxError
00241 << " | d2f-d2f_FD |=" << fxxError << std::endl;
00242 if (fError > tol)
00243 {
00244 Out::os() << tabs << "ERROR: function value mismatch!" << std::endl;
00245 isOK = false;
00246 }
00247 if (fxError > tol)
00248 {
00249 Out::os() << tabs << "ERROR: first derivative mismatch!" << std::endl;
00250 isOK = false;
00251 }
00252 if (fxxError > tol)
00253 {
00254 Out::os() << tabs << "ERROR: second derivative mismatch!" << std::endl;
00255 isOK = false;
00256 }
00257 }
00258 }
00259
00260 Out::os() << tabs << std::endl;
00261 return isOK;
00262 }
00263
00264 bool UnaryFunctor::testInvalidValue(const double& badValue) const
00265 {
00266 Tabs tabs;
00267 bool detectedError = false;
00268
00269 Out::os() << std::endl << tabs
00270 << "testing exception detection for bad value x=" << badValue
00271 << " for function " << name() << std::endl;
00272 try
00273 {
00274 testDerivs(badValue, 1.0);
00275 }
00276 catch(std::exception& e)
00277 {
00278 detectedError = true;
00279 }
00280
00281 if (!detectedError)
00282 {
00283 Out::os() << tabs << "ERROR: missed detection of an exception at x=" << badValue
00284 << " for function " << name() << std::endl;
00285 }
00286 else
00287 {
00288 Out::os() << tabs << "the error was detected!" << std::endl;
00289 }
00290 return detectedError;
00291 }
00292
00293
00294 bool UnaryFunctor::test(int nx, const double& tol) const
00295 {
00296 bool isOK = true;
00297
00298 double a = -sqrt(1.5);
00299 double b = sqrt(2.0);
00300
00301
00302 if (domain()->hasLowerBound())
00303 {
00304 a = domain()->lowerBound();
00305 }
00306 if (domain()->hasUpperBound())
00307 {
00308 b = domain()->upperBound();
00309 }
00310
00311 double c = (b-a)/((double) nx+1);
00312 for (int i=1; i<=nx; i++)
00313 {
00314 double x = a + i*c;
00315 Out::os() << "testing at " << x << std::endl;
00316 if (domain()->hasExcludedPoint() && fabs(x-domain()->excludedPoint())<1.0e-14)
00317 {
00318 continue;
00319 }
00320 isOK = testDerivs(x, tol) && isOK ;
00321 }
00322
00323
00324 if (domain()->hasExcludedPoint())
00325 {
00326 Out::os() << "testing detection of excluded point x="
00327 << domain()->excludedPoint() << std::endl;
00328 isOK = testInvalidValue(domain()->excludedPoint()) && isOK ;
00329 }
00330
00331
00332 if (domain()->hasLowerBound())
00333 {
00334 Out::os() << "testing exception below lower bound x="
00335 << domain()->lowerBound() << std::endl;
00336 isOK = testInvalidValue(domain()->lowerBound() - 0.1) && isOK ;
00337 }
00338
00339
00340 if (domain()->hasUpperBound())
00341 {
00342 Out::os() << "testing exception above lower bound x="
00343 << domain()->upperBound() << std::endl;
00344
00345 isOK = testInvalidValue(domain()->upperBound() + 0.1) && isOK ;
00346 }
00347
00348 return isOK;
00349
00350
00351 }