SundanceUnaryFunctor.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                             Sundance
00005 //                 Copyright 2011 Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Kevin Long (kevin.long@ttu.edu)
00038 // 
00039 
00040 /* @HEADER@ */
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   /* test first differentiation */
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   /* test first and second differentiation */
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   /* first test a sample of points in the domain */
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   /* Test for exception detection at the excluded point, if any */
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   /* Test for exception detection at a point below the lower bound */
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   /* Test for exception detection at a point above the upper bound */
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 }

Site Contact