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>
27 const Teuchos::RCP<
const Thyra::ModelEvaluator<Scalar> > & model,
28 const Scalar& t_final,
29 const bool is_pseudotransient,
30 const Teuchos::RCP<const Teuchos::ParameterList>& pList) :
33 is_pseudotransient_(is_pseudotransient),
34 mass_matrix_is_computed_(false),
35 t_interp_(Teuchos::ScalarTraits<Scalar>::rmax())
37 typedef Thyra::ModelEvaluatorBase MEB;
40 Teuchos::RCP<Teuchos::ParameterList> pl =
41 Teuchos::rcp(
new Teuchos::ParameterList);
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);
52 TEUCHOS_TEST_FOR_EXCEPTION(
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);
91 TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_x));
92 TEUCHOS_ASSERT(me_outArgs.supports(MEB::OUT_ARG_W_op));
93 if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
94 TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_alpha));
95 TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_beta));
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();
115 t_interp_ = Teuchos::ScalarTraits<Scalar>::rmax();
116 forward_state_ = Teuchos::null;
120 template <
typename Scalar>
121 Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
125 TEUCHOS_ASSERT(p < model_->Np());
126 return model_->get_p_space(p);
129 template <
typename Scalar>
130 Teuchos::RCP<const Teuchos::Array<std::string> >
134 TEUCHOS_ASSERT(p < model_->Np());
135 return model_->get_p_names(p);
138 template <
typename Scalar>
139 Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
143 return adjoint_space_;
146 template <
typename Scalar>
147 Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
151 return residual_space_;
154 template <
typename Scalar>
155 Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
159 TEUCHOS_ASSERT(j == 0);
160 return response_space_;
163 template <
typename Scalar>
164 Teuchos::RCP<Thyra::LinearOpBase<Scalar> >
168 Teuchos::RCP<Thyra::LinearOpBase<Scalar> > op = model_->create_W_op();
169 return Thyra::nonconstMultiVectorLinearOp( Thyra::nonconstAdjoint(op),
173 template <
typename Scalar>
174 Teuchos::RCP<const Thyra::LinearOpWithSolveFactoryBase<Scalar> >
179 using Teuchos::rcp_dynamic_cast;
180 typedef Thyra::LinearOpWithSolveFactoryBase<Scalar> LOWSFB;
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>
192 Thyra::ModelEvaluatorBase::InArgs<Scalar>
196 return prototypeInArgs_;
199 template <
typename Scalar>
200 Thyra::ModelEvaluatorBase::InArgs<Scalar>
204 typedef Thyra::ModelEvaluatorBase MEB;
206 using Teuchos::rcp_dynamic_cast;
208 MEB::InArgs<Scalar> me_nominal = model_->getNominalValues();
209 MEB::InArgs<Scalar> nominal = this->createInArgs();
211 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
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>
233 Thyra::ModelEvaluatorBase::OutArgs<Scalar>
237 return prototypeOutArgs_;
240 template <
typename Scalar>
244 const Thyra::ModelEvaluatorBase::OutArgs<Scalar> &outArgs)
const
246 typedef Thyra::ModelEvaluatorBase MEB;
248 using Teuchos::rcp_dynamic_cast;
252 TEUCHOS_ASSERT(sh_ != Teuchos::null);
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)) {
272 if (inArgs.get_x_dot() != Teuchos::null)
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))
306 me_inArgs.set_alpha(inArgs.get_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 =
313 rcp_dynamic_cast<Thyra::DefaultScaledAdjointLinearOp<Scalar> >(
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);
368 my_dfdx_->apply(Thyra::CONJTRANS, *adjoint_x_mv, adjoint_f_mv.ptr(),
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;
397 my_dfdxdot_->apply(Thyra::CONJTRANS, *adjoint_x_dot_mv,
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);
432 Thyra::DetachedMultiVectorView<Scalar> dgdp_view(*adjoint_g_mv);
433 Thyra::DetachedMultiVectorView<Scalar> dgdp_trans_view(*dgdp_trans);
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);
439 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::logic_error,
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_);
446 Thyra::EOpTransp trans = Thyra::CONJTRANS;
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_));
451 trans = Thyra::CONJTRANS;
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_;
461 trans = Thyra::CONJTRANS;
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_;
474 TEUCHOS_TEST_FOR_EXCEPTION(
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>
483 Teuchos::RCP<const Teuchos::ParameterList>
487 Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
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_
bool mass_matrix_is_identity_
Thyra::ModelEvaluatorBase::InArgs< Scalar > createInArgs() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_x_space() 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
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_
Thyra::ModelEvaluatorBase::OutArgs< Scalar > prototypeOutArgs_
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_f_space() const
Thyra::DefaultMultiVectorProductVector< Scalar > DMVPV
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
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_W_op() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int p) const