MOAB: Mesh Oriented datABase  (version 5.2.1)
NumericalOFTest.cpp
Go to the documentation of this file.
00001 /* *****************************************************************
00002     MESQUITE -- The Mesh Quality Improvement Toolkit
00003 
00004     Copyright 2006 Lawrence Livermore National Laboratory.  Under
00005     the terms of Contract B545069 with the University of Wisconsin --
00006     Madison, Lawrence Livermore National Laboratory retains certain
00007     rights in this software.
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Lesser General Public
00011     License as published by the Free Software Foundation; either
00012     version 2.1 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     (lgpl.txt) along with this library; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 
00023     (2006) kraftche@cae.wisc.edu
00024 
00025   ***************************************************************** */
00026 
00027 /** \file NumericalQMTest.cpp
00028  *  \brief
00029  *  \author Jason Kraftcheck
00030  */
00031 
00032 #include "Mesquite.hpp"
00033 #include "ObjectiveFunctionTemplate.hpp"
00034 #include "UnitUtil.hpp"
00035 #include "PatchData.hpp"
00036 #include "MsqHessian.hpp"
00037 
00038 #include "cppunit/extensions/HelperMacros.h"
00039 
00040 using namespace MBMesquite;
00041 using namespace std;
00042 
00043 const double EPSILON = 1e-6;
00044 
00045 class NumericalOFTest : public CppUnit::TestFixture
00046 {
00047   private:
00048     CPPUNIT_TEST_SUITE( NumericalOFTest );
00049     CPPUNIT_TEST( test_gradient_constant );
00050     CPPUNIT_TEST( test_gradient_linear );
00051     CPPUNIT_TEST( test_handles_eval_failure );
00052     CPPUNIT_TEST( test_handles_eval_false );
00053     CPPUNIT_TEST( test_changed );
00054     CPPUNIT_TEST( test_unchanged );
00055     CPPUNIT_TEST( test_Hessian_fails );
00056     CPPUNIT_TEST_SUITE_END();
00057 
00058     PatchData pd;
00059 
00060   public:
00061     void setUp();
00062     void test_gradient_values( bool constant );
00063 
00064     void test_gradient_constant()
00065     {
00066         test_gradient_values( true );
00067     }
00068     void test_gradient_linear()
00069     {
00070         test_gradient_values( false );
00071     }
00072 
00073     void test_handles_eval_failure();
00074     void test_handles_eval_false();
00075     void test_changed();
00076     void test_unchanged();
00077     void test_Hessian_fails();
00078 };
00079 
00080 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( NumericalOFTest, "NumericalOFTest" );
00081 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( NumericalOFTest, "Unit" );
00082 
00083 /** Define a dummy ObjectiveFunction on which to do numerical gradient calculation
00084  *
00085  * If 'constant' flag is true, returns a constant value.
00086  * If 'constant' flag is false, returns a linear function of vertex coordinates.
00087  */
00088 class NumericalTestOF : public ObjectiveFunctionTemplate
00089 {
00090   public:
00091     NumericalTestOF( bool should_fail, bool should_return_false, bool constant_func )
00092         : changed( false ), fail( should_fail ), return_false( should_return_false ), constant( constant_func ),
00093           linearGrad( 1, 2, 3 )
00094     {
00095     }
00096 
00097     bool evaluate( EvalType type, PatchData& pd, double& val, bool free, MsqError& );
00098 
00099     ObjectiveFunction* clone() const
00100     {
00101         return new NumericalTestOF( *this );
00102     }
00103 
00104     void clear()
00105     {
00106         changed = true;
00107     }
00108 
00109     bool changed;       // "accumulated value" has changed (tester should initialize)
00110     bool fail;          // if true, calls to accumulate will unconditionally fail
00111     bool return_false;  // if true, evaluate will return false.
00112     bool constant;      // if true, OF value is constant, otherwise linear.
00113 
00114     const Vector3D linearGrad;
00115 };
00116 
00117 bool NumericalTestOF::evaluate( EvalType type, PatchData& pd, double& val, bool free, MsqError& err )
00118 {
00119     if( fail )
00120     {
00121         MSQ_SETERR( err )( "Expected failure of OF::evaluate", MsqError::INVALID_ARG );
00122         return false;
00123     }
00124 
00125     if( pd.num_free_vertices() < 1 )
00126     {
00127         MSQ_SETERR( err )( "PatchData without free vertices.", MsqError::INVALID_ARG );
00128         return false;
00129     }
00130 
00131     if( type != ObjectiveFunction::CALCULATE && type != ObjectiveFunction::TEMPORARY ) changed = true;
00132 
00133     if( constant )
00134     {
00135         val = 1.0;
00136         return !return_false;
00137     }
00138 
00139     val = 0.0;
00140     for( size_t i = 0; i < pd.num_nodes(); ++i )
00141     {
00142         const MsqVertex& v = pd.vertex_by_index( i );
00143         val += linearGrad[0] * v[0] + linearGrad[1] * v[1] + linearGrad[2] * v[2];
00144     }
00145 
00146     return !return_false;
00147 }
00148 
00149 void NumericalOFTest::setUp()
00150 {
00151     MsqPrintError err( std::cout );
00152 
00153     // Create a triangle mesh with three free vertices
00154     const double coords[]   = { 1, 1, 0, 2, 1, 0, 3, 1, 0, 2, 2, 0, 1, 3, 0, 1, 2, 0 };
00155     const bool fixed_vtx[]  = { true, false, true, false, true, false };
00156     const size_t tri_conn[] = { 0, 1, 5, 1, 2, 3, 3, 4, 5, 1, 3, 5 };
00157     pd.fill( 6, coords, 4, TRIANGLE, tri_conn, fixed_vtx, err );
00158     ASSERT_NO_ERROR( err );
00159 }
00160 
00161 void NumericalOFTest::test_gradient_values( bool constant )
00162 {
00163     NumericalTestOF func( false, false, constant );
00164     MsqPrintError err( std::cout );
00165     double value;
00166     vector< Vector3D > gradient;
00167 
00168     bool rval = func.evaluate_with_gradient( ObjectiveFunction::CALCULATE, pd, value, gradient, err );
00169     ASSERT_NO_ERROR( err );
00170     CPPUNIT_ASSERT( rval );
00171 
00172     Vector3D expected = constant ? Vector3D( 0, 0, 0 ) : func.linearGrad;
00173     CPPUNIT_ASSERT( gradient.size() == pd.num_free_vertices() );
00174     for( vector< Vector3D >::iterator i = gradient.begin(); i != gradient.end(); ++i )
00175         CPPUNIT_ASSERT_VECTORS_EQUAL( expected, *i, EPSILON );
00176 }
00177 
00178 void NumericalOFTest::test_handles_eval_failure()
00179 {
00180     MsqError err;
00181     NumericalTestOF func( true, false, true );
00182     double value;
00183     vector< Vector3D > gradient;
00184 
00185     func.evaluate_with_gradient( ObjectiveFunction::CALCULATE, pd, value, gradient, err );
00186     CPPUNIT_ASSERT( err );
00187 }
00188 
00189 void NumericalOFTest::test_handles_eval_false()
00190 {
00191     MsqError err;
00192     NumericalTestOF func( false, true, true );
00193     double value;
00194     vector< Vector3D > gradient;
00195 
00196     bool rval = func.evaluate_with_gradient( ObjectiveFunction::CALCULATE, pd, value, gradient, err );
00197     ASSERT_NO_ERROR( err );
00198     CPPUNIT_ASSERT( !rval );
00199 }
00200 
00201 void NumericalOFTest::test_changed()
00202 {
00203     MsqPrintError err( cout );
00204     NumericalTestOF func( false, false, true );
00205     double value;
00206     vector< Vector3D > gradient;
00207     bool rval;
00208 
00209     func.changed = false;
00210     rval         = func.evaluate_with_gradient( ObjectiveFunction::SAVE, pd, value, gradient, err );
00211     ASSERT_NO_ERROR( err );
00212     CPPUNIT_ASSERT( rval );
00213     CPPUNIT_ASSERT( func.changed );
00214 
00215     func.changed = false;
00216     rval         = func.evaluate_with_gradient( ObjectiveFunction::UPDATE, pd, value, gradient, err );
00217     ASSERT_NO_ERROR( err );
00218     CPPUNIT_ASSERT( rval );
00219     CPPUNIT_ASSERT( func.changed );
00220 }
00221 
00222 void NumericalOFTest::test_unchanged()
00223 {
00224     MsqPrintError err( cout );
00225     NumericalTestOF func( false, false, true );
00226     double value;
00227     vector< Vector3D > gradient;
00228     bool rval;
00229 
00230     func.changed = false;
00231     rval         = func.evaluate_with_gradient( ObjectiveFunction::TEMPORARY, pd, value, gradient, err );
00232     ASSERT_NO_ERROR( err );
00233     CPPUNIT_ASSERT( rval );
00234     CPPUNIT_ASSERT( !func.changed );
00235 }
00236 
00237 void NumericalOFTest::test_Hessian_fails()
00238 {
00239     MsqError err;
00240     NumericalTestOF func( false, false, true );
00241     double value;
00242     vector< Vector3D > gradient;
00243     MsqHessian Hessian;
00244 
00245     func.evaluate_with_Hessian( ObjectiveFunction::CALCULATE, pd, value, gradient, Hessian, err );
00246     CPPUNIT_ASSERT( err );
00247 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines