Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_StaggeredForwardSensitivityModelEvaluator_impl.hpp
Go to the documentation of this file.
1 //@HEADER
2 // *****************************************************************************
3 // Tempus: Time Integration and Sensitivity Analysis Package
4 //
5 // Copyright 2017 NTESS and the Tempus contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 //@HEADER
9 
10 #ifndef Tempus_StaggeredForwardSensitivityModelEvaluator_impl_hpp
11 #define Tempus_StaggeredForwardSensitivityModelEvaluator_impl_hpp
12 
13 #include "Thyra_DefaultMultiVectorProductVector.hpp"
17 #include "Thyra_VectorStdOps.hpp"
18 #include "Thyra_MultiVectorStdOps.hpp"
19 
20 namespace Tempus {
21 
22 template <typename Scalar>
25  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >& model,
27  sens_residual_model,
29  sens_solve_model,
30  const bool is_pseudotransient,
32  const Teuchos::RCP<MultiVector>& dxdp_init,
33  const Teuchos::RCP<MultiVector>& dx_dotdp_init,
34  const Teuchos::RCP<MultiVector>& dx_dotdotdp_init)
35  : model_(model),
36  sens_residual_model_(sens_residual_model),
37  sens_solve_model_(sens_solve_model),
38  dxdp_init_(dxdp_init),
39  dx_dotdp_init_(dx_dotdp_init),
40  dx_dotdotdp_init_(dx_dotdotdp_init),
41  p_index_(0),
42  g_index_(-1),
43  x_tangent_index_(1),
44  xdot_tangent_index_(2),
45  xdotdot_tangent_index_(3),
46  use_dfdp_as_tangent_(false),
47  use_dgdp_as_tangent_(false),
48  num_param_(0),
49  num_response_(0),
50  g_offset_(0),
51  is_pseudotransient_(is_pseudotransient),
52  mass_matrix_is_computed_(false),
53  jacobian_matrix_is_computed_(false),
54  acceleration_matrix_is_computed_(false),
55  residual_sensitivity_is_computed_(false),
56  t_interp_(Teuchos::ScalarTraits<Scalar>::rmax())
57 {
58  typedef Thyra::ModelEvaluatorBase MEB;
59 
60  // Set parameters
63  if (pList != Teuchos::null) *pl = *pList;
65  use_dfdp_as_tangent_ = pl->get<bool>("Use DfDp as Tangent");
66  use_dgdp_as_tangent_ = pl->get<bool>("Use DgDp as Tangent");
67  p_index_ = pl->get<int>("Sensitivity Parameter Index");
68  g_index_ = pl->get<int>("Response Function Index", -1);
69  x_tangent_index_ = pl->get<int>("Sensitivity X Tangent Index");
70  xdot_tangent_index_ = pl->get<int>("Sensitivity X-Dot Tangent Index");
71  xdotdot_tangent_index_ = pl->get<int>("Sensitivity X-Dot-Dot Tangent Index");
72 
73  num_param_ = model_->get_p_space(p_index_)->dim();
74  if (g_index_ >= 0) {
75  num_response_ = model_->get_g_space(g_index_)->dim();
76  g_offset_ = 2;
77  }
78  dxdp_space_ =
79  Thyra::multiVectorProductVectorSpace(model_->get_x_space(), num_param_);
80  dfdp_space_ =
81  Thyra::multiVectorProductVectorSpace(model_->get_f_space(), num_param_);
82  if (g_index_ >= 0)
83  dgdp_space_ = Thyra::multiVectorProductVectorSpace(
84  model_->get_g_space(g_index_), num_param_);
85 
86  // forward and sensitivity models must support same InArgs
87  MEB::InArgs<Scalar> me_inArgs = model_->createInArgs();
88  me_inArgs.assertSameSupport(sens_residual_model_->createInArgs());
89  me_inArgs.assertSameSupport(sens_solve_model_->createInArgs());
90 
91  MEB::InArgsSetup<Scalar> inArgs;
92  inArgs.setModelEvalDescription(this->description());
93  inArgs.setSupports(MEB::IN_ARG_x);
94  if (me_inArgs.supports(MEB::IN_ARG_x_dot))
95  inArgs.setSupports(MEB::IN_ARG_x_dot);
96  if (me_inArgs.supports(MEB::IN_ARG_t)) inArgs.setSupports(MEB::IN_ARG_t);
97  if (me_inArgs.supports(MEB::IN_ARG_alpha))
98  inArgs.setSupports(MEB::IN_ARG_alpha);
99  if (me_inArgs.supports(MEB::IN_ARG_beta))
100  inArgs.setSupports(MEB::IN_ARG_beta);
101  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
102  inArgs.setSupports(MEB::IN_ARG_W_x_dot_dot_coeff);
103 
104  // Support additional parameters for x and xdot
105  inArgs.set_Np(me_inArgs.Np());
106  prototypeInArgs_ = inArgs;
107 
108  MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
109  MEB::OutArgs<Scalar> sens_mer_outArgs = sens_residual_model_->createOutArgs();
110  MEB::OutArgs<Scalar> sens_mes_outArgs = sens_solve_model_->createOutArgs();
111  MEB::OutArgsSetup<Scalar> outArgs;
112  outArgs.setModelEvalDescription(this->description());
113  outArgs.set_Np_Ng(me_inArgs.Np(), me_outArgs.Ng() + g_offset_);
114  outArgs.setSupports(MEB::OUT_ARG_f);
115  if (sens_mer_outArgs.supports(MEB::OUT_ARG_W_op) ||
116  sens_mes_outArgs.supports(MEB::OUT_ARG_W_op))
117  outArgs.setSupports(MEB::OUT_ARG_W_op);
118 
119  // Response 0 is the reduced dg/dp (no sensitivities supported)
120  // Response 1 is the reduced g (no sensitivities supported)
121  for (int j = 0; j < me_outArgs.Ng(); ++j) {
122  outArgs.setSupports(MEB::OUT_ARG_DgDx_dot, j + g_offset_,
123  me_outArgs.supports(MEB::OUT_ARG_DgDx_dot, j));
124  outArgs.setSupports(MEB::OUT_ARG_DgDx, j + g_offset_,
125  me_outArgs.supports(MEB::OUT_ARG_DgDx, j));
126  for (int l = 0; l < me_outArgs.Np(); ++l) {
127  outArgs.setSupports(MEB::OUT_ARG_DgDp, j + g_offset_, l,
128  me_outArgs.supports(MEB::OUT_ARG_DgDp, j, l));
129  }
130  }
131  prototypeOutArgs_ = outArgs;
132 
133  // Sensitivity residual ME must support W_op to define adjoint ODE/DAE.
134  // Must support alpha, beta if it suports x_dot
135  TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_x));
137  TEUCHOS_ASSERT(sens_mer_outArgs.supports(MEB::OUT_ARG_W_op));
138  if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
139  TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_alpha));
140  TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_beta));
141  }
142  TEUCHOS_ASSERT(me_outArgs.supports(MEB::OUT_ARG_DfDp, p_index_)
143  .supports(MEB::DERIV_MV_JACOBIAN_FORM));
144 }
145 
146 template <typename Scalar>
150 {
151  sh_ = sh;
153 }
154 
155 template <typename Scalar>
158 {
159  sh_ = Teuchos::null;
160  forward_state_ = s;
161 }
162 
163 template <typename Scalar>
166 {
167  TEUCHOS_ASSERT(p < model_->Np());
168  return model_->get_p_space(p);
169 }
170 
171 template <typename Scalar>
174 {
175  TEUCHOS_ASSERT(p < model_->Np());
176  return model_->get_p_names(p);
177 }
178 
179 template <typename Scalar>
182 {
183  return dxdp_space_;
184 }
185 
186 template <typename Scalar>
189 {
190  return dfdp_space_;
191 }
192 
193 template <typename Scalar>
196 {
197  if (g_index_ >= 0) {
198  if (j == 0)
199  return dgdp_space_;
200  else if (j == 1)
201  return model_->get_g_space(g_index_);
202  }
203  return model_->get_g_space(j - g_offset_);
204 }
205 
206 template <typename Scalar>
209 {
210  if (g_index_ >= 0) {
211  if (j == 0) {
212  Teuchos::Array<std::string> names = model_->get_g_names(g_index_);
213  for (int i = 0; i < names.size(); ++i)
214  names[i] = names[i] + "_reduced sensitivity";
215  return names();
216  }
217  else if (j == 1)
218  return model_->get_g_names(g_index_);
219  }
220  return model_->get_g_names(j - g_offset_);
221 }
222 
223 template <typename Scalar>
226 {
228  if (lo_ != Teuchos::null)
229  op = lo_;
230  else
231  op = sens_solve_model_->create_W_op();
232  return Thyra::nonconstMultiVectorLinearOp(op, num_param_);
233 }
234 
235 template <typename Scalar>
238  int j) const
239 {
240  return model_->create_DgDx_dot_op(j - g_offset_);
241 }
242 
243 template <typename Scalar>
246 {
247  return model_->create_DgDx_op(j - g_offset_);
248 }
249 
250 template <typename Scalar>
253  int l) const
254 {
255  return model_->create_DgDp_op(j - g_offset_, l);
256 }
257 
258 template <typename Scalar>
261 {
262  using Teuchos::RCP;
263  using Teuchos::rcp_dynamic_cast;
264 
267  model_factory = sens_solve_model_->get_W_factory();
268  if (model_factory == Teuchos::null)
269  return Teuchos::null; // model_ doesn't support W_factory
270  if (po_ != Teuchos::null) {
271  factory = Thyra::reuseLinearOpWithSolveFactory<Scalar>(model_factory, po_);
272  }
273  else
274  factory = model_factory;
275  return Thyra::multiVectorLinearOpWithSolveFactory(factory, dfdp_space_,
276  dxdp_space_);
277 }
278 
279 template <typename Scalar>
282 {
283  return prototypeInArgs_;
284 }
285 
286 template <typename Scalar>
289 {
290  typedef Thyra::ModelEvaluatorBase MEB;
292  using Teuchos::RCP;
293  using Teuchos::rcp_dynamic_cast;
294 
295  MEB::InArgs<Scalar> me_nominal = model_->getNominalValues();
296  MEB::InArgs<Scalar> nominal = this->createInArgs();
297 
298  const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
299 
300  // Set initial x. If dxdp_init == null, set initial dx/dp = 0
301  RCP<Thyra::VectorBase<Scalar> > x = Thyra::createMember(*dxdp_space_);
302  RCP<DMVPV> dxdp = rcp_dynamic_cast<DMVPV>(x, true);
303  if (dxdp_init_ == Teuchos::null)
304  Thyra::assign(dxdp->getNonconstMultiVector().ptr(), zero);
305  else
306  Thyra::assign(dxdp->getNonconstMultiVector().ptr(), *dxdp_init_);
307  nominal.set_x(x);
308 
309  // Set initial xdot. If dx_dotdp_init == null, set initial dxdot/dp = 0
310  if (me_nominal.supports(MEB::IN_ARG_x_dot)) {
311  RCP<Thyra::VectorBase<Scalar> > xdot = Thyra::createMember(*dxdp_space_);
312  RCP<DMVPV> dxdotdp = rcp_dynamic_cast<DMVPV>(xdot, true);
313  if (dx_dotdp_init_ == Teuchos::null)
314  Thyra::assign(dxdotdp->getNonconstMultiVector().ptr(), zero);
315  else
316  Thyra::assign(dxdotdp->getNonconstMultiVector().ptr(), *dx_dotdp_init_);
317  nominal.set_x_dot(xdot);
318  }
319 
320  // Set initial xdotdot. If dx_dotdotdp_init == null, set initial dxdotdot/dp
321  // = 0
322  if (me_nominal.supports(MEB::IN_ARG_x_dot_dot)) {
323  RCP<Thyra::VectorBase<Scalar> > xdotdot = Thyra::createMember(*dxdp_space_);
324  RCP<DMVPV> dxdotdotdp = rcp_dynamic_cast<DMVPV>(xdotdot, true);
325  if (dx_dotdotdp_init_ == Teuchos::null)
326  Thyra::assign(dxdotdotdp->getNonconstMultiVector().ptr(), zero);
327  else
328  Thyra::assign(dxdotdotdp->getNonconstMultiVector().ptr(),
329  *dx_dotdotdp_init_);
330  nominal.set_x_dot_dot(xdotdot);
331  }
332 
333  const int np = model_->Np();
334  for (int i = 0; i < np; ++i) nominal.set_p(i, me_nominal.get_p(i));
335  return nominal;
336 }
337 
338 template <typename Scalar>
341 {
342  return prototypeOutArgs_;
343 }
344 
345 template <typename Scalar>
348  const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs) const
349 {
351  typedef Thyra::ModelEvaluatorBase MEB;
352  using Teuchos::RCP;
353  using Teuchos::rcp_dynamic_cast;
354 
355  // Interpolate forward solution at supplied time, reusing previous
356  // interpolation if possible
357  Scalar forward_t;
358  if (sh_ != Teuchos::null) {
359  forward_t = inArgs.get_t();
360  if (t_interp_ != forward_t) {
361  if (nc_forward_state_ == Teuchos::null)
362  nc_forward_state_ = sh_->interpolateState(forward_t);
363  else
364  sh_->interpolateState(forward_t, nc_forward_state_.get());
365  forward_state_ = nc_forward_state_;
366  t_interp_ = forward_t;
367  }
368  }
369  else {
370  TEUCHOS_ASSERT(forward_state_ != Teuchos::null);
371  forward_t = forward_state_->getTime();
372  }
373 
374  const bool use_tangent = use_dfdp_as_tangent_ || use_dgdp_as_tangent_;
375 
376  // setup input arguments for model
377  RCP<const Thyra::MultiVectorBase<Scalar> > dxdp, dxdotdp, dxdotdotdp;
378  MEB::InArgs<Scalar> me_inArgs = model_->getNominalValues();
379  dxdp = rcp_dynamic_cast<const DMVPV>(inArgs.get_x(), true)->getMultiVector();
380  me_inArgs.set_x(forward_state_->getX());
381  if (use_dfdp_as_tangent_) me_inArgs.set_p(x_tangent_index_, inArgs.get_x());
382  if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
383  if (inArgs.get_x_dot() != Teuchos::null) {
384  dxdotdp = rcp_dynamic_cast<const DMVPV>(inArgs.get_x_dot(), true)
385  ->getMultiVector();
386  me_inArgs.set_x_dot(forward_state_->getXDot());
387  if (use_dfdp_as_tangent_)
388  me_inArgs.set_p(xdot_tangent_index_, inArgs.get_x_dot());
389  }
390  else {
391  // clear out xdot if it was set in nominalValues to get to ensure we
392  // get the explicit form
393  me_inArgs.set_x_dot(Teuchos::null);
394  }
395  }
396  if (me_inArgs.supports(MEB::IN_ARG_x_dot_dot)) {
397  if (inArgs.get_x_dot_dot() != Teuchos::null) {
398  dxdotdotdp = rcp_dynamic_cast<const DMVPV>(inArgs.get_x_dot_dot(), true)
399  ->getMultiVector();
400  me_inArgs.set_x_dot_dot(forward_state_->getXDotDot());
401  if (use_dfdp_as_tangent_)
402  me_inArgs.set_p(xdotdot_tangent_index_, inArgs.get_x_dot_dot());
403  }
404  else // clear out xdotdot if it was set in nominalValues
405  me_inArgs.set_x_dot_dot(Teuchos::null);
406  }
407  if (me_inArgs.supports(MEB::IN_ARG_t)) me_inArgs.set_t(forward_t);
408  if (me_inArgs.supports(MEB::IN_ARG_alpha))
409  me_inArgs.set_alpha(inArgs.get_alpha());
410  if (me_inArgs.supports(MEB::IN_ARG_beta))
411  me_inArgs.set_beta(inArgs.get_beta());
412  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
413  me_inArgs.set_W_x_dot_dot_coeff(inArgs.get_W_x_dot_dot_coeff());
414 
415  // Set parameters -- be careful to only set ones that were set in our
416  // inArgs to not null out any specified through nominalValues or
417  // dx/dp above
418  const int np = me_inArgs.Np();
419  for (int i = 0; i < np; ++i) {
420  if (inArgs.get_p(i) != Teuchos::null)
421  if (!use_tangent ||
422  (use_tangent && i != x_tangent_index_ && i != xdot_tangent_index_ &&
423  i != xdotdot_tangent_index_))
424  me_inArgs.set_p(i, inArgs.get_p(i));
425  }
426 
427  // setup output arguments for model
428  RCP<Thyra::MultiVectorBase<Scalar> > dfdp;
429  MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
430  if (outArgs.get_f() != Teuchos::null) {
431  dfdp = rcp_dynamic_cast<DMVPV>(outArgs.get_f(), true)
432  ->getNonconstMultiVector();
433  if (!residual_sensitivity_is_computed_) {
434  if (!use_dfdp_as_tangent_ && is_pseudotransient_) {
435  if (my_dfdp_ == Teuchos::null)
436  my_dfdp_ = Thyra::createMembers(model_->get_f_space(),
437  model_->get_p_space(p_index_)->dim());
438  me_outArgs.set_DfDp(p_index_, my_dfdp_);
439  }
440  else
441  me_outArgs.set_DfDp(p_index_, dfdp);
442  }
443  }
444  if (outArgs.supports(MEB::OUT_ARG_W_op) && lo_ == Teuchos::null &&
445  outArgs.get_W_op() != Teuchos::null &&
446  model_.ptr() == sens_solve_model_.ptr()) {
447  RCP<Thyra::LinearOpBase<Scalar> > op = outArgs.get_W_op();
448  RCP<Thyra::MultiVectorLinearOp<Scalar> > mv_op =
449  rcp_dynamic_cast<Thyra::MultiVectorLinearOp<Scalar> >(op, true);
450  me_outArgs.set_W_op(mv_op->getNonconstLinearOp());
451  }
452  for (int j = g_offset_; j < outArgs.Ng(); ++j) {
453  me_outArgs.set_g(j - g_offset_, outArgs.get_g(j));
454  if (!me_outArgs.supports(MEB::OUT_ARG_DgDx_dot, j - g_offset_).none())
455  me_outArgs.set_DgDx_dot(j - g_offset_, outArgs.get_DgDx_dot(j));
456  if (!me_outArgs.supports(MEB::OUT_ARG_DgDx, j - g_offset_).none())
457  me_outArgs.set_DgDx(j - g_offset_, outArgs.get_DgDx(j));
458  for (int l = 0; l < outArgs.Np(); ++l)
459  if (!me_outArgs.supports(MEB::OUT_ARG_DgDp, j - g_offset_, l).none())
460  me_outArgs.set_DgDp(j - g_offset_, l, outArgs.get_DgDp(j, l));
461  }
462  if (g_index_ >= 0 && outArgs.get_g(1) != Teuchos::null)
463  me_outArgs.set_g(g_index_, outArgs.get_g(1));
464 
465  // build residual and jacobian
466  model_->evalModel(me_inArgs, me_outArgs);
467 
468  // Compute W_op separately if we have a separate sensitivity solve ME
469  if (outArgs.supports(MEB::OUT_ARG_W_op) && lo_ == Teuchos::null &&
470  outArgs.get_W_op() != Teuchos::null &&
471  model_.ptr() != sens_solve_model_.ptr()) {
472  MEB::OutArgs<Scalar> sens_me_outArgs = sens_solve_model_->createOutArgs();
473  RCP<Thyra::LinearOpBase<Scalar> > op = outArgs.get_W_op();
474  RCP<Thyra::MultiVectorLinearOp<Scalar> > mv_op =
475  rcp_dynamic_cast<Thyra::MultiVectorLinearOp<Scalar> >(op, true);
476  sens_me_outArgs.set_W_op(mv_op->getNonconstLinearOp());
477  sens_solve_model_->evalModel(me_inArgs, sens_me_outArgs);
478  }
479 
480  // Compute (df/dx) * (dx/dp) + (df/dxdot) * (dxdot/dp) + (df/dxdotdot) *
481  // (dxdotdot/dp) + (df/dp) if the underlying ME doesn't already do this. This
482  // requires computing df/dx, df/dxdot, df/dxdotdot as separate operators. For
483  // pseudo-transient, we would like to reuse these operators, but this is
484  // complicated when steppers use both implicit and explicit forms.
485  if (!use_dfdp_as_tangent_) {
486  if (dfdp != Teuchos::null && is_pseudotransient_) {
487  residual_sensitivity_is_computed_ = true;
488  Thyra::assign(dfdp.ptr(), *my_dfdp_);
489  }
490  if (dxdp != Teuchos::null && dfdp != Teuchos::null) {
491  if (my_dfdx_ == Teuchos::null)
492  my_dfdx_ = sens_residual_model_->create_W_op();
493  if (!jacobian_matrix_is_computed_) {
494  MEB::OutArgs<Scalar> meo = sens_residual_model_->createOutArgs();
495  meo.set_W_op(my_dfdx_);
496  if (me_inArgs.supports(MEB::IN_ARG_alpha)) me_inArgs.set_alpha(0.0);
497  if (me_inArgs.supports(MEB::IN_ARG_beta)) me_inArgs.set_beta(1.0);
498  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
499  me_inArgs.set_W_x_dot_dot_coeff(0.0);
500  sens_residual_model_->evalModel(me_inArgs, meo);
501  if (is_pseudotransient_) jacobian_matrix_is_computed_ = true;
502  }
503  my_dfdx_->apply(Thyra::NOTRANS, *dxdp, dfdp.ptr(), Scalar(1.0),
504  Scalar(1.0));
505  }
506  if (dxdotdp != Teuchos::null && dfdp != Teuchos::null) {
507  if (my_dfdxdot_ == Teuchos::null)
508  my_dfdxdot_ = sens_residual_model_->create_W_op();
509  if (!mass_matrix_is_computed_) {
510  MEB::OutArgs<Scalar> meo = sens_residual_model_->createOutArgs();
511  meo.set_W_op(my_dfdxdot_);
512  if (me_inArgs.supports(MEB::IN_ARG_alpha)) me_inArgs.set_alpha(1.0);
513  if (me_inArgs.supports(MEB::IN_ARG_beta)) me_inArgs.set_beta(0.0);
514  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
515  me_inArgs.set_W_x_dot_dot_coeff(0.0);
516  sens_residual_model_->evalModel(me_inArgs, meo);
517  if (is_pseudotransient_) mass_matrix_is_computed_ = true;
518  }
519  my_dfdxdot_->apply(Thyra::NOTRANS, *dxdotdp, dfdp.ptr(), Scalar(1.0),
520  Scalar(1.0));
521  }
522  if (dxdotdotdp != Teuchos::null && dfdp != Teuchos::null) {
523  if (my_dfdxdotdot_ == Teuchos::null)
524  my_dfdxdotdot_ = sens_residual_model_->create_W_op();
525  if (!acceleration_matrix_is_computed_) {
526  MEB::OutArgs<Scalar> meo = sens_residual_model_->createOutArgs();
527  meo.set_W_op(my_dfdxdotdot_);
528  if (me_inArgs.supports(MEB::IN_ARG_alpha)) me_inArgs.set_alpha(0.0);
529  if (me_inArgs.supports(MEB::IN_ARG_beta)) me_inArgs.set_beta(0.0);
530  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
531  me_inArgs.set_W_x_dot_dot_coeff(1.0);
532  sens_residual_model_->evalModel(me_inArgs, meo);
533  if (is_pseudotransient_) acceleration_matrix_is_computed_ = true;
534  }
535  my_dfdxdotdot_->apply(Thyra::NOTRANS, *dxdotdotdp, dfdp.ptr(),
536  Scalar(1.0), Scalar(1.0));
537  }
538  }
539 
540  if (g_index_ >= 0 && outArgs.get_g(0) != Teuchos::null) {
541  MEB::OutArgs<Scalar> meo = model_->createOutArgs();
542  RCP<Thyra::MultiVectorBase<Scalar> > dgdp =
543  rcp_dynamic_cast<DMVPV>(outArgs.get_g(0), true)
544  ->getNonconstMultiVector();
545  RCP<Thyra::MultiVectorBase<Scalar> > dgdp_trans;
546  MEB::DerivativeSupport dgdp_support =
547  meo.supports(MEB::OUT_ARG_DgDp, g_index_, p_index_);
548  if (dgdp_support.supports(MEB::DERIV_MV_JACOBIAN_FORM))
549  meo.set_DgDp(g_index_, p_index_,
550  MEB::Derivative<Scalar>(dgdp, MEB::DERIV_MV_JACOBIAN_FORM));
551  else if (dgdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
552  dgdp_trans = createMembers(model_->get_p_space(p_index_), num_response_);
553  meo.set_DgDp(
554  g_index_, p_index_,
555  MEB::Derivative<Scalar>(dgdp_trans, MEB::DERIV_MV_GRADIENT_FORM));
556  }
557  else
559  true, std::logic_error,
560  "Operator form of dg/dp not supported for reduced sensitivity");
561 
562  if (!use_dgdp_as_tangent_ || dxdp == Teuchos::null) {
563  MEB::DerivativeSupport dgdx_support =
564  meo.supports(MEB::OUT_ARG_DgDx, g_index_);
565  if (dgdx_support.supports(MEB::DERIV_LINEAR_OP)) {
566  if (my_dgdx_ == Teuchos::null)
567  my_dgdx_ = model_->create_DgDx_op(g_index_);
568  meo.set_DgDx(g_index_, my_dgdx_);
569  }
570  else if (dgdx_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
571  if (my_dgdx_mv_ == Teuchos::null)
572  my_dgdx_mv_ =
573  createMembers(model_->get_g_space(g_index_), num_param_);
574  meo.set_DgDx(g_index_, MEB::Derivative<Scalar>(
575  my_dgdx_mv_, MEB::DERIV_MV_GRADIENT_FORM));
576  }
577  else
579  true, std::logic_error,
580  "Jacobian form of dg/dx not supported for reduced sensitivity");
581  }
582 
583  // Clear dx/dp, dxdot/dp, dxdotdot/dp from inArgs if set and we are not
584  // using dg/dp as the tangent. Note, even though dxdp, dxdotdp, and
585  // dxdotdotdp are not used here, they are non-null if x/xdot/xdotdot are
586  // supported and supplied.
587  if (!use_dgdp_as_tangent_ && use_dfdp_as_tangent_ && dxdp != Teuchos::null)
588  me_inArgs.set_p(x_tangent_index_, Teuchos::null);
589  if (!use_dgdp_as_tangent_ && use_dfdp_as_tangent_ &&
590  dxdotdp != Teuchos::null)
591  me_inArgs.set_p(xdot_tangent_index_, Teuchos::null);
592  if (!use_dgdp_as_tangent_ && use_dfdp_as_tangent_ &&
593  dxdotdotdp != Teuchos::null)
594  me_inArgs.set_p(xdotdot_tangent_index_, Teuchos::null);
595 
596  // Set dx/dp, dxdot/dp, dxdodot/dp if necessary
597  if (use_dgdp_as_tangent_ && !use_dfdp_as_tangent_ && dxdp != Teuchos::null)
598  me_inArgs.set_p(x_tangent_index_, inArgs.get_x());
599  if (use_dgdp_as_tangent_ && !use_dfdp_as_tangent_ &&
600  dxdotdp != Teuchos::null)
601  me_inArgs.set_p(xdot_tangent_index_, inArgs.get_x_dot());
602  if (use_dgdp_as_tangent_ && !use_dfdp_as_tangent_ &&
603  dxdotdotdp != Teuchos::null)
604  me_inArgs.set_p(xdotdot_tangent_index_, inArgs.get_x_dot_dot());
605 
606  model_->evalModel(me_inArgs, meo);
607 
608  // transpose reduced dg/dp if necessary
609  if (dgdp_trans != Teuchos::null) {
611  Thyra::DetachedMultiVectorView<Scalar> dgdp_trans_view(*dgdp_trans);
612  for (int i = 0; i < num_param_; ++i)
613  for (int j = 0; j < num_response_; ++j)
614  dgdp_view(j, i) = dgdp_trans_view(i, j);
615  }
616 
617  // Compute (dg/dx) * (dx/dp) + (dg/dp) if the underlying ME doesn't already
618  // do this.
619  if (!use_dgdp_as_tangent_ && dxdp != Teuchos::null) {
620  MEB::DerivativeSupport dgdx_support =
621  me_outArgs.supports(MEB::OUT_ARG_DgDx, g_index_);
622  if (dgdx_support.supports(MEB::DERIV_LINEAR_OP)) {
623  my_dgdx_->apply(Thyra::NOTRANS, *dxdp, dgdp.ptr(), Scalar(1.0),
624  Scalar(1.0));
625  }
626  else if (dgdx_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
627  my_dgdx_mv_->apply(Thyra::TRANS, *dxdp, dgdp.ptr(), Scalar(1.0),
628  Scalar(1.0));
629  }
630  else
632  true, std::logic_error,
633  "Jacobian form of dg/dx not supported for reduced sensitivity");
634  }
635  }
636 }
637 
638 template <class Scalar>
641 {
642  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
643  pl->set<bool>("Use DfDp as Tangent", false);
644  pl->set<bool>("Use DgDp as Tangent", false);
645  pl->set<int>("Sensitivity Parameter Index", 0);
646  pl->set<int>("Response Function Index", -1);
647  pl->set<int>("Sensitivity X Tangent Index", 1);
648  pl->set<int>("Sensitivity X-Dot Tangent Index", 2);
649  pl->set<int>("Sensitivity X-Dot-Dot Tangent Index", 3);
650  return pl;
651 }
652 
653 } // namespace Tempus
654 
655 #endif
RCP< const VectorBase< Scalar > > get_x_dot() const
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
void setForwardSolutionHistory(const Teuchos::RCP< const Tempus::SolutionHistory< Scalar > > &sh)
Set solution history from forward state evaluation (for interpolation)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual void setForwardSolutionState(const Teuchos::RCP< const Tempus::SolutionState< Scalar > > &s)
Set solution state from forward state evaluation (for frozen state)
Evaluation< VectorBase< Scalar > > get_g(int j) const
Teuchos::RCP< const Teuchos::Array< std::string > > get_p_names(int p) const
Evaluation< VectorBase< Scalar > > get_f() const
bool supports(EOutArgsMembers arg) const
static magnitudeType rmax()
Derivative< Scalar > get_DgDp(int j, int l) const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int p) const
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_DgDx_dot_op(int j) const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual std::string description() const
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_DgDp_op(int j, int l) const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_x_space() const
Implicit concrete LinearOpBase subclass that takes a flattended out multi-vector and performs a multi...
size_type size() const
Teuchos::RCP< const Thyra::LinearOpWithSolveFactoryBase< Scalar > > get_W_factory() const
Derivative< Scalar > get_DgDx_dot(int j) const
RCP< const VectorBase< Scalar > > get_x_dot_dot() const
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_DgDx_op(int j) const
#define TEUCHOS_ASSERT(assertion_test)
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_f_space() const
RCP< LinearOpBase< Scalar > > get_W_op() const
RCP< const VectorBase< Scalar > > get_x() const
StaggeredForwardSensitivityModelEvaluator(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &model, const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &sens_residual_model, const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &sens_solve_model, const bool is_pseudotransient, const Teuchos::RCP< const Teuchos::ParameterList > &pList=Teuchos::null, const Teuchos::RCP< MultiVector > &dxdp_init=Teuchos::null, const Teuchos::RCP< MultiVector > &dx_dotdp_init=Teuchos::null, const Teuchos::RCP< MultiVector > &dx_dotdot_dp_init=Teuchos::null)
Constructor.
Solution state for integrators and steppers.
RCP< const VectorBase< Scalar > > get_p(int l) const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_g_space(int j) const
void evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs) const
Derivative< Scalar > get_DgDx(int j) const