SundanceUnaryFunctor.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                              Sundance
00005 //                 Copyright (2005) Sandia Corporation
00006 // 
00007 // Copyright (year first published) Sandia Corporation.  Under the terms 
00008 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 
00009 // retains certain rights in this software.
00010 // 
00011 // This library is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Lesser General Public License as
00013 // published by the Free Software Foundation; either version 2.1 of the
00014 // License, or (at your option) any later version.
00015 //  
00016 // This library is distributed in the hope that it will be useful, but
00017 // WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 //                                                                                 
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA                                                                                
00025 // Questions? Contact Kevin Long (krlong@sandia.gov), 
00026 // Sandia National Laboratories, Livermore, California, USA
00027 // 
00028 // ************************************************************************
00029 /* @HEADER@ */
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   /* test first differentiation */
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   /* test first and second differentiation */
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   /* first test a sample of points in the domain */
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   /* Test for exception detection at the excluded point, if any */
00311   if (domain()->hasExcludedPoint())
00312     {
00313       isOK =  testInvalidValue(domain()->excludedPoint()) && isOK ;
00314     }
00315 
00316   /* Test for exception detection at a point below the lower bound */
00317   if (domain()->hasLowerBound())
00318     {
00319       isOK =  testInvalidValue(domain()->lowerBound() - 0.1) && isOK ;
00320     }
00321   
00322   /* Test for exception detection at a point above the upper bound */
00323   if (domain()->hasUpperBound())
00324     {
00325       isOK =  testInvalidValue(domain()->upperBound() + 0.1) && isOK ;
00326     }
00327   
00328   return isOK;
00329   
00330 
00331 }

Site Contact