bool setDefaultInitialConditionFromNominalValues( const Thyra::ModelEvaluator<Scalar>& model, const Ptr<StepperBase<Scalar> >& stepper ) { typedef ScalarTraits<Scalar> ST; typedef Thyra::ModelEvaluatorBase MEB; if (isInitialized(*stepper)) return false; // Already has an initial condition MEB::InArgs<Scalar> initCond = model.getNominalValues(); if (!is_null(initCond.get_x())) { // IC has x, we will assume that initCont.get_t() is the valid start time. // Therefore, we just need to check that x_dot is also set or we will // create a zero x_dot #ifdef RYTHMOS_DEBUG THYRA_ASSERT_VEC_SPACES( "setInitialConditionIfExists(...)", *model.get_x_space(), *initCond.get_x()->space() ); #endif if (initCond.supports(MEB::IN_ARG_x_dot)) { if (is_null(initCond.get_x_dot())) { const RCP<Thyra::VectorBase<Scalar> > x_dot = createMember(model.get_x_space()); assign(x_dot.ptr(), ST::zero()); } else { #ifdef RYTHMOS_DEBUG THYRA_ASSERT_VEC_SPACES( "setInitialConditionIfExists(...)", *model.get_x_space(), *initCond.get_x_dot()->space() ); #endif } } stepper->setInitialCondition(initCond); return true; } // The model has not nominal values for which to set the initial // conditions so wo don't do anything! The stepper will still have not return false; }
int main(int argc, char *argv[]) { using std::endl; typedef double Scalar; // typedef double ScalarMag; // unused typedef Teuchos::ScalarTraits<Scalar> ST; using Teuchos::describe; using Teuchos::Array; using Teuchos::RCP; using Teuchos::rcp; using Teuchos::outArg; using Teuchos::rcp_implicit_cast; using Teuchos::rcp_dynamic_cast; using Teuchos::as; using Teuchos::ParameterList; using Teuchos::CommandLineProcessor; typedef Teuchos::ParameterList::PrintOptions PLPrintOptions; typedef Thyra::ModelEvaluatorBase MEB; bool result, success = true; Teuchos::GlobalMPISession mpiSession(&argc,&argv); RCP<Epetra_Comm> epetra_comm; #ifdef HAVE_MPI epetra_comm = rcp( new Epetra_MpiComm(MPI_COMM_WORLD) ); #else epetra_comm = rcp( new Epetra_SerialComm ); #endif // HAVE_MPI RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream(); try { // // Read commandline options // CommandLineProcessor clp; clp.throwExceptions(false); clp.addOutputSetupOptions(true); std::string paramsFileName = ""; clp.setOption( "params-file", ¶msFileName, "File name for XML parameters" ); double t_final = 1e-3; clp.setOption( "final-time", &t_final, "Final integration time (initial time is 0.0)" ); int numTimeSteps = 10; clp.setOption( "num-time-steps", &numTimeSteps, "Number of (fixed) time steps. If <= 0.0, then variable time steps are taken" ); double maxStateError = 1e-14; clp.setOption( "max-state-error", &maxStateError, "Maximum relative error in the integrated state allowed" ); Teuchos::EVerbosityLevel verbLevel = Teuchos::VERB_DEFAULT; setVerbosityLevelOption( "verb-level", &verbLevel, "Top-level verbosity level. By default, this gets deincremented as you go deeper into numerical objects.", &clp ); Teuchos::EVerbosityLevel solnVerbLevel = Teuchos::VERB_DEFAULT; setVerbosityLevelOption( "soln-verb-level", &solnVerbLevel, "Solution verbosity level", &clp ); CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv); if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return; // *out << "\nA) Get the base parameter list ...\n"; // RCP<ParameterList> paramList = Teuchos::parameterList(); if (paramsFileName.length()) updateParametersFromXmlFile( paramsFileName, paramList.ptr() ); paramList->validateParameters(*getValidParameters()); const Scalar t_init = 0.0; const Rythmos::TimeRange<Scalar> fwdTimeRange(t_init, t_final); const Scalar delta_t = t_final / numTimeSteps; *out << "\ndelta_t = " << delta_t; // *out << "\nB) Create the Stratimikos linear solver factory ...\n"; // // This is the linear solve strategy that will be used to solve for the // linear system with the W. // Stratimikos::DefaultLinearSolverBuilder linearSolverBuilder; linearSolverBuilder.setParameterList(sublist(paramList,Stratimikos_name)); RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > W_factory = createLinearSolveStrategy(linearSolverBuilder); // *out << "\nC) Create and initalize the forward model ...\n"; // // C.1) Create the underlying EpetraExt::ModelEvaluator RCP<EpetraExt::DiagonalTransientModel> epetraStateModel = EpetraExt::diagonalTransientModel( epetra_comm, sublist(paramList,DiagonalTransientModel_name) ); *out <<"\nepetraStateModel valid options:\n"; epetraStateModel->getValidParameters()->print( *out, PLPrintOptions().indent(2).showTypes(true).showDoc(true) ); // C.2) Create the Thyra-wrapped ModelEvaluator RCP<Thyra::ModelEvaluator<double> > fwdStateModel = epetraModelEvaluator(epetraStateModel, W_factory); const RCP<const Thyra::VectorSpaceBase<Scalar> > x_space = fwdStateModel->get_x_space(); const RCP<const Thyra::VectorBase<Scalar> > gamma = Thyra::create_Vector(epetraStateModel->get_gamma(), x_space); *out << "\ngamma = " << describe(*gamma, solnVerbLevel); // *out << "\nD) Create the stepper and integrator for the forward problem ...\n"; // RCP<Rythmos::TimeStepNonlinearSolver<double> > fwdTimeStepSolver = Rythmos::timeStepNonlinearSolver<double>(); RCP<Rythmos::StepperBase<Scalar> > fwdStateStepper = Rythmos::backwardEulerStepper<double>(fwdStateModel, fwdTimeStepSolver); fwdStateStepper->setParameterList(sublist(paramList, RythmosStepper_name)); RCP<Rythmos::IntegratorBase<Scalar> > fwdStateIntegrator; { RCP<ParameterList> integrationControlPL = sublist(paramList, RythmosIntegrationControl_name); integrationControlPL->set( "Take Variable Steps", false ); integrationControlPL->set( "Fixed dt", as<double>(delta_t) ); RCP<Rythmos::IntegratorBase<Scalar> > defaultIntegrator = Rythmos::controlledDefaultIntegrator<Scalar>( Rythmos::simpleIntegrationControlStrategy<Scalar>(integrationControlPL) ); fwdStateIntegrator = defaultIntegrator; } fwdStateIntegrator->setParameterList(sublist(paramList, RythmosIntegrator_name)); // *out << "\nE) Solve the forward problem ...\n"; // const MEB::InArgs<Scalar> state_ic = fwdStateModel->getNominalValues(); *out << "\nstate_ic:\n" << describe(state_ic,solnVerbLevel); fwdStateStepper->setInitialCondition(state_ic); fwdStateIntegrator->setStepper(fwdStateStepper, t_final); Array<RCP<const Thyra::VectorBase<Scalar> > > x_final_array; fwdStateIntegrator->getFwdPoints( Teuchos::tuple<Scalar>(t_final), &x_final_array, NULL, NULL ); const RCP<const Thyra::VectorBase<Scalar> > x_final = x_final_array[0]; *out << "\nx_final:\n" << describe(*x_final, solnVerbLevel); // *out << "\nF) Check the solution to the forward problem ...\n"; // const RCP<Thyra::VectorBase<Scalar> > x_beta = createMember(x_space), x_final_be_exact = createMember(x_space); { Thyra::ConstDetachedVectorView<Scalar> d_gamma(*gamma); Thyra::ConstDetachedVectorView<Scalar> d_x_ic(*state_ic.get_x()); Thyra::DetachedVectorView<Scalar> d_x_beta(*x_beta); Thyra::DetachedVectorView<Scalar> d_x_final_be_exact(*x_final_be_exact); const int n = d_gamma.subDim(); for ( int i = 0; i < n; ++i ) { d_x_beta(i) = 1.0 / ( 1.0 - delta_t * d_gamma(i) ); d_x_final_be_exact(i) = integralPow(d_x_beta(i), numTimeSteps) * d_x_ic(i); } } *out << "\nx_final_be_exact:\n" << describe(*x_final_be_exact, solnVerbLevel); result = Thyra::testRelNormDiffErr<Scalar>( "x_final", *x_final, "x_final_be_exact", *x_final_be_exact, "maxStateError", maxStateError, "warningTol", 1.0, // Don't warn &*out, solnVerbLevel ); if (!result) success = false; // *out << "\nG) Create the Adjoint ME wrapper object ...\n"; // RCP<Thyra::ModelEvaluator<double> > adjModel = Rythmos::adjointModelEvaluator<double>( fwdStateModel, fwdTimeRange ); // *out << "\nH) Create a stepper and integrator for the adjoint ...\n"; // RCP<Thyra::LinearNonlinearSolver<double> > adjTimeStepSolver = Thyra::linearNonlinearSolver<double>(); RCP<Rythmos::StepperBase<Scalar> > adjStepper = Rythmos::backwardEulerStepper<double>(adjModel, adjTimeStepSolver); adjStepper->setParameterList(sublist(paramList, RythmosStepper_name)); RCP<Rythmos::IntegratorBase<Scalar> > adjIntegrator = fwdStateIntegrator->cloneIntegrator(); // *out << "\nI) Set up the initial condition for the adjoint at the final time ...\n"; // const RCP<const Thyra::VectorSpaceBase<Scalar> > f_space = fwdStateModel->get_f_space(); // lambda(t_final) = x_final const RCP<Thyra::VectorBase<Scalar> > lambda_ic = createMember(f_space); V_V( outArg(*lambda_ic), *x_final_be_exact ); // lambda_dot(t_final,i) = - gamma(i) * lambda(t_final,i) const RCP<Thyra::VectorBase<Scalar> > lambda_dot_ic = createMember(f_space); Thyra::V_S<Scalar>( outArg(*lambda_dot_ic), ST::zero() ); Thyra::ele_wise_prod<Scalar>( -ST::one(), *gamma, *lambda_ic, outArg(*lambda_dot_ic) ); MEB::InArgs<Scalar> adj_ic = adjModel->getNominalValues(); adj_ic.set_x(lambda_ic); adj_ic.set_x_dot(lambda_dot_ic); *out << "\nadj_ic:\n" << describe(adj_ic,solnVerbLevel); // *out << "\nJ) Integrate the adjoint backwards in time (using backward time) ...\n"; // adjStepper->setInitialCondition(adj_ic); adjIntegrator->setStepper(adjStepper, fwdTimeRange.length()); Array<RCP<const Thyra::VectorBase<Scalar> > > lambda_final_array; adjIntegrator->getFwdPoints( Teuchos::tuple<Scalar>(fwdTimeRange.length()), &lambda_final_array, NULL, NULL ); const RCP<const Thyra::VectorBase<Scalar> > lambda_final = lambda_final_array[0]; *out << "\nlambda_final:\n" << describe(*lambda_final, solnVerbLevel); // *out << "\nK) Test the final adjoint againt exact discrete solution ...\n"; // { const RCP<Thyra::VectorBase<Scalar> > lambda_final_be_exact = createMember(x_space); { Thyra::ConstDetachedVectorView<Scalar> d_gamma(*gamma); Thyra::ConstDetachedVectorView<Scalar> d_x_final(*x_final); Thyra::DetachedVectorView<Scalar> d_x_beta(*x_beta); Thyra::DetachedVectorView<Scalar> d_lambda_final_be_exact(*lambda_final_be_exact); const int n = d_gamma.subDim(); for ( int i = 0; i < n; ++i ) { d_lambda_final_be_exact(i) = integralPow(d_x_beta(i), numTimeSteps) * d_x_final(i); } } *out << "\nlambda_final_be_exact:\n" << describe(*lambda_final_be_exact, solnVerbLevel); result = Thyra::testRelNormDiffErr<Scalar>( "lambda_final", *lambda_final, "lambda_final_be_exact", *lambda_final_be_exact, "maxStateError", maxStateError, "warningTol", 1.0, // Don't warn &*out, solnVerbLevel ); if (!result) success = false; } // *out << "\nL) Test the reduced gradient from the adjoint against the discrete forward reduced gradient ...\n"; // { const RCP<const Thyra::VectorBase<Scalar> > d_d_hat_d_p_from_lambda = lambda_final; // See above const RCP<Thyra::VectorBase<Scalar> > d_d_hat_d_p_be_exact = createMember(x_space); { Thyra::ConstDetachedVectorView<Scalar> d_x_ic(*state_ic.get_x()); Thyra::DetachedVectorView<Scalar> d_x_beta(*x_beta); Thyra::DetachedVectorView<Scalar> d_d_d_hat_d_p_be_exact(*d_d_hat_d_p_be_exact); const int n = d_x_ic.subDim(); for ( int i = 0; i < n; ++i ) { d_d_d_hat_d_p_be_exact(i) = integralPow(d_x_beta(i), 2*numTimeSteps) * d_x_ic(i); } } *out << "\nd_d_hat_d_p_be_exact:\n" << describe(*d_d_hat_d_p_be_exact, solnVerbLevel); result = Thyra::testRelNormDiffErr<Scalar>( "d_d_hat_d_p_from_lambda", *d_d_hat_d_p_from_lambda, "d_d_hat_d_p_be_exact", *d_d_hat_d_p_be_exact, "maxStateError", maxStateError, "warningTol", 1.0, // Don't warn &*out, solnVerbLevel ); if (!result) success = false; } } TEUCHOS_STANDARD_CATCH_STATEMENTS(true,*out,success); if(success) *out << "\nEnd Result: TEST PASSED" << endl; else *out << "\nEnd Result: TEST FAILED" << endl; return ( success ? 0 : 1 ); } // end main() [Doxygen looks for this!]
int main(int argc, char *argv[]) { using std::endl; typedef double Scalar; typedef double ScalarMag; using Teuchos::describe; using Teuchos::RCP; using Teuchos::rcp; using Teuchos::rcp_implicit_cast; using Teuchos::rcp_dynamic_cast; using Teuchos::as; using Teuchos::ParameterList; using Teuchos::CommandLineProcessor; typedef Teuchos::ParameterList::PrintOptions PLPrintOptions; typedef Thyra::ModelEvaluatorBase MEB; typedef Thyra::DefaultMultiVectorProductVectorSpace<Scalar> DMVPVS; using Thyra::productVectorBase; bool result, success = true; Teuchos::GlobalMPISession mpiSession(&argc,&argv); RCP<Epetra_Comm> epetra_comm; #ifdef HAVE_MPI epetra_comm = rcp( new Epetra_MpiComm(MPI_COMM_WORLD) ); #else epetra_comm = rcp( new Epetra_SerialComm ); #endif // HAVE_MPI RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream(); try { // // Read commandline options // CommandLineProcessor clp; clp.throwExceptions(false); clp.addOutputSetupOptions(true); std::string paramsFileName = ""; clp.setOption( "params-file", ¶msFileName, "File name for XML parameters" ); std::string extraParamsString = ""; clp.setOption( "extra-params", &extraParamsString, "Extra XML parameters" ); std::string extraParamsFile = ""; clp.setOption( "extra-params-file", &extraParamsFile, "File containing extra parameters in XML format."); double maxStateError = 1e-6; clp.setOption( "max-state-error", &maxStateError, "The maximum allowed error in the integrated state in relation to the exact state solution" ); double finalTime = 1e-3; clp.setOption( "final-time", &finalTime, "Final integration time (initial time is 0.0)" ); int numTimeSteps = 10; clp.setOption( "num-time-steps", &numTimeSteps, "Number of (fixed) time steps. If <= 0.0, then variable time steps are taken" ); bool useBDF = false; clp.setOption( "use-BDF", "use-BE", &useBDF, "Use BDF or Backward Euler (BE)" ); bool useIRK = false; clp.setOption( "use-IRK", "use-other", &useIRK, "Use IRK or something" ); bool doFwdSensSolve = false; clp.setOption( "fwd-sens-solve", "state-solve", &doFwdSensSolve, "Do the forward sensitivity solve or just the state solve" ); bool doFwdSensErrorControl = false; clp.setOption( "fwd-sens-err-cntrl", "no-fwd-sens-err-cntrl", &doFwdSensErrorControl, "Do error control on the forward sensitivity solve or not" ); double maxRestateError = 0.0; clp.setOption( "max-restate-error", &maxRestateError, "The maximum allowed error between the state integrated by itself verses integrated along with DxDp" ); double maxSensError = 1e-4; clp.setOption( "max-sens-error", &maxSensError, "The maximum allowed error in the integrated sensitivity in relation to" " the finite-difference sensitivity" ); Teuchos::EVerbosityLevel verbLevel = Teuchos::VERB_DEFAULT; setVerbosityLevelOption( "verb-level", &verbLevel, "Top-level verbosity level. By default, this gets deincremented as you go deeper into numerical objects.", &clp ); bool testExactSensitivity = false; clp.setOption( "test-exact-sens", "no-test-exact-sens", &testExactSensitivity, "Test the exact sensitivity with finite differences or not." ); bool dumpFinalSolutions = false; clp.setOption( "dump-final-solutions", "no-dump-final-solutions", &dumpFinalSolutions, "Determine if the final solutions are dumpped or not." ); CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv); if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return; if ( Teuchos::VERB_DEFAULT == verbLevel ) verbLevel = Teuchos::VERB_LOW; const Teuchos::EVerbosityLevel solnVerbLevel = ( dumpFinalSolutions ? Teuchos::VERB_EXTREME : verbLevel ); // // Get the base parameter list that all other parameter lists will be read // from. // RCP<ParameterList> paramList = Teuchos::parameterList(); if (paramsFileName.length()) updateParametersFromXmlFile( paramsFileName, paramList.ptr() ); if(extraParamsFile.length()) Teuchos::updateParametersFromXmlFile( "./"+extraParamsFile, paramList.ptr() ); if (extraParamsString.length()) updateParametersFromXmlString( extraParamsString, paramList.ptr() ); if (testExactSensitivity) { paramList->sublist(DiagonalTransientModel_name).set("Exact Solution as Response",true); } paramList->validateParameters(*getValidParameters(),0); // Only validate top level lists! // // Create the Stratimikos linear solver factory. // // This is the linear solve strategy that will be used to solve for the // linear system with the W. // Stratimikos::DefaultLinearSolverBuilder linearSolverBuilder; linearSolverBuilder.setParameterList(sublist(paramList,Stratimikos_name)); RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > W_factory = createLinearSolveStrategy(linearSolverBuilder); // // Create the underlying EpetraExt::ModelEvaluator // RCP<EpetraExt::DiagonalTransientModel> epetraStateModel = EpetraExt::diagonalTransientModel( epetra_comm, sublist(paramList,DiagonalTransientModel_name) ); *out <<"\nepetraStateModel valid options:\n"; epetraStateModel->getValidParameters()->print( *out, PLPrintOptions().indent(2).showTypes(true).showDoc(true) ); // // Create the Thyra-wrapped ModelEvaluator // RCP<Thyra::ModelEvaluator<double> > stateModel = epetraModelEvaluator(epetraStateModel,W_factory); *out << "\nParameter names = " << *stateModel->get_p_names(0) << "\n"; // // Create the Rythmos stateStepper // RCP<Rythmos::TimeStepNonlinearSolver<double> > nonlinearSolver = Rythmos::timeStepNonlinearSolver<double>(); RCP<ParameterList> nonlinearSolverPL = sublist(paramList,TimeStepNonlinearSolver_name); nonlinearSolverPL->get("Default Tol",1e-3*maxStateError); // Set default if not set nonlinearSolver->setParameterList(nonlinearSolverPL); RCP<Rythmos::StepperBase<Scalar> > stateStepper; if (useBDF) { stateStepper = rcp( new Rythmos::ImplicitBDFStepper<double>( stateModel, nonlinearSolver ) ); } else if (useIRK) { // We need a separate LOWSFB object for the IRK stepper RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > irk_W_factory = createLinearSolveStrategy(linearSolverBuilder); RCP<Rythmos::RKButcherTableauBase<double> > irkbt = Rythmos::createRKBT<double>("Backward Euler"); stateStepper = Rythmos::implicitRKStepper<double>( stateModel, nonlinearSolver, irk_W_factory, irkbt ); } else { stateStepper = rcp( new Rythmos::BackwardEulerStepper<double>( stateModel, nonlinearSolver ) ); } *out <<"\nstateStepper:\n" << describe(*stateStepper,verbLevel); *out <<"\nstateStepper valid options:\n"; stateStepper->getValidParameters()->print( *out, PLPrintOptions().indent(2).showTypes(true).showDoc(true) ); stateStepper->setParameterList(sublist(paramList,RythmosStepper_name)); // // Setup finite difference objects that will be used for tests // Thyra::DirectionalFiniteDiffCalculator<Scalar> fdCalc; fdCalc.setParameterList(sublist(paramList,FdCalc_name)); fdCalc.setOStream(out); fdCalc.setVerbLevel(verbLevel); // // Use a StepperAsModelEvaluator to integrate the state // const MEB::InArgs<Scalar> state_ic = stateModel->getNominalValues(); *out << "\nstate_ic:\n" << describe(state_ic,verbLevel); RCP<Rythmos::IntegratorBase<Scalar> > integrator; { RCP<ParameterList> integratorPL = sublist(paramList,RythmosIntegrator_name); integratorPL->set( "Take Variable Steps", as<bool>(numTimeSteps < 0) ); integratorPL->set( "Fixed dt", as<double>((finalTime - state_ic.get_t())/numTimeSteps) ); RCP<Rythmos::IntegratorBase<Scalar> > defaultIntegrator = Rythmos::controlledDefaultIntegrator<Scalar>( Rythmos::simpleIntegrationControlStrategy<Scalar>(integratorPL) ); integrator = defaultIntegrator; } RCP<Rythmos::StepperAsModelEvaluator<Scalar> > stateIntegratorAsModel = Rythmos::stepperAsModelEvaluator( stateStepper, integrator, state_ic ); stateIntegratorAsModel->setVerbLevel(verbLevel); *out << "\nUse the StepperAsModelEvaluator to integrate state x(p,finalTime) ... \n"; RCP<Thyra::VectorBase<Scalar> > x_final; { Teuchos::OSTab tab(out); x_final = createMember(stateIntegratorAsModel->get_g_space(0)); eval_g( *stateIntegratorAsModel, 0, *state_ic.get_p(0), finalTime, 0, &*x_final ); *out << "\nx_final = x(p,finalTime) evaluated using stateIntegratorAsModel:\n" << describe(*x_final,solnVerbLevel); } // // Test the integrated state against the exact analytical state solution // RCP<const Thyra::VectorBase<Scalar> > exact_x_final = create_Vector( epetraStateModel->getExactSolution(finalTime), stateModel->get_x_space() ); result = Thyra::testRelNormDiffErr( "exact_x_final", *exact_x_final, "x_final", *x_final, "maxStateError", maxStateError, "warningTol", 1.0, // Don't warn &*out, solnVerbLevel ); if (!result) success = false; // // Solve and test the forward sensitivity computation // if (doFwdSensSolve) { // // Create the forward sensitivity stepper // RCP<Rythmos::ForwardSensitivityStepper<Scalar> > stateAndSensStepper = Rythmos::forwardSensitivityStepper<Scalar>(); if (doFwdSensErrorControl) { stateAndSensStepper->initializeDecoupledSteppers( stateModel, 0, stateModel->getNominalValues(), stateStepper, nonlinearSolver, integrator->cloneIntegrator(), finalTime ); } else { stateAndSensStepper->initializeSyncedSteppers( stateModel, 0, stateModel->getNominalValues(), stateStepper, nonlinearSolver ); // The above call will result in stateStepper and nonlinearSolver being // cloned. This helps to ensure consistency between the state and // sensitivity computations! } // // Set the initial condition for the state and forward sensitivities // RCP<Thyra::VectorBase<Scalar> > s_bar_init = createMember(stateAndSensStepper->getFwdSensModel()->get_x_space()); assign( s_bar_init.ptr(), 0.0 ); RCP<Thyra::VectorBase<Scalar> > s_bar_dot_init = createMember(stateAndSensStepper->getFwdSensModel()->get_x_space()); assign( s_bar_dot_init.ptr(), 0.0 ); // Above, I believe that these are the correct initial conditions for // s_bar and s_bar_dot given how the EpetraExt::DiagonalTransientModel // is currently implemented! RCP<const Rythmos::StateAndForwardSensitivityModelEvaluator<Scalar> > stateAndSensModel = stateAndSensStepper->getStateAndFwdSensModel(); MEB::InArgs<Scalar> state_and_sens_ic = stateAndSensStepper->getModel()->createInArgs(); // Copy time, parameters etc. state_and_sens_ic.setArgs(state_ic); // Set initial condition for x_bar = [ x; s_bar ] state_and_sens_ic.set_x( stateAndSensModel->create_x_bar_vec(state_ic.get_x(),s_bar_init) ); // Set initial condition for x_bar_dot = [ x_dot; s_bar_dot ] state_and_sens_ic.set_x_dot( stateAndSensModel->create_x_bar_vec(state_ic.get_x_dot(),s_bar_dot_init) ); *out << "\nstate_and_sens_ic:\n" << describe(state_and_sens_ic,verbLevel); stateAndSensStepper->setInitialCondition(state_and_sens_ic); // // Use a StepperAsModelEvaluator to integrate the state+sens // RCP<Rythmos::StepperAsModelEvaluator<Scalar> > stateAndSensIntegratorAsModel = Rythmos::stepperAsModelEvaluator( rcp_implicit_cast<Rythmos::StepperBase<Scalar> >(stateAndSensStepper), integrator, state_and_sens_ic ); stateAndSensIntegratorAsModel->setVerbLevel(verbLevel); *out << "\nUse the StepperAsModelEvaluator to integrate state + sens x_bar(p,finalTime) ... \n"; RCP<Thyra::VectorBase<Scalar> > x_bar_final; { Teuchos::OSTab tab(out); x_bar_final = createMember(stateAndSensIntegratorAsModel->get_g_space(0)); eval_g( *stateAndSensIntegratorAsModel, 0, *state_ic.get_p(0), finalTime, 0, &*x_bar_final ); *out << "\nx_bar_final = x_bar(p,finalTime) evaluated using stateAndSensIntegratorAsModel:\n" << describe(*x_bar_final,solnVerbLevel); } // // Test that the state computed above is same as computed initially! // *out << "\nChecking that x(p,finalTime) computed as part of x_bar above is the same ...\n"; { Teuchos::OSTab tab(out); RCP<const Thyra::VectorBase<Scalar> > x_in_x_bar_final = productVectorBase<Scalar>(x_bar_final)->getVectorBlock(0); result = Thyra::testRelNormDiffErr<Scalar>( "x_final", *x_final, "x_in_x_bar_final", *x_in_x_bar_final, "maxRestateError", maxRestateError, "warningTol", 1.0, // Don't warn &*out, solnVerbLevel ); if (!result) success = false; } // // Compute DxDp using finite differences // *out << "\nApproximating DxDp(p,t) using directional finite differences of integrator for x(p,t) ...\n"; RCP<Thyra::MultiVectorBase<Scalar> > DxDp_fd_final; { Teuchos::OSTab tab(out); MEB::InArgs<Scalar> fdBasePoint = stateIntegratorAsModel->createInArgs(); fdBasePoint.set_t(finalTime); fdBasePoint.set_p(0,stateModel->getNominalValues().get_p(0)); DxDp_fd_final = createMembers( stateIntegratorAsModel->get_g_space(0), stateIntegratorAsModel->get_p_space(0)->dim() ); typedef Thyra::DirectionalFiniteDiffCalculatorTypes::SelectedDerivatives SelectedDerivatives; MEB::OutArgs<Scalar> fdOutArgs = fdCalc.createOutArgs( *stateIntegratorAsModel, SelectedDerivatives().supports(MEB::OUT_ARG_DgDp,0,0) ); fdOutArgs.set_DgDp(0,0,DxDp_fd_final); // Silence the model evaluators that are called. The fdCal object // will show all of the inputs and outputs for each call. stateStepper->setVerbLevel(Teuchos::VERB_NONE); stateIntegratorAsModel->setVerbLevel(Teuchos::VERB_NONE); fdCalc.calcDerivatives( *stateIntegratorAsModel, fdBasePoint, stateIntegratorAsModel->createOutArgs(), // Don't bother with function value fdOutArgs ); *out << "\nFinite difference DxDp_fd_final = DxDp(p,finalTime): " << describe(*DxDp_fd_final,solnVerbLevel); } // // Test that the integrated sens and the F.D. sens are similar // *out << "\nChecking that integrated DxDp(p,finalTime) and finite-diff DxDp(p,finalTime) are similar ...\n"; { Teuchos::OSTab tab(out); RCP<const Thyra::VectorBase<Scalar> > DxDp_vec_final = Thyra::productVectorBase<Scalar>(x_bar_final)->getVectorBlock(1); RCP<const Thyra::VectorBase<Scalar> > DxDp_fd_vec_final = Thyra::multiVectorProductVector( rcp_dynamic_cast<const Thyra::DefaultMultiVectorProductVectorSpace<Scalar> >( DxDp_vec_final->range() ), DxDp_fd_final ); result = Thyra::testRelNormDiffErr( "DxDp_vec_final", *DxDp_vec_final, "DxDp_fd_vec_final", *DxDp_fd_vec_final, "maxSensError", maxSensError, "warningTol", 1.0, // Don't warn &*out, solnVerbLevel ); if (!result) success = false; } } } TEUCHOS_STANDARD_CATCH_STATEMENTS(true,*out,success); if(success) *out << "\nEnd Result: TEST PASSED" << endl; else *out << "\nEnd Result: TEST FAILED" << endl; return ( success ? 0 : 1 ); } // end main() [Doxygen looks for this!]
double computeForwardSensitivityErrorStackedStepperSinCosFE( int numTimeSteps, Array<RCP<const VectorBase<double> > >& computedSol, Array<RCP<const VectorBase<double> > >& exactSol ) { using Teuchos::rcp_dynamic_cast; typedef Thyra::ModelEvaluatorBase MEB; // Forward ODE Model: RCP<SinCosModel> fwdModel = sinCosModel(); { RCP<ParameterList> pl = Teuchos::parameterList(); pl->set("Accept model parameters",true); pl->set("Implicit model formulation",false); pl->set("Provide nominal values",true); double b = 5.0; //double phi = 0.0; double a = 2.0; double f = 3.0; double L = 4.0; double x0 = a; double x1 = b*f/L; pl->set("Coeff a", a); pl->set("Coeff f", f); pl->set("Coeff L", L); pl->set("IC x_0", x0); pl->set("IC x_1", x1); fwdModel->setParameterList(pl); } RCP<StepperBase<double> > fwdStepper; RCP<StepperBase<double> > fsStepper; { const RCP<StepperBuilder<double> > builder = stepperBuilder<double>(); RCP<ParameterList> stepperPL = Teuchos::parameterList(); stepperPL->set("Stepper Type","Forward Euler"); builder->setParameterList(stepperPL); fwdStepper = builder->create(); fsStepper = builder->create(); } // Forward Sensitivity Model: RCP<ForwardSensitivityExplicitModelEvaluator<double> > fsModel = forwardSensitivityExplicitModelEvaluator<double>(); int p_index = 0; fsModel->initializeStructure(fwdModel,p_index); const MEB::InArgs<double> fwdModel_ic = fwdModel->getNominalValues(); fwdStepper->setModel(fwdModel); fwdStepper->setInitialCondition(fwdModel_ic); fsModel->initializePointState(Teuchos::inOutArg(*fwdStepper),false); MEB::InArgs<double> fsModel_ic = fsModel->getNominalValues(); { // Set up sensitivity initial conditions so they match the initial // conditions in getExactSensSolution RCP<Thyra::VectorBase<double> > s_bar_init = createMember(fsModel->get_x_space()); RCP<Thyra::DefaultMultiVectorProductVector<double> > s_bar_mv = rcp_dynamic_cast<Thyra::DefaultMultiVectorProductVector<double> >( s_bar_init, true ); int np = 3; // SinCos problem number of elements in parameter vector. for (int j=0 ; j < np ; ++j) { MEB::InArgs<double> sens_ic = fwdModel->getExactSensSolution(j,0.0); V_V(outArg(*(s_bar_mv->getNonconstVectorBlock(j))), *(sens_ic.get_x()) ); } fsModel_ic.set_x(s_bar_init); } fsStepper->setModel(fsModel); fsStepper->setInitialCondition(fsModel_ic); RCP<StackedStepper<double> > sStepper = stackedStepper<double>(); sStepper->addStepper(fwdStepper); sStepper->addStepper(fsStepper); { // Set up Forward Sensitivities step strategy RCP<ForwardSensitivityStackedStepperStepStrategy<double> > stepStrategy = forwardSensitivityStackedStepperStepStrategy<double>(); sStepper->setStackedStepperStepControlStrategy(stepStrategy); } double finalTime = 1.0e-4; double dt = finalTime/numTimeSteps; // Assume t_0 = 0.0; for (int i=0 ; i < numTimeSteps ; ++i ) { double dt_taken = sStepper->takeStep(dt,STEP_TYPE_FIXED); TEUCHOS_ASSERT( dt_taken == dt ); } RCP<VectorBase<double> > x_bar_final = Thyra::createMember(sStepper->get_x_space()); { Array<double> t_vec; Array<RCP<const VectorBase<double> > > x_vec; t_vec.push_back(finalTime); sStepper->getPoints( t_vec, &x_vec, NULL, NULL ); V_V(Teuchos::outArg(*x_bar_final),*x_vec[0]); } // Now we check that the sensitivities are correct RCP<const Thyra::VectorBase<double> > DxDp_vec_final = Thyra::productVectorBase<double>(x_bar_final)->getVectorBlock(1); RCP<const Thyra::DefaultMultiVectorProductVector<double> > DxDp_mv_final = rcp_dynamic_cast<const Thyra::DefaultMultiVectorProductVector<double> >( DxDp_vec_final, true ); RCP<const Thyra::VectorBase<double> > DxDp_s0_final = DxDp_mv_final->getVectorBlock(0); RCP<const Thyra::VectorBase<double> > DxDp_s1_final = DxDp_mv_final->getVectorBlock(1); RCP<const Thyra::VectorBase<double> > DxDp_s2_final = DxDp_mv_final->getVectorBlock(2); computedSol.clear(); computedSol.push_back(DxDp_s0_final); computedSol.push_back(DxDp_s1_final); computedSol.push_back(DxDp_s2_final); MEB::InArgs<double> exactSensSolution; exactSensSolution = fwdModel->getExactSensSolution(0,finalTime); RCP<const Thyra::VectorBase<double> > ds0dp = exactSensSolution.get_x(); exactSensSolution = fwdModel->getExactSensSolution(1,finalTime); RCP<const Thyra::VectorBase<double> > ds1dp = exactSensSolution.get_x(); exactSensSolution = fwdModel->getExactSensSolution(2,finalTime); RCP<const Thyra::VectorBase<double> > ds2dp = exactSensSolution.get_x(); exactSol.clear(); exactSol.push_back(ds0dp); exactSol.push_back(ds1dp); exactSol.push_back(ds2dp); return dt; }