9 #ifndef Tempus_AdjointSensitivityModelEvaluator_impl_hpp
10 #define Tempus_AdjointSensitivityModelEvaluator_impl_hpp
12 #include "Thyra_DefaultMultiVectorProductVectorSpace.hpp"
13 #include "Thyra_DefaultMultiVectorProductVector.hpp"
16 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
17 #include "Thyra_DefaultAdjointLinearOpWithSolve.hpp"
19 #include "Thyra_VectorStdOps.hpp"
20 #include "Thyra_MultiVectorStdOps.hpp"
24 template <
typename Scalar>
28 const Scalar& t_final,
29 const bool is_pseudotransient,
33 is_pseudotransient_(is_pseudotransient),
34 mass_matrix_is_computed_(false),
35 t_interp_(Teuchos::ScalarTraits<Scalar>::rmax())
42 if (pList != Teuchos::null)
47 p_index_ = pl->
get<
int>(
"Sensitivity Parameter Index", 0);
48 g_index_ = pl->
get<
int>(
"Response Function Index", 0);
54 "AdjointSensitivityModelEvaluator currently does not support " <<
55 "non-constant mass matrix df/dx_dot!");
62 Thyra::multiVectorProductVectorSpace(
model_->get_p_space(p_index_),
65 MEB::InArgs<Scalar> me_inArgs =
model_->createInArgs();
66 MEB::InArgsSetup<Scalar> inArgs;
67 inArgs.setModelEvalDescription(this->
description());
68 inArgs.setSupports(MEB::IN_ARG_x);
69 inArgs.setSupports(MEB::IN_ARG_t);
70 if (me_inArgs.supports(MEB::IN_ARG_x_dot))
71 inArgs.setSupports(MEB::IN_ARG_x_dot);
72 if (me_inArgs.supports(MEB::IN_ARG_alpha))
73 inArgs.setSupports(MEB::IN_ARG_alpha);
74 if (me_inArgs.supports(MEB::IN_ARG_beta))
75 inArgs.setSupports(MEB::IN_ARG_beta);
78 inArgs.set_Np(me_inArgs.Np());
81 MEB::OutArgs<Scalar> me_outArgs =
model_->createOutArgs();
82 MEB::OutArgsSetup<Scalar> outArgs;
83 outArgs.setModelEvalDescription(this->
description());
84 outArgs.set_Np_Ng(me_inArgs.Np(),1);
85 outArgs.setSupports(MEB::OUT_ARG_f);
86 outArgs.setSupports(MEB::OUT_ARG_W_op);
93 if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
97 MEB::DerivativeSupport dgdx_support =
98 me_outArgs.supports(MEB::OUT_ARG_DgDx, g_index_);
99 MEB::DerivativeSupport dgdp_support =
100 me_outArgs.supports(MEB::OUT_ARG_DgDp, g_index_, p_index_);
101 TEUCHOS_ASSERT(dgdx_support.supports(MEB::DERIV_MV_GRADIENT_FORM));
102 TEUCHOS_ASSERT(dgdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM));
105 template <
typename Scalar>
112 if (is_pseudotransient_)
113 forward_state_ = sh_->getCurrentState();
116 forward_state_ = Teuchos::null;
120 template <
typename Scalar>
126 return model_->get_p_space(p);
129 template <
typename Scalar>
135 return model_->get_p_names(p);
138 template <
typename Scalar>
143 return adjoint_space_;
146 template <
typename Scalar>
151 return residual_space_;
154 template <
typename Scalar>
160 return response_space_;
163 template <
typename Scalar>
169 return Thyra::nonconstMultiVectorLinearOp( Thyra::nonconstAdjoint(op),
173 template <
typename Scalar>
179 using Teuchos::rcp_dynamic_cast;
182 RCP<const LOWSFB> factory = model_->get_W_factory();
183 if (factory == Teuchos::null)
184 return Teuchos::null;
186 RCP<const LOWSFB> alowsfb = Thyra::adjointLinearOpWithSolveFactory(factory);
187 return Thyra::multiVectorLinearOpWithSolveFactory(
188 alowsfb, residual_space_, adjoint_space_);
191 template <
typename Scalar>
196 return prototypeInArgs_;
199 template <
typename Scalar>
206 using Teuchos::rcp_dynamic_cast;
208 MEB::InArgs<Scalar> me_nominal = model_->getNominalValues();
209 MEB::InArgs<Scalar> nominal = this->createInArgs();
214 RCP< Thyra::VectorBase<Scalar> > x = Thyra::createMember(*adjoint_space_);
215 Thyra::assign(x.ptr(), zero);
218 if (me_nominal.supports(MEB::IN_ARG_x_dot)) {
219 RCP< Thyra::VectorBase<Scalar> > x_dot =
220 Thyra::createMember(*adjoint_space_);
221 Thyra::assign(x_dot.ptr(), zero);
222 nominal.set_x_dot(x_dot);
225 const int np = model_->Np();
226 for (
int i=0; i<np; ++i)
227 nominal.set_p(i, me_nominal.get_p(i));
232 template <
typename Scalar>
237 return prototypeOutArgs_;
240 template <
typename Scalar>
248 using Teuchos::rcp_dynamic_cast;
253 const Scalar t = inArgs.
get_t();
255 if (is_pseudotransient_)
256 forward_t = forward_state_->getTime();
258 forward_t = t_final_ - t;
259 if (forward_state_ == Teuchos::null || t_interp_ != t) {
260 if (forward_state_ == Teuchos::null)
261 forward_state_ = sh_->interpolateState(forward_t);
263 sh_->interpolateState(forward_t, forward_state_.get());
269 MEB::InArgs<Scalar> me_inArgs = model_->getNominalValues();
270 me_inArgs.set_x(forward_state_->getX());
271 if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
273 me_inArgs.set_x_dot(forward_state_->getXDot());
275 if (is_pseudotransient_) {
280 if (my_x_dot_ == Teuchos::null) {
281 my_x_dot_ = Thyra::createMember(model_->get_x_space());
282 Thyra::assign(my_x_dot_.ptr(), Scalar(0.0));
284 me_inArgs.set_x_dot(my_x_dot_);
289 me_inArgs.set_x_dot(Teuchos::null);
293 if (me_inArgs.supports(MEB::IN_ARG_t))
294 me_inArgs.set_t(forward_t);
295 const int np = me_inArgs.Np();
296 for (
int i=0; i<np; ++i)
297 me_inArgs.set_p(i, inArgs.
get_p(i));
303 RCP<Thyra::LinearOpBase<Scalar> > op = outArgs.
get_W_op();
304 if (op != Teuchos::null) {
305 if (me_inArgs.supports(MEB::IN_ARG_alpha))
307 if (me_inArgs.supports(MEB::IN_ARG_beta))
308 me_inArgs.set_beta(inArgs.
get_beta());
310 RCP<Thyra::MultiVectorLinearOp<Scalar> > mv_adjoint_op =
312 RCP<Thyra::DefaultScaledAdjointLinearOp<Scalar> > adjoint_op =
314 mv_adjoint_op->getNonconstLinearOp(),
true);
315 MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
316 me_outArgs.set_W_op(adjoint_op->getNonconstOp());
317 model_->evalModel(me_inArgs, me_outArgs);
320 RCP<Thyra::VectorBase<Scalar> > adjoint_f = outArgs.
get_f();
321 RCP<Thyra::VectorBase<Scalar> > adjoint_g = outArgs.
get_g(0);
322 RCP<const Thyra::MultiVectorBase<Scalar> > adjoint_x_mv;
323 if (adjoint_f != Teuchos::null || adjoint_g != Teuchos::null) {
324 RCP<const Thyra::VectorBase<Scalar> > adjoint_x =
325 inArgs.
get_x().assert_not_null();
327 rcp_dynamic_cast<
const DMVPV>(adjoint_x,
true)->getMultiVector();
335 if (adjoint_f != Teuchos::null) {
336 RCP<Thyra::MultiVectorBase<Scalar> > adjoint_f_mv =
337 rcp_dynamic_cast<
DMVPV>(adjoint_f,
true)->getNonconstMultiVector();
339 MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
343 if (!is_pseudotransient_ || my_dgdx_mv_ == Teuchos::null) {
344 if (my_dgdx_mv_ == Teuchos::null)
346 Thyra::createMembers(model_->get_x_space(),
347 model_->get_g_space(g_index_)->dim());
348 me_outArgs.set_DgDx(g_index_,
349 MEB::Derivative<Scalar>(my_dgdx_mv_,
350 MEB::DERIV_MV_GRADIENT_FORM));
351 model_->evalModel(me_inArgs, me_outArgs);
352 me_outArgs.set_DgDx(g_index_, MEB::Derivative<Scalar>());
354 Thyra::assign(adjoint_f_mv.ptr(), *my_dgdx_mv_);
358 if (!is_pseudotransient_ || my_dfdx_ == Teuchos::null) {
359 if (my_dfdx_ == Teuchos::null)
360 my_dfdx_ = model_->create_W_op();
361 me_outArgs.set_W_op(my_dfdx_);
362 if (me_inArgs.supports(MEB::IN_ARG_alpha))
363 me_inArgs.set_alpha(0.0);
364 if (me_inArgs.supports(MEB::IN_ARG_beta))
365 me_inArgs.set_beta(1.0);
366 model_->evalModel(me_inArgs, me_outArgs);
369 Scalar(-1.0), Scalar(1.0));
375 if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
376 RCP<const Thyra::VectorBase<Scalar> > adjoint_x_dot = inArgs.
get_x_dot();
377 if (adjoint_x_dot != Teuchos::null) {
378 RCP<const Thyra::MultiVectorBase<Scalar> > adjoint_x_dot_mv =
379 rcp_dynamic_cast<
const DMVPV>(adjoint_x_dot,
true)->getMultiVector();
380 if (mass_matrix_is_identity_) {
382 Thyra::V_StVpV(adjoint_f_mv.ptr(), Scalar(-1.0), *adjoint_f_mv,
386 if (!is_pseudotransient_ || my_dfdxdot_ == Teuchos::null) {
387 if (my_dfdxdot_ == Teuchos::null)
388 my_dfdxdot_ = model_->create_W_op();
389 if (!mass_matrix_is_constant_ || !mass_matrix_is_computed_) {
390 me_outArgs.set_W_op(my_dfdxdot_);
391 me_inArgs.set_alpha(1.0);
392 me_inArgs.set_beta(0.0);
393 model_->evalModel(me_inArgs, me_outArgs);
394 mass_matrix_is_computed_ =
true;
398 adjoint_f_mv.ptr(), Scalar(1.0), Scalar(-1.0));
408 if (adjoint_g != Teuchos::null) {
409 RCP<Thyra::MultiVectorBase<Scalar> > adjoint_g_mv =
410 rcp_dynamic_cast<
DMVPV>(adjoint_g,
true)->getNonconstMultiVector();
412 MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
415 MEB::DerivativeSupport dgdp_support =
416 me_outArgs.supports(MEB::OUT_ARG_DgDp, g_index_, p_index_);
417 if (dgdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
418 me_outArgs.set_DgDp(g_index_, p_index_,
419 MEB::Derivative<Scalar>(adjoint_g_mv,
420 MEB::DERIV_MV_GRADIENT_FORM));
421 model_->evalModel(me_inArgs, me_outArgs);
423 else if (dgdp_support.supports(MEB::DERIV_MV_JACOBIAN_FORM)) {
424 const int num_g = model_->get_g_space(g_index_)->dim();
425 const int num_p = model_->get_p_space(p_index_)->dim();
426 RCP<Thyra::MultiVectorBase<Scalar> > dgdp_trans =
427 createMembers(model_->get_g_space(g_index_), num_p);
428 me_outArgs.set_DgDp(g_index_, p_index_,
429 MEB::Derivative<Scalar>(dgdp_trans,
430 MEB::DERIV_MV_JACOBIAN_FORM));
431 model_->evalModel(me_inArgs, me_outArgs);
434 for (
int i=0; i<num_p; ++i)
435 for (
int j=0; j<num_g; ++j)
436 dgdp_view(i,j) = dgdp_trans_view(j,i);
440 "Invalid dg/dp support");
441 me_outArgs.set_DgDp(g_index_, p_index_, MEB::Derivative<Scalar>());
444 MEB::DerivativeSupport dfdp_support =
445 me_outArgs.supports(MEB::OUT_ARG_DfDp, p_index_);
447 if (dfdp_support.supports(MEB::DERIV_LINEAR_OP)) {
448 if (my_dfdp_op_ == Teuchos::null)
449 my_dfdp_op_ = model_->create_DfDp_op(p_index_);
450 me_outArgs.set_DfDp(p_index_, MEB::Derivative<Scalar>(my_dfdp_op_));
453 else if (dfdp_support.supports(MEB::DERIV_MV_JACOBIAN_FORM)) {
454 if (my_dfdp_mv_ == Teuchos::null)
455 my_dfdp_mv_ = createMembers(model_->get_f_space(),
456 model_->get_p_space(p_index_)->dim());
457 me_outArgs.set_DfDp(p_index_,
458 MEB::Derivative<Scalar>(my_dfdp_mv_,
459 MEB::DERIV_MV_JACOBIAN_FORM));
460 my_dfdp_op_ = my_dfdp_mv_;
463 else if (dfdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
464 if (my_dfdp_mv_ == Teuchos::null)
465 my_dfdp_mv_ = createMembers(model_->get_p_space(p_index_),
466 model_->get_f_space()->dim());
467 me_outArgs.set_DfDp(p_index_,
468 MEB::Derivative<Scalar>(my_dfdp_mv_,
469 MEB::DERIV_MV_GRADIENT_FORM));
470 my_dfdp_op_ = my_dfdp_mv_;
475 true, std::logic_error,
"Invalid df/dp support");
476 model_->evalModel(me_inArgs, me_outArgs);
477 my_dfdp_op_->apply(trans, *adjoint_x_mv, adjoint_g_mv.ptr(),
478 Scalar(-1.0), Scalar(1.0));
482 template<
class Scalar>
488 pl->
set<
int>(
"Sensitivity Parameter Index", 0);
489 pl->
set<
int>(
"Response Function Index", 0);
490 pl->
set<
bool>(
"Mass Matrix Is Constant",
true);
491 pl->
set<
bool>(
"Mass Matrix Is Identity",
false);
static Teuchos::RCP< const Teuchos::ParameterList > getValidParameters()
AdjointSensitivityModelEvaluator(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &model, const Scalar &t_final, const bool is_pseudotransient, const Teuchos::RCP< const Teuchos::ParameterList > &pList=Teuchos::null)
Constructor.
Teuchos::RCP< const DMVPVS > residual_space_
Teuchos::RCP< const DMVPVS > adjoint_space_
RCP< const VectorBase< Scalar > > get_x_dot() const
bool mass_matrix_is_identity_
T & get(const std::string &name, T def_value)
Thyra::ModelEvaluatorBase::InArgs< Scalar > createInArgs() const
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_x_space() const
Evaluation< VectorBase< Scalar > > get_g(int j) const
Evaluation< VectorBase< Scalar > > get_f() const
Teuchos::RCP< const Teuchos::Array< std::string > > get_p_names(int p) const
Teuchos::RCP< const DMVPVS > response_space_
Teuchos::RCP< const Thyra::LinearOpWithSolveFactoryBase< Scalar > > get_W_factory() const
static magnitudeType rmax()
bool mass_matrix_is_constant_
void evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs) const
Thyra::ModelEvaluatorBase::OutArgs< Scalar > createOutArgsImpl() const
Thyra::ModelEvaluatorBase::InArgs< Scalar > prototypeInArgs_
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Thyra::ModelEvaluatorBase::OutArgs< Scalar > prototypeOutArgs_
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_f_space() const
virtual std::string description() const
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_g_space(int j) const
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > model_
void setForwardSolutionHistory(const Teuchos::RCP< const Tempus::SolutionHistory< Scalar > > &sh)
Set solution history from forward evaluation.
Implicit concrete LinearOpBase subclass that takes a flattended out multi-vector and performs a multi...
Thyra::ModelEvaluatorBase::InArgs< Scalar > getNominalValues() const
#define TEUCHOS_ASSERT(assertion_test)
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_W_op() const
RCP< LinearOpBase< Scalar > > get_W_op() const
RCP< const VectorBase< Scalar > > get_x() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int p) const
RCP< const VectorBase< Scalar > > get_p(int l) const