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 #include "Epetra_Map.h"
00031 #include "Epetra_Vector.h"
00032 #include "Epetra_Version.h"
00033 #ifdef HAVE_MPI
00034 #include "Epetra_MpiComm.h"
00035 #include "mpi.h"
00036 #else
00037 #include "Epetra_SerialComm.h"
00038 #endif // HAVE_MPI
00039
00040 #include "ExampleApplication.hpp"
00041
00042
00043 #include "Rythmos_ConfigDefs.h"
00044
00045 #include "Rythmos_ForwardEulerStepper.hpp"
00046 #include "Rythmos_BackwardEulerStepper.hpp"
00047 #include "Rythmos_ExplicitRKStepper.hpp"
00048 #include "Rythmos_ImplicitBDFStepper.hpp"
00049
00050
00051 #include "Thyra_EpetraThyraWrappers.hpp"
00052 #include "Thyra_EpetraLinearOp.hpp"
00053 #include "Thyra_EpetraModelEvaluator.hpp"
00054 #include "Thyra_LinearNonlinearSolver.hpp"
00055 #include "Thyra_TimeStepNewtonNonlinearSolver.hpp"
00056 #include "Thyra_TestingTools.hpp"
00057
00058
00059 #ifdef HAVE_RYTHMOS_STRATIMIKOS
00060 # include "Thyra_DefaultRealLinearSolverBuilder.hpp"
00061 #endif
00062
00063 #include <string>
00064
00065
00066 #include "Teuchos_RefCountPtr.hpp"
00067 #include "Teuchos_ParameterList.hpp"
00068 #include "Teuchos_CommandLineProcessor.hpp"
00069 #include "Teuchos_FancyOStream.hpp"
00070 #include "Teuchos_GlobalMPISession.hpp"
00071 #include "Teuchos_VerboseObject.hpp"
00072 #include "Teuchos_StandardCatchMacros.hpp"
00073
00074 enum EMethod { METHOD_FE, METHOD_BE, METHOD_ERK, METHOD_BDF };
00075 enum EStepMethod { FIXED_STEP, VARIABLE_STEP };
00076
00077 int main(int argc, char *argv[])
00078 {
00079 bool verbose = false;
00080 bool result, success = true;
00081
00082 Teuchos::GlobalMPISession mpiSession(&argc,&argv);
00083
00084 Teuchos::RefCountPtr<Teuchos::FancyOStream>
00085 out = Teuchos::VerboseObjectBase::getDefaultOStream();
00086
00087 #ifdef HAVE_MPI
00088 MPI_Comm mpiComm = MPI_COMM_WORLD;
00089 #endif // HAVE_MPI
00090
00091 try {
00092
00093 double lambda_min = -0.9;
00094 double lambda_max = -0.01;
00095 double coeff_s = 0.0;
00096 std::string lambda_fit = "linear";
00097 int numElements = 1;
00098 double x0 = 10.0;
00099 double finalTime = 1.0;
00100 int N = 10;
00101 const int num_methods = 4;
00102 const EMethod method_values[] = { METHOD_FE, METHOD_BE, METHOD_ERK, METHOD_BDF };
00103 const char * method_names[] = { "FE", "BE", "ERK", "BDF" };
00104 EMethod method_val = METHOD_ERK;
00105 const int num_step_methods = 2;
00106 const EStepMethod step_method_values[] = { FIXED_STEP, VARIABLE_STEP };
00107 const char * step_method_names[] = { "fixed", "variable" };
00108 EStepMethod step_method_val = FIXED_STEP;
00109 double maxError = 1e-6;
00110 bool version = false;
00111 double reltol = 1.0e-2;
00112 double abstol = 1.0e-4;
00113 int maxOrder = 5;
00114 #ifdef Rythmos_DEBUG
00115 int debugLevel = 2;
00116 #endif // Rythmos_DEBUG
00117
00118
00119 Teuchos::CommandLineProcessor clp(false);
00120 clp.addOutputSetupOptions(true);
00121 #ifdef HAVE_RYTHMOS_STRATIMIKOS
00122 Thyra::DefaultRealLinearSolverBuilder lowsfCreator;
00123 lowsfCreator.setupCLP(&clp);
00124 #endif
00125 clp.setOption( "x0", &x0, "Constant ODE initial condition." );
00126 clp.setOption( "T", &finalTime, "Final time for simulation." );
00127 clp.setOption( "lambda_min", &lambda_min, "Lower bound for ODE coefficient");
00128 clp.setOption( "lambda_max", &lambda_max, "Upper bound for ODE coefficient");
00129 clp.setOption( "lambda_fit", &lambda_fit, "Lambda model: random, linear");
00130 clp.setOption( "force_coeff", &coeff_s, "Forcing term coefficient");
00131 clp.setOption( "numelements", &numElements, "Problem size");
00132 clp.setOption( "method", &method_val, num_methods, method_values, method_names, "Integration method" );
00133 clp.setOption( "stepmethod", &step_method_val, num_step_methods, step_method_values, step_method_names, "Stepping method" );
00134 clp.setOption( "numsteps", &N, "Number of integration steps to take" );
00135 clp.setOption( "maxerror", &maxError, "Maximum error" );
00136 clp.setOption( "verbose", "quiet", &verbose, "Set if output is printed or not" );
00137 clp.setOption( "version", "run", &version, "Version of this code" );
00138 clp.setOption( "reltol", &reltol, "Relative Error Tolerance" );
00139 clp.setOption( "abstol", &abstol, "Absolute Error Tolerance" );
00140 clp.setOption( "maxorder", &maxOrder, "Maximum Implicit BDF order" );
00141 #ifdef Rythmos_DEBUG
00142 clp.setOption( "debuglevel", &debugLevel, "Debug Level for Rythmos" );
00143 #endif // Rythmos_DEBUG
00144
00145 Teuchos::CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
00146 if( parse_return != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
00147
00148 #ifdef HAVE_RYTHMOS_STRATIMIKOS
00149 lowsfCreator.readParameters(out.get());
00150 *out << "\nThe parameter list after being read in:\n";
00151 lowsfCreator.getParameterList()->print(*out,2,true,false);
00152 #endif
00153
00154 if (version)
00155 {
00156 *out << Rythmos::Rythmos_Version() << std::endl;
00157 *out << "basicExample Version 0.1 - 06/23/05" << std::endl;
00158 return(0);
00159 }
00160
00161 if (lambda_min > lambda_max)
00162 {
00163 *out << "lamba_min must be less than lambda_max" << std::endl;
00164 return(1);
00165 }
00166
00167 if (finalTime <= 0.0)
00168 {
00169 *out << "Final simulation time must be > 0.0." << std::endl;
00170 return(1);
00171 }
00172
00173 #ifdef Rythmos_DEBUG
00174 *out << std::setprecision(15);
00175 #endif // Rythmos_DEBUG
00176
00177
00178 Teuchos::ParameterList params;
00179 bool implicitFlag = ((method_val==METHOD_BE) | (method_val==METHOD_BDF));
00180
00181 params.set( "implicit", implicitFlag );
00182 params.set( "Lambda_min", lambda_min );
00183 params.set( "Lambda_max", lambda_max );
00184 params.set( "Lambda_fit", lambda_fit );
00185 params.set( "NumElements", numElements );
00186 params.set( "x0", x0 );
00187 params.set( "Coeff_s", coeff_s );
00188 #ifdef HAVE_MPI
00189 Teuchos::RefCountPtr<Epetra_Comm> epetra_comm_ptr_ = Teuchos::rcp( new Epetra_MpiComm(mpiComm) );
00190 #else
00191 Teuchos::RefCountPtr<Epetra_Comm> epetra_comm_ptr_ = Teuchos::rcp( new Epetra_SerialComm );
00192 #endif // HAVE_MPI
00193
00194
00195 Teuchos::RefCountPtr<Thyra::LinearOpWithSolveFactoryBase<double> >
00196 W_factory;
00197 if((method_val == METHOD_BE) | (method_val == METHOD_BDF)) {
00198 #ifdef HAVE_RYTHMOS_STRATIMIKOS
00199 W_factory = lowsfCreator.createLinearSolveStrategy("");
00200 *out
00201 << "\nCreated a LinearOpWithSolveFactory described as:\n"
00202 << Teuchos::describe(*W_factory,Teuchos::VERB_MEDIUM);
00203 #endif
00204 }
00205
00206
00207 Teuchos::RefCountPtr<ExampleApplication>
00208 epetraModel = Teuchos::rcp(new ExampleApplication(epetra_comm_ptr_, params));
00209 Teuchos::RefCountPtr<Thyra::ModelEvaluator<double> >
00210 model = Teuchos::rcp(new Thyra::EpetraModelEvaluator(epetraModel,W_factory));
00211
00212
00213 std::string method;
00214 Teuchos::RefCountPtr<Rythmos::Stepper<double> > stepper_ptr;
00215 if ( method_val == METHOD_ERK ) {
00216 stepper_ptr = Teuchos::rcp(new Rythmos::ExplicitRKStepper<double>(model));
00217 method = "Explicit Runge-Kutta of order 4";
00218 step_method_val = FIXED_STEP;
00219 } else if (method_val == METHOD_FE) {
00220 stepper_ptr = Teuchos::rcp(new Rythmos::ForwardEulerStepper<double>(model));
00221 method = "Forward Euler";
00222 step_method_val = FIXED_STEP;
00223 } else if ((method_val == METHOD_BE) | (method_val == METHOD_BDF)) {
00224 Teuchos::RefCountPtr<Thyra::NonlinearSolverBase<double> >
00225 nonlinearSolver;
00226 Teuchos::RefCountPtr<Thyra::TimeStepNewtonNonlinearSolver<double> >
00227 _nonlinearSolver = Teuchos::rcp(new Thyra::TimeStepNewtonNonlinearSolver<double>());
00228 _nonlinearSolver->defaultTol(1e-3*maxError);
00229 nonlinearSolver = _nonlinearSolver;
00230 if (method_val == METHOD_BE)
00231 {
00232 stepper_ptr = Teuchos::rcp(new Rythmos::BackwardEulerStepper<double>(model,nonlinearSolver));
00233 method = "Backward Euler";
00234 step_method_val = FIXED_STEP;
00235 }
00236 else
00237 {
00238 Teuchos::ParameterList BDFparams;
00239 BDFparams.set( "stopTime", finalTime );
00240 BDFparams.set( "maxOrder", maxOrder );
00241 BDFparams.set( "relErrTol", reltol );
00242 BDFparams.set( "absErrTol", abstol );
00243 #ifdef Rythmos_DEBUG
00244 BDFparams.set( "debugLevel", debugLevel );
00245 #endif // Rythmos_DEBUG
00246
00247 stepper_ptr = Teuchos::rcp(new Rythmos::ImplicitBDFStepper<double>(model,nonlinearSolver,BDFparams));
00248 method = "Implicit BDF";
00249
00250 }
00251 } else {
00252 TEST_FOR_EXCEPT(true);
00253 }
00254 Rythmos::Stepper<double> &stepper = *stepper_ptr;
00255 #ifdef Rythmos_DEBUG
00256 Teuchos::RefCountPtr<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
00257 if (debugLevel > 1)
00258 {
00259 stepper.describe(*out,Teuchos::VERB_EXTREME);
00260 }
00261 #endif // Rythmos_DEBUG
00262
00263 int numSteps = 0;
00264 double t0 = 0.0;
00265 double dt = (finalTime-t0)/N;
00266 double time = t0;
00267
00268 if (step_method_val == FIXED_STEP)
00269 {
00270
00271 for (int i=1 ; i<=N ; ++i)
00272 {
00273 double dt_taken = stepper.TakeStep(dt);
00274 time += dt_taken;
00275 numSteps++;
00276 #ifdef Rythmos_DEBUG
00277 if (debugLevel > 1)
00278 {
00279 stepper.describe(*out,Teuchos::VERB_EXTREME);
00280 }
00281 #endif // Rythmos_DEBUG
00282 if (dt_taken != dt)
00283 {
00284 cerr << "Error, stepper took step of dt = " << dt_taken << " when asked to take step of dt = " << dt << std::endl;
00285 break;
00286 }
00287 }
00288 }
00289 else
00290 {
00291 #ifdef Rythmos_DEBUG
00292
00293 Teuchos::RefCountPtr<const Thyra::VectorBase<double> > x_computed_thyra_ptr = stepper.get_solution();
00294
00295 Teuchos::RefCountPtr<const Epetra_Vector> x_computed_ptr = Thyra::get_Epetra_Vector(*(epetraModel->get_x_map()),x_computed_thyra_ptr);
00296
00297 Teuchos::RefCountPtr<Epetra_Vector> x_numerical_exact_ptr = Teuchos::rcp(new Epetra_Vector(x_computed_ptr->Map()));
00298 Epetra_Vector& x_numerical_exact = *x_numerical_exact_ptr;
00299
00300 Teuchos::RefCountPtr<Epetra_Vector> x_rel_diff_ptr = Teuchos::rcp(new Epetra_Vector(x_computed_ptr->Map()));
00301 Epetra_Vector& x_rel_diff = *x_rel_diff_ptr;
00302
00303 Teuchos::RefCountPtr<const Epetra_Vector> lambda_ptr = epetraModel->get_coeff();
00304 const Epetra_Vector &lambda = *lambda_ptr;
00305 #endif // Rythmos_DEBUG
00306 while (time < finalTime)
00307 {
00308 double dt_taken = stepper.TakeStep();
00309 numSteps++;
00310 #ifdef Rythmos_DEBUG
00311 if (debugLevel > 1)
00312 {
00313 stepper.describe(*out,Teuchos::VERB_EXTREME);
00314 }
00315 #endif // Rythmos_DEBUG
00316 if (dt_taken < 0)
00317 {
00318 *out << "Error, stepper failed for some reason with step taken = " << dt_taken << endl;
00319 break;
00320 }
00321 #ifdef Rythmos_DEBUG
00322
00323 x_computed_thyra_ptr = stepper.get_solution();
00324
00325 x_computed_ptr = Thyra::get_Epetra_Vector(*(epetraModel->get_x_map()),x_computed_thyra_ptr);
00326 if ((method_val == METHOD_BDF) && (maxOrder == 1))
00327 {
00328 int myN = x_numerical_exact.MyLength();
00329 if (numSteps == 1)
00330 {
00331 for (int i=0 ; i<myN ; ++i)
00332 x_numerical_exact[i] = x0;
00333 }
00334 for (int i=0 ; i<myN ; ++i)
00335 x_numerical_exact[i] = ( x_numerical_exact[i]
00336 +dt_taken*epetraModel->evalR(time+dt_taken,lambda[i],coeff_s))
00337 /(1-lambda[i]*dt_taken);
00338 for (int i=0 ; i<myN ; ++i)
00339 x_rel_diff[i] = (x_numerical_exact[i]-(*x_computed_ptr)[i])/x_numerical_exact[i];
00340 if (myN == 1)
00341 *out << "Computed x(" << time+dt_taken << ") = " << (*x_computed_ptr)[0]
00342 << " Numerical Exact = " << x_numerical_exact[0]
00343 << " Rel Diff = " << x_rel_diff[0] << std::endl;
00344 else
00345 {
00346 for (int i=0 ; i<myN ; ++i)
00347 *out << "Computed x_" << i << "(" << time+dt_taken << ") = " << (*x_computed_ptr)[i]
00348 << " Numerical Exact = " << x_numerical_exact[i]
00349 << " Rel Diff = " << x_rel_diff[i] << std::endl;
00350 }
00351 }
00352 else
00353 {
00354
00355 Teuchos::RefCountPtr<const Epetra_Vector> x_star_ptr = epetraModel->get_exact_solution(time);
00356 const Epetra_Vector& x_star = *x_star_ptr;
00357 int myN = x_computed_ptr->MyLength();
00358 for (int i=0 ; i<myN ; ++i)
00359 x_rel_diff[i] = (x_star[i]-(*x_computed_ptr)[i])/x_star[i];
00360 if (myN == 1)
00361 *out << "Computed x(" << time+dt_taken << ") = " << (*x_computed_ptr)[0]
00362 << " Exact = " << x_star[0]
00363 << " Rel Diff = " << x_rel_diff[0] << std::endl;
00364 else
00365 {
00366 for (int i=0 ; i<myN ; ++i)
00367 *out << "Computed x_" << i << "(" << time+dt_taken << ") = " << (*x_computed_ptr)[i]
00368 << " Exact = " << x_star[i]
00369 << " Rel Diff = " << x_rel_diff[i] << std::endl;
00370 }
00371 }
00372
00373 #endif // Rythmos_DEBUG
00374 time += dt_taken;
00375 *out << "Took stepsize of: " << dt_taken << " time = " << time << endl;
00376 }
00377 }
00378 *out << "Integrated to time = " << time << endl;
00379
00380
00381 Teuchos::RefCountPtr<const Thyra::VectorBase<double> > x_computed_thyra_ptr = stepper.get_solution();
00382
00383 Teuchos::RefCountPtr<const Epetra_Vector>
00384 x_computed_ptr = Thyra::get_Epetra_Vector(*(epetraModel->get_x_map()),x_computed_thyra_ptr);
00385 const Epetra_Vector &x_computed = *x_computed_ptr;
00386
00387
00388 Teuchos::RefCountPtr<const Epetra_Vector> x_star_ptr = epetraModel->get_exact_solution(finalTime);
00389 const Epetra_Vector& x_star = *x_star_ptr;
00390
00391
00392 Teuchos::RefCountPtr<const Epetra_Vector> lambda_ptr = epetraModel->get_coeff();
00393 const Epetra_Vector &lambda = *lambda_ptr;
00394
00395
00396 Teuchos::RefCountPtr<const Epetra_Vector> x_numerical_exact_ptr;
00397 if (method_val == METHOD_FE)
00398 {
00399 Teuchos::RefCountPtr<Epetra_Vector> x_exact_ptr = Teuchos::rcp(new Epetra_Vector(x_star.Map()));
00400 Epetra_Vector& x_exact = *x_exact_ptr;
00401 int myN = x_exact.MyLength();
00402 for ( int i=0 ; i<myN ; ++i)
00403 {
00404 x_exact[i] = x0;
00405 for (int j=1 ; j<=N ; ++j)
00406 {
00407 x_exact[i] = (1+lambda[i]*dt)*x_exact[i]+dt*epetraModel->evalR(0+j*dt,lambda[i],coeff_s);
00408 }
00409
00410 }
00411 x_numerical_exact_ptr = x_exact_ptr;
00412 }
00413 else if (method_val == METHOD_BE)
00414 {
00415 Teuchos::RefCountPtr<Epetra_Vector> x_exact_ptr = Teuchos::rcp(new Epetra_Vector(x_star.Map()));
00416 Epetra_Vector& x_exact = *x_exact_ptr;
00417 int myN = x_exact.MyLength();
00418 for ( int i=0 ; i<myN ; ++i)
00419 {
00420 x_exact[i] = x0;
00421 for (int j=1 ; j<=N ; ++j)
00422 {
00423 x_exact[i] = (x_exact[i]+dt*epetraModel->evalR(0+j*dt,lambda[i],coeff_s))/(1-lambda[i]*dt);
00424 }
00425
00426 }
00427 x_numerical_exact_ptr = x_exact_ptr;
00428 }
00429 else if (method_val == METHOD_BDF)
00430 {
00431
00432 }
00433
00434
00435
00436
00437
00438
00439 int MyPID = x_computed.Comm().MyPID();
00440 if (MyPID == 0)
00441 {
00442 *out << "Integrating \\dot{x}=\\lambda x from t = " << t0
00443 << " to t = " << finalTime << std::endl;
00444 *out << "using " << method << std::endl;
00445 *out << "with initial x_0 = " << x0
00446 << ", \\Delta t = " << dt << "." << std::endl;
00447 *out << "Took " << numSteps << " steps." << std::endl;
00448 }
00449 int MyLength = x_computed.MyLength();
00450 if (verbose)
00451 {
00452 for (int i=0 ; i<MyLength ; ++i)
00453 {
00454 *out << std::setprecision(15);
00455 *out << "lambda[" << MyPID*MyLength+i << "] = " << lambda[i] << std::endl;
00456 }
00457
00458 for (int i=0 ; i<MyLength ; ++i)
00459 {
00460 *out << std::setprecision(15);
00461 *out << "Computed: x[" << MyPID*MyLength+i << "] = ";
00462 *out << std::setw(20) << x_computed[i] << "\t";
00463 *out << "Exact: x[" << MyPID*MyLength+i << "] = ";
00464 *out << std::setw(20) << x_star[i] << std::endl;
00465 }
00466 }
00467
00468
00469 double numerical_error = 0;
00470 double numerical_error_mag = 0;
00471 if (x_numerical_exact_ptr.get())
00472 {
00473 const Epetra_Vector& x_numerical_exact = *x_numerical_exact_ptr;
00474 for ( int i=0 ; i<MyLength ; ++i)
00475 {
00476 if (verbose)
00477 {
00478 *out << std::setprecision(15);
00479 *out << "Computed: x[" << MyPID*MyLength+i << "] = ";
00480 *out << std::setw(20) << x_computed[i] << "\t";
00481 *out << "Numerical Exact: x[" << MyPID*MyLength+i << "] = ";
00482 *out << std::setw(20) << x_numerical_exact[i] << std::endl;
00483 }
00484 const double thisError = x_numerical_exact[i]-x_computed[i];
00485 numerical_error += thisError*thisError;
00486 numerical_error_mag += x_numerical_exact[i]*x_numerical_exact[i];
00487 }
00488 numerical_error = sqrt(numerical_error)/sqrt(numerical_error_mag);
00489 result = Thyra::testMaxErr(
00490 "Exact numerical error",numerical_error
00491 ,"maxError",1.0e-10
00492 ,"maxWarning",1.0e-9
00493 ,&*out,""
00494 );
00495 if(!result) success = false;
00496 }
00497
00498
00499 double error = 0;
00500 double errorMag = 0;
00501 for (int i=0 ; i<MyLength ; ++i)
00502 {
00503 const double thisError = x_computed[i]-x_star[i];
00504 error += thisError*thisError;
00505 errorMag += x_star[i]*x_star[i];
00506 }
00507 error = sqrt(error)/sqrt(errorMag);
00508 result = Thyra::testMaxErr(
00509 "Exact DE solution error",error
00510 ,"maxError",maxError
00511 ,"maxWarning",10.0*maxError
00512 ,&*out,""
00513 );
00514 if(!result) success = false;
00515
00516 #ifdef HAVE_RYTHMOS_STRATIMIKOS
00517
00518 if(W_factory.get())
00519 lowsfCreator.writeParamsFile(*W_factory);
00520 #endif
00521
00522 }
00523 TEUCHOS_STANDARD_CATCH_STATEMENTS(true,*out,success)
00524
00525 return success ? 0 : 1;
00526
00527 }