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