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 #ifndef THYRA_TESTING_TOOLS_HPP
00030 #define THYRA_TESTING_TOOLS_HPP
00031
00032 #include "Thyra_TestingToolsDecl.hpp"
00033 #include "Thyra_VectorBase.hpp"
00034 #include "Thyra_VectorStdOps.hpp"
00035 #include "Thyra_LinearOpBase.hpp"
00036 #include "Thyra_AssertOp.hpp"
00037 #include "Teuchos_as.hpp"
00038
00039
00040
00041 template <bool hasMachineParameters, class Scalar>
00042 class relErrSmallNumber {
00043 public:
00044 static Scalar smallNumber()
00045 {
00046 return Teuchos::ScalarTraits<Scalar>::ThisShouldNotCompile();
00047 }
00048 };
00049
00050 template <class Scalar>
00051 class relErrSmallNumber<false,Scalar> {
00052 public:
00053 static Scalar smallNumber()
00054 {
00055 return Scalar(1e-8);
00056 }
00057 };
00058
00059
00060 template <class Scalar>
00061 class relErrSmallNumber<true,Scalar> {
00062 public:
00063 static Scalar smallNumber()
00064 {
00065 return Teuchos::ScalarTraits<Scalar>::eps();
00066 }
00067 };
00068
00069
00070 template <class Scalar>
00071 typename Teuchos::ScalarTraits<Scalar>::magnitudeType
00072 Thyra::relErr( const Scalar &s1, const Scalar &s2 )
00073 {
00074 typedef Teuchos::ScalarTraits<Scalar> ST;
00075 return
00076 ST::magnitude( s1 - s2 )
00077 / (
00078 ST::magnitude(
00079 relErrSmallNumber<ST::hasMachineParameters,Scalar>::smallNumber()
00080 )
00081 + std::max( ST::magnitude(s1), ST::magnitude(s1) )
00082 );
00083 }
00084
00085
00086 template <class Scalar>
00087 typename Teuchos::ScalarTraits<Scalar>::magnitudeType
00088 Thyra::relVectorErr( const VectorBase<Scalar> &v1, const VectorBase<Scalar> &v2 )
00089 {
00090 typedef Teuchos::ScalarTraits<Scalar> ST;
00091 typedef typename ST::magnitudeType ScalarMag;
00092 #ifdef TEUCHOS_DEBUG
00093 THYRA_ASSERT_VEC_SPACES( "relErr(v1,v2)", *v1.space(), *v2.space() );
00094 #endif
00095 Teuchos::RCP<VectorBase<Scalar> >
00096 diff = createMember(v1.space());
00097 V_VmV( &*diff, v1, v2 );
00098 const ScalarMag
00099 nrm_v1 = norm(v1),
00100 nrm_v2 = norm(v2),
00101 nrm_diff = norm(*diff);
00102 return
00103 ( nrm_diff
00104 / (
00105 ST::magnitude(
00106 relErrSmallNumber<ST::hasMachineParameters,Scalar>::smallNumber()
00107 )
00108 + std::max( nrm_v1, nrm_v2 )
00109 )
00110 );
00111 }
00112
00113
00114 template<class Scalar>
00115 bool Thyra::testRelErr(
00116 const std::string &v1_name
00117 ,const Scalar &v1
00118 ,const std::string &v2_name
00119 ,const Scalar &v2
00120 ,const std::string &maxRelErr_error_name
00121 ,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_error
00122 ,const std::string &maxRelErr_warning_name
00123 ,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_warning
00124 ,std::ostream *out
00125 ,const std::string &li
00126 )
00127 {
00128 typedef Teuchos::ScalarTraits<Scalar> ST;
00129 typedef typename ST::magnitudeType ScalarMag;
00130 typedef Teuchos::ScalarTraits<ScalarMag> SMT;
00131 const ScalarMag rel_err = relErr( v1, v2 );
00132 const bool success = ( !SMT::isnaninf(rel_err) && !SMT::isnaninf(maxRelErr_error) && rel_err <= maxRelErr_error );
00133 if(out) {
00134 *out
00135 << std::endl
00136 << li << "Check: rel_err(" << v1_name << "," << v2_name << ")\n"
00137 << li << " = rel_err(" << v1 << "," << v2 << ") "
00138 << "= " << rel_err << std::endl
00139 << li << " <= " << maxRelErr_error_name << " = " << maxRelErr_error << " : " << passfail(success) << std::endl;
00140 if( success && rel_err >= maxRelErr_warning ) {
00141 *out
00142 << li << "Warning! rel_err(" << v1_name << "," << v2_name << ")\n"
00143 << li << " = rel_err(" << v1 << "," << v2 << ") " << "= " << rel_err << std::endl
00144 << li << " >= " << maxRelErr_warning_name << " = " << maxRelErr_warning << "!\n";
00145 }
00146 }
00147 return success;
00148 }
00149
00150 template<class Scalar1, class Scalar2, class ScalarMag>
00151 bool Thyra::testRelErrors(
00152 const int num_scalars
00153 ,const std::string &v1_name
00154 ,const Scalar1 v1[]
00155 ,const std::string &v2_name
00156 ,const Scalar2 v2[]
00157 ,const std::string &maxRelErr_error_name
00158 ,const ScalarMag &maxRelErr_error
00159 ,const std::string &maxRelErr_warning_name
00160 ,const ScalarMag &maxRelErr_warning
00161 ,std::ostream *out
00162 ,const std::string &li
00163 )
00164 {
00165 using std::setw;
00166 typedef Teuchos::ScalarTraits<ScalarMag> SMT;
00167 typedef typename Teuchos::PromotionTraits<Scalar1,Scalar2>::promote Scalar;
00168 if(num_scalars==1) {
00169 return testRelErr<Scalar>(
00170 v1_name,v1[0],v2_name,v2[0]
00171 ,maxRelErr_error_name,maxRelErr_error
00172 ,maxRelErr_warning_name,maxRelErr_warning
00173 ,out,li
00174 );
00175 }
00176 bool success = true;
00177 if(out) *out
00178 << std::endl
00179 << li << "Check: rel_err(" << v1_name << "," << v2_name << ") <= " << maxRelErr_error_name << " ?\n";
00180 for( int i = 0; i < num_scalars; ++i ) {
00181 const ScalarMag rel_err = relErr<Scalar>( v1[i], v2[i] );
00182 const bool result = ( !SMT::isnaninf(rel_err) && !SMT::isnaninf(maxRelErr_error) && rel_err <= maxRelErr_error );
00183 if(!result) success = false;
00184 if(out) {
00185 *out
00186 << li << " "<<setw(2)<<i<<": rel_err("<<v1[i]<<","<<v2[i]<<") "<<"= "<<rel_err
00187 << " <= " << maxRelErr_error << " : " << passfail(result) << std::endl;
00188 if( result && rel_err >= maxRelErr_warning ) {
00189 *out
00190 << li << " Warning! rel_err(...) >= " << maxRelErr_warning_name << " = " << maxRelErr_warning << "!\n";
00191 }
00192 }
00193 }
00194 return success;
00195 }
00196
00197
00198 template<class Scalar>
00199 bool Thyra::testRelNormDiffErr(
00200 const std::string &v1_name,
00201 const VectorBase<Scalar> &v1,
00202 const std::string &v2_name,
00203 const VectorBase<Scalar> &v2,
00204 const std::string &maxRelErr_error_name,
00205 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_error,
00206 const std::string &maxRelErr_warning_name,
00207 const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_warning,
00208 std::ostream *out,
00209 const Teuchos::EVerbosityLevel verbLevel,
00210 const std::string &li
00211 )
00212 {
00213 using std::endl;
00214 using Teuchos::as;
00215 typedef Teuchos::ScalarTraits<Scalar> ST;
00216 typedef typename ST::magnitudeType ScalarMag;
00217 typedef Teuchos::ScalarTraits<ScalarMag> SMT;
00218 const ScalarMag
00219 nrm_v1 = norm(v1),
00220 nrm_v2 = norm(v2);
00221 const ScalarMag rel_err = relVectorErr(v1,v2);
00222 const bool success =
00223 (
00224 !SMT::isnaninf(rel_err)
00225 && !SMT::isnaninf(maxRelErr_error)
00226 && rel_err <= maxRelErr_error
00227 );
00228 if(out) {
00229 *out
00230 << endl
00231 << li << "Testing relative error between vectors " << v1_name << " and " << v2_name << ":\n"
00232 << li << " ||"<<v1_name<<"|| = " << nrm_v1 << endl
00233 << li << " ||"<<v2_name<<"|| = " << nrm_v2 << endl;
00234 if ( as<int>(verbLevel) >= as<int>(Teuchos::VERB_HIGH) ) {
00235 *out
00236 << li << " " << v1_name << " = " << describe(v1,verbLevel)
00237 << li << " " << v2_name << " = " << describe(v2,verbLevel);
00238 Teuchos::RCP<VectorBase<Scalar> >
00239 diff = createMember(v1.space());
00240 V_VmV( &*diff, v1, v2 );
00241 *out
00242 << li << " " << v1_name << " - " << v2_name << " = " << describe(*diff,verbLevel);
00243 }
00244 *out
00245 << li << " Check: rel_err(" << v1_name << "," << v2_name << ") = "
00246 << rel_err << " <= " << maxRelErr_error_name << " = " << maxRelErr_error << " : " << passfail(success) << endl;
00247 if( success && rel_err >= maxRelErr_warning ) {
00248 *out
00249 << li << " Warning! rel_err(" << v1_name << "," << v2_name << " >= "
00250 << maxRelErr_warning_name << " = " << maxRelErr_warning << "!\n";
00251 }
00252 }
00253 return success;
00254 }
00255
00256
00257 template<class Scalar>
00258 bool Thyra::testMaxErr(
00259 const std::string &error_name
00260 ,const Scalar &error
00261 ,const std::string &max_error_name
00262 ,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &max_error
00263 ,const std::string &max_warning_name
00264 ,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &max_warning
00265 ,std::ostream *out
00266 ,const std::string &li
00267 )
00268 {
00269 typedef Teuchos::ScalarTraits<Scalar> ST;
00270 typedef typename ST::magnitudeType ScalarMag;
00271 typedef Teuchos::ScalarTraits<ScalarMag> SMT;
00272 const ScalarMag error_mag = ST::magnitude(error);
00273 const bool success = ( !SMT::isnaninf(error_mag) && !SMT::isnaninf(max_error) && error_mag <= max_error );
00274 if(out) {
00275 *out
00276 << std::endl
00277 << li << "Check: |" << error_name << "| = " << error_mag
00278 << " <= " << max_error_name << " = " << max_error << " : " << passfail(success) << std::endl;
00279 if( success && error_mag >= max_warning ) {
00280 *out
00281 << li << "Warning! " << error_name << " = " << error_mag
00282 << " >= " << max_warning_name << " = " << max_warning << "!\n";
00283 }
00284 }
00285 return success;
00286 }
00287
00288 template<class Scalar>
00289 bool Thyra::testMaxErrors(
00290 const int num_scalars
00291 ,const std::string &error_name
00292 ,const Scalar error[]
00293 ,const std::string &max_error_name
00294 ,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &max_error
00295 ,const std::string &max_warning_name
00296 ,const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &max_warning
00297 ,std::ostream *out
00298 ,const std::string &li
00299 )
00300 {
00301 using std::setw;
00302 typedef Teuchos::ScalarTraits<Scalar> ST;
00303 typedef typename ST::magnitudeType ScalarMag;
00304 typedef Teuchos::ScalarTraits<ScalarMag> SMT;
00305 if(num_scalars==1) {
00306 return testMaxErr(
00307 error_name,error[0]
00308 ,max_error_name,max_error
00309 ,max_warning_name,max_warning
00310 ,out,li
00311 );
00312 }
00313 bool success = true;
00314 if(out) *out
00315 << std::endl
00316 << li << "Check: |"<<error_name<<"| <= "<<max_error_name<<" ?\n";
00317 for( int i = 0; i < num_scalars; ++i ) {
00318 const ScalarMag error_mag = ST::magnitude(error[i]);
00319 const bool result = ( !SMT::isnaninf(error_mag) && !SMT::isnaninf(max_error) && error_mag <= max_error );
00320 if(!result) success = false;
00321 if(out) {
00322 *out
00323 << li << " "<<setw(2)<<i<<": |"<<error[i]<<"| = "<<error_mag<<" <= "<<max_error<<" : "<<passfail(success)<<"\n";
00324 if( result && error_mag >= max_warning ) {
00325 *out
00326 << li << " Warning! |...| >= "<<max_warning_name<<" = "<<max_warning<<"!\n";
00327 }
00328 }
00329 }
00330 return success;
00331 }
00332
00333 template<class Scalar>
00334 std::ostream& Thyra::operator<<( std::ostream& o, const VectorBase<Scalar>& v )
00335 {
00336 return o << Teuchos::describe(v,Teuchos::VERB_EXTREME);
00337 }
00338
00339 template<class Scalar>
00340 std::ostream& Thyra::operator<<( std::ostream& o, const LinearOpBase<Scalar>& M )
00341 {
00342 return o << Teuchos::describe(M,Teuchos::VERB_EXTREME);
00343 }
00344
00345 #endif // THYRA_TESTING_TOOLS_HPP