diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitAppAction.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitAppAction.hpp new file mode 100644 index 000000000000..3f8b8be0ca3a --- /dev/null +++ b/packages/tempus/src/Tempus_StepperOperatorSplitAppAction.hpp @@ -0,0 +1,64 @@ +// @HEADER +// **************************************************************************** +// Tempus: Copyright (2017) Sandia Corporation +// +// Distributed under BSD 3-clause license (See accompanying file Copyright.txt) +// **************************************************************************** +// @HEADER + +#ifndef Tempus_StepperOperatorSplitAppAction_hpp +#define Tempus_StepperOperatorSplitAppAction_hpp + +#include "Tempus_config.hpp" +#include "Tempus_SolutionHistory.hpp" +#include "Tempus_StepperOperatorSplit.hpp" + +namespace Tempus { + +// Forward Declaration for recursive includes (this Observer <--> Stepper) +template class StepperOperatorSplit; + +/** \brief StepperOperatorSplitAppAction class for StepperOperatorSplit. + * + * This is a means for application developers to perform tasks + * during the time steps, e.g., + * - Compute specific quantities + * - Output information + * - "Massage" the working solution state + * - ... + * + * Design Considerations + * - StepperOperatorSplitAppAction is not stateless! Developers may touch the + * solution state! Developers need to be careful not to break the + * restart (checkpoint) capability. + */ +template +class StepperOperatorSplitAppAction +{ +public: + + enum ACTION_LOCATION { + BEGIN_STEP, ///< At the beginning of the step. + BEFORE_STEPPER, ///< Before a stepper evaluation. + AFTER_STEPPER, ///< After a stepper evaluation. + END_STEP ///< At the end of the step. + }; + + /// Constructor + StepperOperatorSplitAppAction(){} + + /// Destructor + virtual ~StepperOperatorSplitAppAction(){} + + /// Execute application action for OperatorSplit Stepper. + virtual void execute( + Teuchos::RCP > sh, + Teuchos::RCP > stepper, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) = 0; +}; +} // namespace Tempus +#endif // Tempus_StepperOperatorSplitAppAction_hpp + + + + diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitAppActionComposite.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitAppActionComposite.hpp new file mode 100644 index 000000000000..d96bc06f01be --- /dev/null +++ b/packages/tempus/src/Tempus_StepperOperatorSplitAppActionComposite.hpp @@ -0,0 +1,65 @@ +// @HEADER +// **************************************************************************** +// Tempus: Copyright (2017) Sandia Corporation +// +// Distributed under BSD 3-clause license (See accompanying file Copyright.txt) +// **************************************************************************** +// @HEADER + +#ifndef Tempus_StepperOperatorSplitAppActionComposite_hpp +#define Tempus_StepperOperatorSplitAppActionComposite_hpp + +#include "Tempus_StepperOperatorSplitAppAction.hpp" +#include "Tempus_TimeStepControl.hpp" +#include + +namespace Tempus { + +/** \brief This composite AppAction loops over added AppActions. + * + * Inidividual AppActions are executed in the order in which they + * were added. + */ +template +class StepperOperatorSplitAppActionComposite + : virtual public Tempus::StepperOperatorSplitAppAction +{ +public: + + /// Default constructor + StepperOperatorSplitAppActionComposite(); + + /// Destructor + virtual ~StepperOperatorSplitAppActionComposite(); + + /// Execute application action for OperatorSplit Stepper. + virtual void execute( + Teuchos::RCP > sh, + Teuchos::RCP > stepper, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { + for(auto& a : appActions_) + a->execute(sh, stepper, actLoc); + } + + // Add AppAction to the AppAction vector. + void addOperatorSplitAppAction(Teuchos::RCP > appAction); + { + appActions_.push_back(appAction); + } + + // Clear the AppAction vector. + void clearOperatorSplitAppActions(); + { appActions_.clear();} + + // Return the size of the AppAction vector. + std::size_t getSize() const { return appActions_.size(); } + +private: + + std::vector > > appActions_; + +}; + +} // namespace Tempus +#endif // Tempus_StepperOperatorSplitAppActionComposite_hpp diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitModifierBase.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitModifierBase.hpp new file mode 100644 index 000000000000..5f62f66ed2f8 --- /dev/null +++ b/packages/tempus/src/Tempus_StepperOperatorSplitModifierBase.hpp @@ -0,0 +1,65 @@ +// @HEADER +// **************************************************************************** +// Tempus: Copyright (2017) Sandia Corporation +// +// Distributed under BSD 3-clause license (See accompanying file Copyright.txt) +// **************************************************************************** +// @HEADER + +#ifndef Tempus_StepperOperatorSplitModifierBase_hpp +#define Tempus_StepperOperatorSplitModifierBase_hpp + +#include "Tempus_SolutionHistory.hpp" +#include "Tempus_config.hpp" +#include "Tempus_StepperOperatorSplitAppAction.hpp" + +namespace Tempus { + + /** \brief Base modifier for OperatorSplit. + * + * This class provides a means to modify values (e.g., solution variables + * through SolutionHistory, and stepper member data through the Stepper), + * and can be very powerful and easy to make changes to the stepper and + * the solution. + * + * Users deriving from this class can access a lot of data, and it is + * expected that those users know what changes are allowable without + * affecting the Stepper correctness, performance, accuracy and stability. + * Thus the user should be careful when accessing data through classes + * derived from the default modifier (i.e., USER BEWARE!!). + * + */ + template +class StepperOperatorSplitModifierBase + : virtual public Tempus::StepperOperatorSplitAppAction + { + private: + /* \brief Adaptor execute function + * + * This is an adaptor function to bridge between the AppAction + * interface and the Modifier interface. It is meant to be private + * and non-virtual as deriving from this class should only need to + * implement the modify function. + * + * For the Modifier interface, this adaptor is a "simple pass through". + */ + void execute( + Teuchos::RCP > sh, + Teuchos::RCP > stepper, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { this->modify(sh, stepper, actLoc); } + public: + /// Modify OperatorSplit Stepper. + virtual void modify( + Teuchos::RCP > /* sh */, + Teuchos::RCP > /* stepper */, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) = 0; + + }; + +} // namespace Tempus +#endif // Tempus_StepperOperatorModifierBase_hpp + + + + diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitModifierDefault.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitModifierDefault.hpp new file mode 100644 index 000000000000..a7b88aa620e8 --- /dev/null +++ b/packages/tempus/src/Tempus_StepperOperatorSplitModifierDefault.hpp @@ -0,0 +1,61 @@ +// @HEADER +// **************************************************************************** +// Tempus: Copyright (2017) Sandia Corporation +// +// Distributed under BSD 3-clause license (See accompanying file Copyright.txt) +// **************************************************************************** +// @HEADER + +#ifndef Tempus_StepperOperatorSplitModifierDefault_hpp +#define Tempus_StepperOperatorSplitModifierDefault_hpp + +#include "Tempus_config.hpp" +#include "Tempus_SolutionHistory.hpp" +#include "Tempus_StepperOperatorSplitModifierBase.hpp" + + +namespace Tempus { + +/** \brief Default modifier for StepperOperatorSplit. + * + * The default modifier provides no-op functionality for the modifier. + * See StepperOperatorSplitModifierBase for details on the algorithm. + */ +template +class StepperOperatorSplitModifierDefault + : virtual public Tempus::StepperOperatorSplitModifierBase +{ +public: + + /// Constructor + StepperOperatorSplitModifierDefault(){} + + /// Destructor + virtual ~StepperOperatorSplitModifierDefault(){} + + /// Modify OperatorSplit Stepper. + virtual void modify( + Teuchos::RCP > /* sh */, + Teuchos::RCP > /* stepper */, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { + switch(actLoc) { + case StepperOperatorSplitAppAction::BEGIN_STEP: + case StepperOperatorSplitAppAction::BEFORE_STEPPER: + case StepperOperatorSplitAppAction::AFTER_STEPPER: + case StepperOperatorSplitAppAction::END_STEP: + { + // No-op. + break; + } + default: + TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, + "Error - unknown action location.\n"); + } + } + +}; + +} // namespace Tempus + +#endif // Tempus_StepperOperatorSplitModifierDefault_hpp diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitModifierXBase.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitModifierXBase.hpp new file mode 100644 index 000000000000..3260aa5e49a5 --- /dev/null +++ b/packages/tempus/src/Tempus_StepperOperatorSplitModifierXBase.hpp @@ -0,0 +1,118 @@ +// @HEADER +// **************************************************************************** +// Tempus: Copyright (2017) Sandia Corporation +// +// Distributed under BSD 3-clause license (See accompanying file Copyright.txt) +// **************************************************************************** +// @HEADER + +#ifndef Tempus_StepperOperatorSplitModifierXBase_hpp +#define Tempus_StepperOperatorSplitModifierXBase_hpp + +#include "Tempus_config.hpp" +#include "Tempus_SolutionHistory.hpp" +#include "Tempus_StepperOperatorSplitAppAction.hpp" + + +namespace Tempus { + +/** \brief Base ModifierX for StepperOperatorSplit. + * + * This class provides a means to modify just the solution values + * (i.e., \f$x\f$ and \f$dot{x}\f$), and nothing else, but time and + * timestep are also provided. + * + * Users deriving from this class can access and change the solution + * during the timestep (e.g., limiting the solution for monoticity). + * It is expected that the user knows what changes are allowable without + * affecting the Stepper correctness, performance, accuracy and stability + * (i.e., USER BEWARE!!). + * + */ + +template +class StepperOperatorSplitModifierXBase + : virtual public Tempus::StepperOperatorSplitAppAction +{ +private: + + /* \brief Adaptor execute function + * + * This is an adaptor function to bridge between the AppAction + * interface and the ModifierX interface. It is meant to be private + * and non-virtual as deriving from this class should only need to + * implement the modify function. + * + * For the ModifierX interface, this adaptor maps the + * StepperOperatorSplitAppAction::ACTION_LOCATION to the + * StepperOperatorSplitModifierX::MODIFIERX_TYPE, and only pass the solution + * (\f$x\f$ and/or \f$\dot{x}\f$ and other parameters to the modify + * function. + */ + void execute( + Teuchos::RCP > sh, + Teuchos::RCP > stepper, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { + using Teuchos::RCP; + + MODIFIER_TYPE modType = X_BEGIN_STEP; + RCP > workingState = sh->getWorkingState(); + const Scalar time = workingState->getTime(); + const Scalar dt = workingState->getTimeStep(); + RCP > x; + + switch(actLoc) { + case StepperOperatorSplitAppAction::BEGIN_STEP: + { + modType = X_BEGIN_STEP; + x = workingState->getX(); + break; + } + case StepperOperatorSplitAppAction::BEFORE_STEPPER: + { + modType = X_BEFORE_STEPPER; + x = workingState->getX(); + break; + } + case StepperOperatorSplitAppAction::AFTER_STEPPER: + { + modType = X_AFTER_STEPPER; + x = workingState->getX(); + break; + } + case StepperOperatorSplitAppAction::END_STEP: + { + modType = XDOT_END_STEP; + x = stepper->getStepperXDot(workingState); + break; + } + default: + TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, + "Error - unknown action location.\n"); + } + + this->modify(x, time, dt, modType); + } + +public: + + /// Indicates the location of application action (see algorithm). + enum MODIFIER_TYPE { + X_BEGIN_STEP, ///< Modify \f$x\f$ at the beginning of the step. + X_BEFORE_STEPPER, ///< Modify \f$x\f$ before the implicit solve. + X_AFTER_STEPPER, + XDOT_END_STEP ///< Modify \f$\dot{x}\f$ at the end of the step. + }; + + /// Modify solution based on the MODIFIER_TYPE. + virtual void modify( + Teuchos::RCP > /* x */, + const Scalar /* time */, const Scalar /* dt */, + const MODIFIER_TYPE modType) = 0; + +}; + +} // namespace Tempus + +#endif // Tempus_StepperOperatorSplitModifierXBase_hpp diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitObserver.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitObserver.hpp index 045ddf7bccbd..f4181be1dce7 100644 --- a/packages/tempus/src/Tempus_StepperOperatorSplitObserver.hpp +++ b/packages/tempus/src/Tempus_StepperOperatorSplitObserver.hpp @@ -10,7 +10,7 @@ #define Tempus_StepperOperatorSplitObserver_hpp #include "Tempus_SolutionHistory.hpp" - +#include "Tempus_StepperObserver.hpp" namespace Tempus { diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitObserverBase.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitObserverBase.hpp new file mode 100644 index 000000000000..d93901e497fe --- /dev/null +++ b/packages/tempus/src/Tempus_StepperOperatorSplitObserverBase.hpp @@ -0,0 +1,65 @@ +// @HEADER +// **************************************************************************** +// Tempus: Copyright (2017) Sandia Corporation +// +// Distributed under BSD 3-clause license (See accompanying file Copyright.txt) +// **************************************************************************** +// @HEADER + +#ifndef Tempus_StepperOperatorSplitObserverBase_hpp +#define Tempus_StepperOperatorSplitObserverBase_hpp + +#include "Tempus_config.hpp" +#include "Tempus_SolutionHistory.hpp" +#include "Tempus_StepperOperatorSplitAppAction.hpp" + + +namespace Tempus { + +/** \brief Base observer for StepperOperatorSplit. + * + * This class provides a means to observe values (e.g., solution variables + * through SolutionHistory, and stepper member data through the Stepper), + * and cannot modify them. + * + * Users deriving from this class can observer a lot of data, and it is + * expected that users will NOT modify any of that data. If the user + * wishes to modify the solution and/or stepper data during the + * Stepper::takeStep, they should use the Modifier class (with care!). + * + */ +template +class StepperOperatorSplitObserverBase + : virtual public Tempus::StepperOperatorSplitAppAction +{ +private: + + /* \brief Adaptor execute function + * + * This is an adaptor function to bridge between the AppAction + * interface and this derived interface. It is meant to be private + * and non-virtual as deriving from this class should only need to + * implement the observe function. + * + * For the Observer interface, this adaptor simply "applies" constantness + * to the arguments. + */ + void execute( + Teuchos::RCP > sh, + Teuchos::RCP > stepper, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { this->observe(sh, stepper, actLoc); } + +public: + + /// Observe OperatorSplit Stepper. + virtual void observe( + Teuchos::RCP > /* sh */, + Teuchos::RCP > /* stepper */, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) = 0; + +}; + +} // namespace Tempus + +#endif // Tempus_StepperOperatorSplitObserverBase_hpp diff --git a/packages/tempus/src/Tempus_StepperOperatorSplitObserverDefault.hpp b/packages/tempus/src/Tempus_StepperOperatorSplitObserverDefault.hpp new file mode 100644 index 000000000000..d25367b348d5 --- /dev/null +++ b/packages/tempus/src/Tempus_StepperOperatorSplitObserverDefault.hpp @@ -0,0 +1,60 @@ +// @HEADER +// **************************************************************************** +// Tempus: Copyright (2017) Sandia Corporation +// +// Distributed under BSD 3-clause license (See accompanying file Copyright.txt) +// **************************************************************************** +// @HEADER + +#ifndef Tempus_StepperOperatorSplitObserverDefault_hpp +#define Tempus_StepperOperatorSplitObserverDefault_hpp + +#include "Tempus_config.hpp" +#include "Tempus_SolutionHistory.hpp" +#include "Tempus_StepperOperatorSplitObserverBase.hpp" + +namespace Tempus { + +/** \brief Default observer for StepperOperatorSplit. + * + * The default observer provides no-op functionality for the observer. + * See StepperOperatorSplitObserverBase for details on the algorithm. + */ +template +class StepperOperatorSplitObserverDefault + : virtual public Tempus::StepperOperatorSplitObserverBase +{ +public: + + /// Constructor + StepperOperatorSplitObserverDefault(){} + + /// Destructor + virtual ~StepperOperatorSplitObserverDefault(){} + + /// Observe OperatorSplit Stepper at end of takeStep. + virtual void observe( + Teuchos::RCP > /* sh */, + Teuchos::RCP > /* stepper */, + const typename StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { + switch(actLoc) { + case StepperOperatorSplitAppAction::BEGIN_STEP: + case StepperOperatorSplitAppAction::BEFORE_STEPPER: + case StepperOperatorSplitAppAction::AFTER_STEPPER: + case StepperOperatorSplitAppAction::END_STEP: + { + // No-op. + break; + } + default: + TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, + "Error - unknown action location.\n"); + } + } + +}; + +} // namespace Tempus + +#endif // Tempus_StepperOperatorSplitObserverDefault_hpp diff --git a/packages/tempus/src/Tempus_StepperOperatorSplit_decl.hpp b/packages/tempus/src/Tempus_StepperOperatorSplit_decl.hpp index c27bb677428f..74548ee89c4b 100644 --- a/packages/tempus/src/Tempus_StepperOperatorSplit_decl.hpp +++ b/packages/tempus/src/Tempus_StepperOperatorSplit_decl.hpp @@ -11,8 +11,10 @@ #include "Tempus_config.hpp" #include "Tempus_Stepper.hpp" -#include "Tempus_StepperOperatorSplitObserver.hpp" - +#ifndef TEMPUS_HIDE_DEPRECATED_CODE + #include "Tempus_StepperOperatorSplitObserver.hpp" +#endif +#include "Tempus_StepperOperatorSplitAppAction.hpp" namespace Tempus { @@ -47,6 +49,7 @@ class StepperOperatorSplit : virtual public Tempus::Stepper */ StepperOperatorSplit(); +#ifndef TEMPUS_HIDE_DEPRECATED_CODE /// Constructor StepperOperatorSplit( std::vector > > appModels, @@ -58,6 +61,19 @@ class StepperOperatorSplit : virtual public Tempus::Stepper int order, int orderMin, int orderMax); +#endif + + /// Constructor + StepperOperatorSplit( + std::vector > > appModels, + std::vector > > subStepperList, + bool useFSAL, + std::string ICConsistency, + bool ICConsistencyCheck, + int order, + int orderMin, + int orderMax, + const Teuchos::RCP >& stepperOSAppAction); /// \name Basic stepper methods //@{ @@ -73,11 +89,18 @@ class StepperOperatorSplit : virtual public Tempus::Stepper virtual Teuchos::RCP > getSolver() const { return Teuchos::null; } +#ifndef TEMPUS_HIDE_DEPRECATED_CODE virtual void setObserver( Teuchos::RCP > obs = Teuchos::null); virtual Teuchos::RCP > getObserver() const { return this->stepperOSObserver_; } +#endif + + virtual void setAppAction(Teuchos::RCP > appAction); + + virtual Teuchos::RCP > getAppAction() const + { return stepperOSAppAction_; } virtual void setTempState(Teuchos::RCP> state) { tempState_ = state; } @@ -187,7 +210,10 @@ class StepperOperatorSplit : virtual public Tempus::Stepper std::vector > > subStepperList_; Teuchos::RCP > OpSpSolnHistory_; Teuchos::RCP > tempState_; +#ifndef TEMPUS_HIDE_DEPRECATED_CODE Teuchos::RCP > stepperOSObserver_; +#endif + Teuchos::RCP > stepperOSAppAction_; }; } // namespace Tempus diff --git a/packages/tempus/src/Tempus_StepperOperatorSplit_impl.hpp b/packages/tempus/src/Tempus_StepperOperatorSplit_impl.hpp index 8c8bf68bb85c..90e250d02870 100644 --- a/packages/tempus/src/Tempus_StepperOperatorSplit_impl.hpp +++ b/packages/tempus/src/Tempus_StepperOperatorSplit_impl.hpp @@ -12,7 +12,7 @@ #include "Teuchos_VerboseObjectParameterListHelpers.hpp" #include "Thyra_VectorStdOps.hpp" #include "Tempus_StepperFactory.hpp" - +#include "Tempus_StepperOperatorSplitModifierDefault.hpp" namespace Tempus { @@ -28,14 +28,17 @@ StepperOperatorSplit::StepperOperatorSplit() this->setOrder (1); this->setOrderMin(1); this->setOrderMax(1); - +#ifndef TEMPUS_HIDE_DEPRECATED_CODE this->setObserver(); +#endif + this->setAppAction(Teuchos::null); OpSpSolnHistory_ = rcp(new SolutionHistory()); OpSpSolnHistory_->setStorageLimit(2); OpSpSolnHistory_->setStorageType(Tempus::STORAGE_TYPE_STATIC); } +#ifndef TEMPUS_HIDE_DEPRECATED_CODE template StepperOperatorSplit::StepperOperatorSplit( std::vector > > appModels, @@ -59,6 +62,7 @@ StepperOperatorSplit::StepperOperatorSplit( this->setOrderMax(orderMax); this->setObserver(obs); + this->setAppAction(Teuchos::null); OpSpSolnHistory_ = rcp(new SolutionHistory()); OpSpSolnHistory_->setStorageLimit(2); @@ -69,6 +73,45 @@ StepperOperatorSplit::StepperOperatorSplit( this->initialize(); } } +#endif + +template +StepperOperatorSplit::StepperOperatorSplit( + std::vector > > appModels, + std::vector > > subStepperList, + bool useFSAL, + std::string ICConsistency, + bool ICConsistencyCheck, + int order, + int orderMin, + int orderMax, + const Teuchos::RCP >& stepperOSAppAction) +{ + this->setStepperType( "Operator Split"); + this->setUseFSAL( useFSAL); + this->setICConsistency( ICConsistency); + this->setICConsistencyCheck( ICConsistencyCheck); + + this->setSubStepperList(subStepperList); + this->setOrder (order); + this->setOrderMin(orderMin); + this->setOrderMax(orderMax); + +#ifndef TEMPUS_HIDE_DEPRECATED_CODE + this->setObserver(); +#endif + this->setAppAction(stepperOSAppAction); + + OpSpSolnHistory_ = rcp(new SolutionHistory()); + OpSpSolnHistory_->setStorageLimit(2); + OpSpSolnHistory_->setStorageType(Tempus::STORAGE_TYPE_STATIC); + + if ( !(appModels.empty()) ) { + this->setModels(appModels); + this->initialize(); + } +} + template void StepperOperatorSplit::setModel( @@ -115,6 +158,7 @@ void StepperOperatorSplit::setSolver( this->isInitialized_ = false; } +#ifndef TEMPUS_HIDE_DEPRECATED_CODE template void StepperOperatorSplit::setObserver( Teuchos::RCP > obs) @@ -132,6 +176,24 @@ void StepperOperatorSplit::setObserver( this->isInitialized_ = false; } +#endif + +template +void StepperOperatorSplit::setAppAction( + Teuchos::RCP > appAction) +{ + if (appAction == Teuchos::null) { + // Create default appAction, otherwise keep current. + if (stepperOSAppAction_ == Teuchos::null) { + stepperOSAppAction_ = + Teuchos::rcp(new StepperOperatorSplitModifierDefault()); + } + } else { + stepperOSAppAction_ = + Teuchos::rcp_dynamic_cast > (appAction, true); + } + this->isInitialized_ = false; +} template @@ -259,8 +321,12 @@ void StepperOperatorSplit::takeStep( " Number of States = " << solutionHistory->getNumStates() << "\n" "Try setting in \"Solution History\" \"Storage Type\" = \"Undo\"\n" " or \"Storage Type\" = \"Static\" and \"Storage Limit\" = \"2\"\n"); - +#ifndef TEMPUS_HIDE_DEPRECATED_CODE stepperOSObserver_->observeBeginTakeStep(solutionHistory, *this); +#endif + RCP > thisStepper = Teuchos::rcpFromRef(*this); + stepperOSAppAction_->execute(solutionHistory, thisStepper, + StepperOperatorSplitAppAction::ACTION_LOCATION::BEGIN_STEP); RCP > workingState=solutionHistory->getWorkingState(); @@ -281,11 +347,19 @@ void StepperOperatorSplit::takeStep( for (; subStepperIter < subStepperList_.end() and pass; subStepperIter++) { int index = subStepperIter - subStepperList_.begin(); +#ifndef TEMPUS_HIDE_DEPRECATED_CODE stepperOSObserver_->observeBeforeStepper(index, solutionHistory, *this); +#endif + stepperOSAppAction_->execute(solutionHistory, thisStepper, + StepperOperatorSplitAppAction::ACTION_LOCATION::BEFORE_STEPPER); (*subStepperIter)->takeStep(OpSpSolnHistory_); +#ifndef TEMPUS_HIDE_DEPRECATED_CODE stepperOSObserver_->observeAfterStepper(index, solutionHistory, *this); +#endif + stepperOSAppAction_->execute(solutionHistory, thisStepper, + StepperOperatorSplitAppAction::ACTION_LOCATION::AFTER_STEPPER); if (workingSubState->getSolutionStatus() == Status::FAILED) { pass = false; @@ -306,7 +380,11 @@ void StepperOperatorSplit::takeStep( workingState->setOrder(this->getOrder()); workingState->computeNorms(solutionHistory->getCurrentState()); OpSpSolnHistory_->clear(); +#ifndef TEMPUS_HIDE_DEPRECATED_CODE stepperOSObserver_->observeEndTakeStep(solutionHistory, *this); +#endif + stepperOSAppAction_->execute(solutionHistory, thisStepper, + StepperOperatorSplitAppAction::ACTION_LOCATION::END_STEP); } return; } @@ -345,12 +423,15 @@ void StepperOperatorSplit::describe( out << " = " << (*subStepperIter)->isInitialized() << std::endl; out << " = " << (*subStepperIter) << std::endl; } - out << " OpSpSolnHistory_ = " << OpSpSolnHistory_ << std::endl; - out << " tempState_ = " << tempState_ << std::endl; - out << " stepperOSObserver_ = " << stepperOSObserver_ << std::endl; - out << " order_ = " << order_ << std::endl; - out << " orderMin_ = " << orderMin_ << std::endl; - out << " orderMax_ = " << orderMax_ << std::endl; + out << " OpSpSolnHistory_ = " << OpSpSolnHistory_ << std::endl; + out << " tempState_ = " << tempState_ << std::endl; +#ifndef TEMPUS_HIDE_DEPRECATED_CODE + out << " stepperOSObserver_ = " << stepperOSObserver_ << std::endl; +#endif + out << " stepperOSAppAction_ = " << stepperOSAppAction_ << std::endl; + out << " order_ = " << order_ << std::endl; + out << " orderMin_ = " << orderMin_ << std::endl; + out << " orderMax_ = " << orderMax_ << std::endl; out << "----------------------------" << std::endl; } @@ -378,11 +459,16 @@ bool StepperOperatorSplit::isValidSetup(Teuchos::FancyOStream & out) con << ", is not initialized!\n"; } } - +#ifndef TEMPUS_HIDE_DEPRECATED_CODE if (stepperOSObserver_ == Teuchos::null) { isValidSetup = false; out << "The Operator-Split observer is not set!\n"; } +#endif + if (stepperOSAppAction_ == Teuchos::null) { + isValidSetup = false; + out << "The Operator-Split AppAction is not set!\n"; + } return isValidSetup; } diff --git a/packages/tempus/unit_test/Tempus_UnitTest_OperatorSplit.cpp b/packages/tempus/unit_test/Tempus_UnitTest_OperatorSplit.cpp index 951ceb9853b5..1e800fd00639 100644 --- a/packages/tempus/unit_test/Tempus_UnitTest_OperatorSplit.cpp +++ b/packages/tempus/unit_test/Tempus_UnitTest_OperatorSplit.cpp @@ -17,6 +17,12 @@ #include "Tempus_UnitTest_Utils.hpp" #include "Tempus_StepperRKButcherTableau.hpp" +#include "Tempus_StepperOperatorSplitModifierBase.hpp" +#include "Tempus_StepperOperatorSplitObserverBase.hpp" +#include "Tempus_StepperOperatorSplitModifierXBase.hpp" +#include "Tempus_StepperOperatorSplitModifierDefault.hpp" +#include "Tempus_StepperOperatorSplitObserver.hpp" + #include "../TestModels/VanDerPol_IMEX_ExplicitModel.hpp" #include "../TestModels/VanDerPol_IMEX_ImplicitModel.hpp" #include "../TestUtils/Tempus_ConvergenceTestUtils.hpp" @@ -63,8 +69,12 @@ TEUCHOS_UNIT_TEST(OperatorSplit, Default_Construction) TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized()); // Default values for construction. +#ifndef TEMPUS_DEPRECATED_CODE auto obs = rcp(new Tempus::StepperOperatorSplitObserver()); +#endif + auto modifier = rcp(new Tempus::StepperOperatorSplitModifierDefault()); + stepper->setAppAction(modifier); bool useFSAL = stepper->getUseFSALDefault(); std::string ICConsistency = stepper->getICConsistencyDefault(); bool ICConsistencyCheck = stepper->getICConsistencyCheckDefault(); @@ -89,9 +99,14 @@ TEUCHOS_UNIT_TEST(OperatorSplit, Default_Construction) subStepperList.push_back(subStepper1); subStepperList.push_back(subStepper2); +#ifndef TEMPUS_HIDE_DEPRECATED_CODE stepper = rcp(new Tempus::StepperOperatorSplit( models, subStepperList, obs, useFSAL, ICConsistency, ICConsistencyCheck, order, order, order)); +#endif + stepper = rcp(new Tempus::StepperOperatorSplit( + models, subStepperList, useFSAL, ICConsistency, ICConsistencyCheck,order, order, order,modifier)); + TEUCHOS_TEST_FOR_EXCEPT(!stepper->isInitialized()); } @@ -126,5 +141,382 @@ TEUCHOS_UNIT_TEST(OperatorSplit, StepperFactory_Construction) } #endif // STEPPERFACTORY_CONSTRUCTION +// ************************************************************ +// ************************************************************ +class StepperOperatorSplitModifierTest + : virtual public Tempus::StepperOperatorSplitModifierBase +{ +public: + + /// Constructor + StepperOperatorSplitModifierTest() + : testBEGIN_STEP(false), testEND_STEP(false), + testCurrentValue(-0.99), testWorkingValue(-0.99), + testDt(-1.5), testType("") + {} + + /// Destructor + virtual ~StepperOperatorSplitModifierTest(){} + + /// Modify OperatorSplit Stepper at action location. + virtual void modify( + Teuchos::RCP > sh, + Teuchos::RCP > stepper, + const typename Tempus::StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { + switch(actLoc) { + case StepperOperatorSplitAppAction::BEGIN_STEP: + { + testBEGIN_STEP = true; + auto x = sh->getCurrentState()->getX(); + testCurrentValue = get_ele(*(x), 0); + break; + } + case StepperOperatorSplitAppAction::BEFORE_STEPPER: + { + testBEFORE_STEPPER = true; + testDt = sh->getWorkingState()->getTimeStep()/10.0; + sh->getWorkingState()->setTimeStep(testDt); + break; + } + case StepperOperatorSplitAppAction::AFTER_STEPPER: + { + testAFTER_STEPPER = true; + testType = "OperatorSplit - Modifier"; + stepper->setStepperType(testType); + break; + } + case StepperOperatorSplitAppAction::END_STEP: + { + testEND_STEP = true; + auto x = sh->getWorkingState()->getX(); + testWorkingValue = get_ele(*(x), 0); + break; + } + default: + TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, + "Error - unknown action location.\n"); + } + } + + bool testBEGIN_STEP; + bool testBEFORE_STEPPER; + bool testAFTER_STEPPER; + bool testEND_STEP; + double testCurrentValue; + double testWorkingValue; + double testDt; + std::string testType; +}; + +TEUCHOS_UNIT_TEST(OperatorSplit, AppAction_Modifier) +{ + auto explicitModel = rcp(new Tempus_Test::VanDerPol_IMEX_ExplicitModel()); + auto implicitModel = rcp(new Tempus_Test::VanDerPol_IMEX_ImplicitModel()); + // Default construction. + auto stepper = rcp(new Tempus::StepperOperatorSplit()); + auto sf = Teuchos::rcp(new Tempus::StepperFactory()); + auto subStepper1 = + sf->createStepperForwardEuler(explicitModel, Teuchos::null); + auto subStepper2 = + sf->createStepperBackwardEuler(implicitModel, Teuchos::null); + auto modifier = rcp(new StepperOperatorSplitModifierTest()); + stepper->setAppAction(modifier); + stepper->addStepper(subStepper1); + stepper->addStepper(subStepper2); + stepper->initialize(); + + // Setup initial condition SolutionState -------------------- + Thyra::ModelEvaluatorBase::InArgs inArgsIC = + stepper->getModel()->getNominalValues(); + auto icX = rcp_const_cast > (inArgsIC.get_x()); + auto icXDot = rcp_const_cast > (inArgsIC.get_x_dot()); + auto icState = Tempus::createSolutionStateX(icX, icXDot); + icState->setTime (0.0); + icState->setIndex (1); + icState->setTimeStep(-15.0); + icState->setOrder (stepper->getOrder()); + icState->setSolutionStatus(Tempus::Status::PASSED); // ICs are passing. + + // Create a SolutionHistory. + auto solutionHistory = rcp(new Tempus::SolutionHistory()); + solutionHistory->setName("Forward States"); + solutionHistory->setStorageType(Tempus::STORAGE_TYPE_STATIC); + solutionHistory->setStorageLimit(2); + solutionHistory->addState(icState); + + // Take one time step. + stepper->setInitialConditions(solutionHistory); + solutionHistory->initWorkingState(); + solutionHistory->getWorkingState()->setTimeStep(-15.0); + stepper->takeStep(solutionHistory); + + // Testing that each ACTION_LOCATION has been called. + TEST_COMPARE(modifier->testBEGIN_STEP, ==, true); + TEST_COMPARE(modifier->testBEFORE_STEPPER, ==, true); + TEST_COMPARE(modifier->testAFTER_STEPPER, ==, true); + TEST_COMPARE(modifier->testEND_STEP, ==, true); + + // Testing that values can be set through the Modifier. + auto x = solutionHistory->getCurrentState()->getX(); + TEST_FLOATING_EQUALITY(modifier->testCurrentValue, get_ele(*(x), 0), 1.0e-15); + x = solutionHistory->getWorkingState()->getX(); + TEST_FLOATING_EQUALITY(modifier->testWorkingValue, get_ele(*(x), 0), 1.0e-15); + auto Dt = solutionHistory->getWorkingState()->getTimeStep(); + TEST_FLOATING_EQUALITY(modifier->testDt, Dt, 1.0e-15); + + TEST_COMPARE(modifier->testType, ==, "OperatorSplit - Modifier"); +} + +// ************************************************************ +// ************************************************************ +class StepperOperatorSplitObserverTest + : virtual public Tempus::StepperOperatorSplitObserverBase +{ +public: + + /// Constructor + StepperOperatorSplitObserverTest() + : testBEGIN_STEP(false), testBEFORE_STEPPER(false), + testAFTER_STEPPER(false), testEND_STEP(false), + testCurrentValue(-0.99), testWorkingValue(-0.99), + testDt(-1.5), testType("Operator Split") + {} + + /// Destructor + virtual ~StepperOperatorSplitObserverTest(){} + + /// Observe OperatorSplit Stepper at action location. + virtual void observe( + Teuchos::RCP > sh, + Teuchos::RCP > stepper, + const typename Tempus::StepperOperatorSplitAppAction::ACTION_LOCATION actLoc) + { + switch(actLoc) { + case StepperOperatorSplitAppAction::BEGIN_STEP: + { + testBEGIN_STEP = true; + auto x = sh->getCurrentState()->getX(); + testCurrentValue = get_ele(*(x), 0); + break; + } + case StepperOperatorSplitAppAction::BEFORE_STEPPER: + { + testBEFORE_STEPPER = true; + testDt = sh->getWorkingState()->getTimeStep(); + break; + } + case StepperOperatorSplitAppAction::AFTER_STEPPER: + { + testAFTER_STEPPER = true; + testType = stepper->getStepperType(); + break; + } + case StepperOperatorSplitAppAction::END_STEP: + { + testEND_STEP = true; + auto x = sh->getWorkingState()->getX(); + testWorkingValue = get_ele(*(x), 0); + break; + } + default: + TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, + "Error - unknown action location.\n"); + } + } + + bool testBEGIN_STEP; + bool testBEFORE_STEPPER; + bool testAFTER_STEPPER; + bool testEND_STEP; + double testCurrentValue; + double testWorkingValue; + double testDt; + std::string testType; +}; + +TEUCHOS_UNIT_TEST(OperatorSplit, AppAction_Observer) +{ + auto explicitModel = rcp(new Tempus_Test::VanDerPol_IMEX_ExplicitModel()); + auto implicitModel = rcp(new Tempus_Test::VanDerPol_IMEX_ImplicitModel()); + // Default construction. + auto stepper = rcp(new Tempus::StepperOperatorSplit()); + auto sf = Teuchos::rcp(new Tempus::StepperFactory()); + auto subStepper1 = + sf->createStepperForwardEuler(explicitModel, Teuchos::null); + auto subStepper2 = + sf->createStepperBackwardEuler(implicitModel, Teuchos::null); + auto observer = rcp(new StepperOperatorSplitObserverTest()); + stepper->setAppAction(observer); + stepper->addStepper(subStepper1); + stepper->addStepper(subStepper2); + stepper->initialize(); + + // Setup initial condition SolutionState -------------------- + Thyra::ModelEvaluatorBase::InArgs inArgsIC = + stepper->getModel()->getNominalValues(); + auto icX = rcp_const_cast > (inArgsIC.get_x()); + auto icXDot = rcp_const_cast > (inArgsIC.get_x_dot()); + auto icState = Tempus::createSolutionStateX(icX, icXDot); + icState->setTime (0.0); + icState->setIndex (1); + icState->setTimeStep(-1.5); + icState->setOrder (stepper->getOrder()); + icState->setSolutionStatus(Tempus::Status::PASSED); // ICs are passing. + + // Create a SolutionHistory. + auto solutionHistory = rcp(new Tempus::SolutionHistory()); + solutionHistory->setName("Forward States"); + solutionHistory->setStorageType(Tempus::STORAGE_TYPE_STATIC); + solutionHistory->setStorageLimit(2); + solutionHistory->addState(icState); + + // Take one time step. + stepper->setInitialConditions(solutionHistory); + solutionHistory->initWorkingState(); + solutionHistory->getWorkingState()->setTimeStep(-1.5); + stepper->takeStep(solutionHistory); + + // Testing that each ACTION_LOCATION has been called. + TEST_COMPARE(observer->testBEGIN_STEP, ==, true); + TEST_COMPARE(observer->testBEFORE_STEPPER, ==, true); + TEST_COMPARE(observer->testAFTER_STEPPER, ==, true); + TEST_COMPARE(observer->testEND_STEP, ==, true); + + // Testing that values can be observed through the observer. + auto x = solutionHistory->getCurrentState()->getX(); + TEST_FLOATING_EQUALITY(observer->testCurrentValue, get_ele(*(x), 0), 1.0e-15); + x = solutionHistory->getWorkingState()->getX(); + TEST_FLOATING_EQUALITY(observer->testWorkingValue, get_ele(*(x), 0), 1.0e-15); + TEST_FLOATING_EQUALITY(observer->testDt, -1.5, 1.0e-15); + + TEST_COMPARE(observer->testType, ==, "Operator Split"); +} + +// ************************************************************ +// ************************************************************ +class StepperOperatorSplitModifierXTest + : virtual public Tempus::StepperOperatorSplitModifierXBase +{ +public: + + /// Constructor + StepperOperatorSplitModifierXTest() + : testX_BEGIN_STEP(false), testX_BEFORE_STEPPER(false), + testX_AFTER_STEPPER(false), testXDOT_END_STEP(false), + testX(-0.99), testXDot(-0.99), + testDt(-1.5), testTime(-1.5) + {} + + /// Destructor + virtual ~StepperOperatorSplitModifierXTest(){} + + /// Modify OperatorSplit Stepper at action location. + virtual void modify( + Teuchos::RCP > x, + const double time, const double dt, + const typename Tempus::StepperOperatorSplitModifierXBase::MODIFIER_TYPE modType) + { + switch(modType) { + case StepperOperatorSplitModifierXBase::X_BEGIN_STEP: + { + testX_BEGIN_STEP = true; + testX = get_ele(*(x), 0); + break; + } + case StepperOperatorSplitModifierXBase::X_BEFORE_STEPPER: + { + testX_BEFORE_STEPPER = true; + testDt = dt; + break; + } + case StepperOperatorSplitModifierXBase::X_AFTER_STEPPER: + { + testX_AFTER_STEPPER = true; + testTime = time; + break; + } + case StepperOperatorSplitModifierXBase::XDOT_END_STEP: + { + testXDOT_END_STEP = true; + testXDot = get_ele(*(x), 0); + break; + } + default: + TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, + "Error - unknown action location.\n"); + } + } + + bool testX_BEGIN_STEP; + bool testX_BEFORE_STEPPER; + bool testX_AFTER_STEPPER; + bool testXDOT_END_STEP; + double testX; + double testXDot; + double testDt; + double testTime; +}; + +TEUCHOS_UNIT_TEST(OperatorSplit, AppAction_ModifierX) +{ + auto explicitModel = rcp(new Tempus_Test::VanDerPol_IMEX_ExplicitModel()); + auto implicitModel = rcp(new Tempus_Test::VanDerPol_IMEX_ImplicitModel()); + // Default construction. + auto stepper = rcp(new Tempus::StepperOperatorSplit()); + auto sf = Teuchos::rcp(new Tempus::StepperFactory()); + auto subStepper1 = + sf->createStepperForwardEuler(explicitModel, Teuchos::null); + auto subStepper2 = + sf->createStepperBackwardEuler(implicitModel, Teuchos::null); + auto modifierX = rcp(new StepperOperatorSplitModifierXTest()); + stepper->setAppAction(modifierX); + stepper->addStepper(subStepper1); + stepper->addStepper(subStepper2); + stepper->initialize(); + + // Setup initial condition SolutionState -------------------- + Thyra::ModelEvaluatorBase::InArgs inArgsIC = + stepper->getModel()->getNominalValues(); + auto icX = rcp_const_cast > (inArgsIC.get_x()); + auto icXDot = rcp_const_cast > (inArgsIC.get_x_dot()); + auto icState = Tempus::createSolutionStateX(icX, icXDot); + icState->setTime (0.0); + icState->setIndex (1); + icState->setTimeStep(-1.5); + icState->setOrder (stepper->getOrder()); + icState->setSolutionStatus(Tempus::Status::PASSED); // ICs are passing. + + // Create a SolutionHistory. + auto solutionHistory = rcp(new Tempus::SolutionHistory()); + solutionHistory->setName("Forward States"); + solutionHistory->setStorageType(Tempus::STORAGE_TYPE_STATIC); + solutionHistory->setStorageLimit(2); + solutionHistory->addState(icState); + + // Take one time step. + stepper->setInitialConditions(solutionHistory); + solutionHistory->initWorkingState(); + solutionHistory->getWorkingState()->setTimeStep(-1.5); + stepper->takeStep(solutionHistory); + + // Testing that each ACTION_LOCATION has been called. + TEST_COMPARE(modifierX->testX_BEGIN_STEP, ==, true); + TEST_COMPARE(modifierX->testX_BEFORE_STEPPER, ==, true); + TEST_COMPARE(modifierX->testX_AFTER_STEPPER, ==, true); + TEST_COMPARE(modifierX->testXDOT_END_STEP, ==, true); + + // Testing that values can be set through the Modifier. + auto x = solutionHistory->getCurrentState()->getX(); + TEST_FLOATING_EQUALITY(modifierX->testX, get_ele(*(x), 0), 1.0e-15); + // Temporary memory for xDot is not guarranteed to exist outside the Stepper. + auto xDot = stepper->getStepperXDot(solutionHistory->getWorkingState()); + TEST_FLOATING_EQUALITY(modifierX->testXDot, get_ele(*(xDot), 0),1.0e-15); + auto Dt = solutionHistory->getWorkingState()->getTimeStep(); + TEST_FLOATING_EQUALITY(modifierX->testDt, Dt, 1.0e-15); + + auto time = solutionHistory->getWorkingState()->getTime(); + TEST_FLOATING_EQUALITY(modifierX->testTime, time, 1.0e-15); +} } // namespace Tempus_Test