Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_CombinedForwardSensitivityModelEvaluator_impl.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ****************************************************************************
3 // Tempus: Copyright (2017) Sandia Corporation
4 //
5 // Distributed under BSD 3-clause license (See accompanying file Copyright.txt)
6 // ****************************************************************************
7 // @HEADER
8 
9 #ifndef Tempus_CombinedForwardSensitivityModelEvaluator_impl_hpp
10 #define Tempus_CombinedForwardSensitivityModelEvaluator_impl_hpp
11 
12 #include "Thyra_DefaultMultiVectorProductVector.hpp"
16 #include "Thyra_VectorStdOps.hpp"
17 #include "Thyra_MultiVectorStdOps.hpp"
18 
19 namespace Tempus {
20 
21 template <typename Scalar>
24  const Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> > & model,
26  const Teuchos::RCP<MultiVector>& dxdp_init,
27  const Teuchos::RCP<MultiVector>& dx_dotdp_init,
28  const Teuchos::RCP<MultiVector>& dx_dotdotdp_init) :
29  model_(model),
30  dxdp_init_(dxdp_init),
31  dx_dotdp_init_(dx_dotdp_init),
32  dx_dotdotdp_init_(dx_dotdotdp_init),
33  p_index_(0),
34  x_tangent_index_(1),
35  xdot_tangent_index_(2),
36  xdotdot_tangent_index_(3),
37  use_dfdp_as_tangent_(false)
38 {
39  typedef Thyra::ModelEvaluatorBase MEB;
40 
41  // Set parameters
44  if (pList != Teuchos::null)
45  *pl = *pList;
47  use_dfdp_as_tangent_ = pl->get<bool>("Use DfDp as Tangent");
48  p_index_ = pl->get<int>("Sensitivity Parameter Index");
49  x_tangent_index_ = pl->get<int>("Sensitivity X Tangent Index");
50  xdot_tangent_index_ = pl->get<int>("Sensitivity X-Dot Tangent Index");
51  xdotdot_tangent_index_ = pl->get<int>("Sensitivity X-Dot-Dot Tangent Index");
52 
53  num_param_ = model_->get_p_space(p_index_)->dim();
54  dxdp_space_ =
55  Thyra::multiVectorProductVectorSpace(model_->get_x_space(), num_param_);
57  Thyra::multiVectorProductVectorSpace(model_->get_x_space(), num_param_+1);
58  dfdp_space_ =
59  Thyra::multiVectorProductVectorSpace(model_->get_f_space(), num_param_);
61  Thyra::multiVectorProductVectorSpace(model_->get_f_space(), num_param_+1);
62 
63  MEB::InArgs<Scalar> me_inArgs = model_->createInArgs();
64  MEB::InArgsSetup<Scalar> inArgs;
65  inArgs.setModelEvalDescription(this->description());
66  inArgs.setSupports(MEB::IN_ARG_x);
67  if (me_inArgs.supports(MEB::IN_ARG_x_dot))
68  inArgs.setSupports(MEB::IN_ARG_x_dot);
69  if (me_inArgs.supports(MEB::IN_ARG_t))
70  inArgs.setSupports(MEB::IN_ARG_t);
71  if (me_inArgs.supports(MEB::IN_ARG_alpha))
72  inArgs.setSupports(MEB::IN_ARG_alpha);
73  if (me_inArgs.supports(MEB::IN_ARG_beta))
74  inArgs.setSupports(MEB::IN_ARG_beta);
75  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
76  inArgs.setSupports(MEB::IN_ARG_W_x_dot_dot_coeff);
77 
78  // Support additional parameters for x and xdot
79  inArgs.set_Np(me_inArgs.Np());
80  prototypeInArgs_ = inArgs;
81 
82  MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
83  MEB::OutArgsSetup<Scalar> outArgs;
84  outArgs.setModelEvalDescription(this->description());
85  outArgs.set_Np_Ng(me_outArgs.Np(),me_outArgs.Ng());
86  outArgs.setSupports(MEB::OUT_ARG_f);
87  if (me_outArgs.supports(MEB::OUT_ARG_W_op))
88  outArgs.setSupports(MEB::OUT_ARG_W_op);
89  for (int j=0; j<me_outArgs.Ng(); ++j) {
90  outArgs.setSupports(MEB::OUT_ARG_DgDx_dot, j,
91  me_outArgs.supports(MEB::OUT_ARG_DgDx_dot, j));
92  outArgs.setSupports(MEB::OUT_ARG_DgDx, j,
93  me_outArgs.supports(MEB::OUT_ARG_DgDx, j));
94  for (int l=0; l<me_outArgs.Np(); ++l) {
95  outArgs.setSupports(MEB::OUT_ARG_DgDp, j, l,
96  me_outArgs.supports(MEB::OUT_ARG_DgDp, j, l));
97  }
98  }
99  prototypeOutArgs_ = outArgs;
100 
101  TEUCHOS_ASSERT(me_outArgs.supports(MEB::OUT_ARG_DfDp, p_index_).supports(MEB::DERIV_MV_JACOBIAN_FORM));
103  TEUCHOS_ASSERT(me_outArgs.supports(MEB::OUT_ARG_W_op));
104 }
105 
106 template <typename Scalar>
109 get_p_space(int p) const
110 {
111  return model_->get_p_space(p);
112 }
113 
114 template <typename Scalar>
117 get_p_names(int p) const
118 {
119  return model_->get_p_names(p);
120 }
121 
122 template <typename Scalar>
125 get_x_space() const
126 {
127  return x_dxdp_space_;
128 }
129 
130 template <typename Scalar>
133 get_f_space() const
134 {
135  return f_dfdp_space_;
136 }
137 
138 template <typename Scalar>
141 get_g_space(int j) const
142 {
143  return model_->get_g_space(j);
144 }
145 
146 template <typename Scalar>
149 get_g_names(int j) const
150 {
151  return model_->get_g_names(j);
152 }
153 
154 template <typename Scalar>
157 create_W_op() const
158 {
159  Teuchos::RCP<Thyra::LinearOpBase<Scalar> > op = model_->create_W_op();
160  return Thyra::nonconstMultiVectorLinearOp(op, num_param_+1);
161 }
162 
163 template <typename Scalar>
166 create_DgDx_dot_op(int j) const
167 {
168  return model_->create_DgDx_dot_op(j);
169 }
170 
171 template <typename Scalar>
174 create_DgDx_op(int j) const
175 {
176  return model_->create_DgDx_op(j);
177 }
178 
179 template <typename Scalar>
182 create_DgDp_op(int j, int l) const
183 {
184  return model_->create_DgDp_op(j,l);
185 }
186 
187 template <typename Scalar>
191 {
193  model_->get_W_factory();
194  if (factory == Teuchos::null)
195  return Teuchos::null; // model_ doesn't support W_factory
196 
197  return Thyra::multiVectorLinearOpWithSolveFactory(factory,
198  f_dfdp_space_,
199  x_dxdp_space_);
200 }
201 
202 template <typename Scalar>
206 {
207  return prototypeInArgs_;
208 }
209 
210 template <typename Scalar>
214 {
215  typedef Thyra::ModelEvaluatorBase MEB;
217  using Teuchos::RCP;
218  using Teuchos::rcp_dynamic_cast;
219  using Teuchos::Range1D;
220 
221  MEB::InArgs<Scalar> me_nominal = model_->getNominalValues();
222  MEB::InArgs<Scalar> nominal = this->createInArgs();
223 
224  const Teuchos::Range1D rng(1,num_param_);
225  const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
226 
227  // Set initial x. If dxdp_init == null, set initial dx/dp = 0
228  RCP< const Thyra::VectorBase<Scalar> > me_x = me_nominal.get_x();
229  if (me_x != Teuchos::null) {
230  RCP< Thyra::VectorBase<Scalar> > x = Thyra::createMember(*x_dxdp_space_);
231  RCP<DMVPV> x_dxdp = rcp_dynamic_cast<DMVPV>(x,true);
232  Thyra::assign(x_dxdp->getNonconstMultiVector()->col(0).ptr(), *me_x);
233  if (dxdp_init_ == Teuchos::null)
234  Thyra::assign(x_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
235  zero);
236  else
237  Thyra::assign(x_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
238  *dxdp_init_);
239  nominal.set_x(x);
240  }
241 
242  // Set initial xdot. If dx_dotdp_init == null, set initial dxdot/dp = 0
243  RCP< const Thyra::VectorBase<Scalar> > me_xdot;
244  if (me_nominal.supports(MEB::IN_ARG_x_dot))
245  me_xdot = me_nominal.get_x_dot();
246  if (me_xdot != Teuchos::null) {
247  RCP< Thyra::VectorBase<Scalar> > xdot = Thyra::createMember(*x_dxdp_space_);
248  RCP<DMVPV> xdot_dxdp = rcp_dynamic_cast<DMVPV>(xdot,true);
249  Thyra::assign(xdot_dxdp->getNonconstMultiVector()->col(0).ptr(), *me_xdot);
250  if (dx_dotdp_init_ == Teuchos::null)
251  Thyra::assign(xdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
252  zero);
253  else
254  Thyra::assign(xdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
255  *dx_dotdp_init_);
256  nominal.set_x_dot(xdot);
257  }
258 
259  // Set initial xdotdot. If dx_dotdotdp_init == null, set initial dxdotdot/dp = 0
260  RCP< const Thyra::VectorBase<Scalar> > me_xdotdot;
261  if (me_nominal.supports(MEB::IN_ARG_x_dot_dot))
262  me_xdotdot = me_nominal.get_x_dot_dot();
263  if (me_xdotdot != Teuchos::null) {
264  RCP< Thyra::VectorBase<Scalar> > xdotdot =
265  Thyra::createMember(*x_dxdp_space_);
266  RCP<DMVPV> xdotdot_dxdp = rcp_dynamic_cast<DMVPV>(xdotdot,true);
267  Thyra::assign(xdotdot_dxdp->getNonconstMultiVector()->col(0).ptr(), *me_xdotdot);
268  if (dx_dotdotdp_init_ == Teuchos::null)
269  Thyra::assign(xdotdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
270  zero);
271  else
272  Thyra::assign(xdotdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
273  *dx_dotdotdp_init_);
274  nominal.set_x_dot_dot(xdotdot);
275  }
276 
277  const int np = model_->Np();
278  for (int i=0; i<np; ++i)
279  nominal.set_p(i, me_nominal.get_p(i));
280 
281  return nominal;
282 }
283 
284 template <typename Scalar>
288 {
289  return prototypeOutArgs_;
290 }
291 
292 template <typename Scalar>
293 void
296  const Thyra::ModelEvaluatorBase::OutArgs<Scalar> &outArgs) const
297 {
298  typedef Thyra::ModelEvaluatorBase MEB;
300  using Teuchos::RCP;
301  using Teuchos::rcp_dynamic_cast;
302  using Teuchos::Range1D;
303 
304  // setup input arguments for model
305  RCP< const Thyra::VectorBase<Scalar> > x, xdot, xdotdot;
306  RCP< const Thyra::MultiVectorBase<Scalar> > dxdp, dxdotdp, dxdotdotdp;
307  MEB::InArgs<Scalar> me_inArgs = model_->getNominalValues();
308  RCP<const DMVPV> x_dxdp = rcp_dynamic_cast<const DMVPV>(inArgs.get_x(),true);
309  x = x_dxdp->getMultiVector()->col(0);
310  dxdp = x_dxdp->getMultiVector()->subView(Range1D(1,num_param_));
311  me_inArgs.set_x(x);
312  if (use_dfdp_as_tangent_) {
313  RCP< const Thyra::VectorBase<Scalar> > dxdp_vec =
314  Thyra::multiVectorProductVector(dxdp_space_, dxdp);
315  me_inArgs.set_p(x_tangent_index_, dxdp_vec);
316  }
317  if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
318  if (inArgs.get_x_dot() != Teuchos::null) {
319  RCP<const DMVPV> xdot_dxdotdp =
320  rcp_dynamic_cast<const DMVPV>(inArgs.get_x_dot(),true);
321  xdot = xdot_dxdotdp->getMultiVector()->col(0);
322  dxdotdp = xdot_dxdotdp->getMultiVector()->subView(Range1D(1,num_param_));
323  me_inArgs.set_x_dot(xdot);
324  if (use_dfdp_as_tangent_) {
325  RCP< const Thyra::VectorBase<Scalar> > dxdotdp_vec =
326  Thyra::multiVectorProductVector(dxdp_space_, dxdotdp);
327  me_inArgs.set_p(xdot_tangent_index_, dxdotdp_vec);
328  }
329  }
330  else // clear out xdot if it was set in nominalValues
331  me_inArgs.set_x_dot(Teuchos::null);
332  }
333  if (me_inArgs.supports(MEB::IN_ARG_x_dot_dot)) {
334  if (inArgs.get_x_dot_dot() != Teuchos::null) {
335  RCP<const DMVPV> xdotdot_dxdotdotdp =
336  rcp_dynamic_cast<const DMVPV>(inArgs.get_x_dot_dot(),true);
337  xdotdot = xdotdot_dxdotdotdp->getMultiVector()->col(0);
338  dxdotdotdp = xdotdot_dxdotdotdp->getMultiVector()->subView(Range1D(1,num_param_));
339  me_inArgs.set_x_dot_dot(xdotdot);
340  if (use_dfdp_as_tangent_) {
341  RCP< const Thyra::VectorBase<Scalar> > dxdotdotdp_vec =
342  Thyra::multiVectorProductVector(dxdp_space_, dxdotdotdp);
343  me_inArgs.set_p(xdotdot_tangent_index_, dxdotdotdp_vec);
344  }
345  }
346  else // clear out xdotdot if it was set in nominalValues
347  me_inArgs.set_x_dot_dot(Teuchos::null);
348  }
349  if (me_inArgs.supports(MEB::IN_ARG_t))
350  me_inArgs.set_t(inArgs.get_t());
351  if (me_inArgs.supports(MEB::IN_ARG_alpha))
352  me_inArgs.set_alpha(inArgs.get_alpha());
353  if (me_inArgs.supports(MEB::IN_ARG_beta))
354  me_inArgs.set_beta(inArgs.get_beta());
355  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
356  me_inArgs.set_W_x_dot_dot_coeff(inArgs.get_W_x_dot_dot_coeff());
357 
358  // Set parameters -- be careful to only set ones that were set in our
359  // inArgs to not null out any specified through nominalValues or
360  // dx/dp above
361  const int np = me_inArgs.Np();
362  for (int i=0; i<np; ++i) {
363  if (inArgs.get_p(i) != Teuchos::null)
364  if (!use_dfdp_as_tangent_ ||
365  (use_dfdp_as_tangent_ && i != x_tangent_index_ &&
366  i != xdot_tangent_index_ &&
367  i != xdotdot_tangent_index_ ))
368  me_inArgs.set_p(i, inArgs.get_p(i));
369  }
370 
371  // setup output arguments for model
372  RCP< Thyra::VectorBase<Scalar> > f;
373  RCP< Thyra::MultiVectorBase<Scalar> > dfdp;
374  MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
375  if (outArgs.get_f() != Teuchos::null) {
376  RCP<DMVPV> f_dfdp = rcp_dynamic_cast<DMVPV>(outArgs.get_f(),true);
377  f = f_dfdp->getNonconstMultiVector()->col(0);
378  dfdp = f_dfdp->getNonconstMultiVector()->subView(Range1D(1,num_param_));
379  me_outArgs.set_f(f);
380  me_outArgs.set_DfDp(p_index_, dfdp);
381  }
382  if (outArgs.get_W_op() != Teuchos::null) {
383  RCP< Thyra::LinearOpBase<Scalar> > op = outArgs.get_W_op();
384  RCP< Thyra::MultiVectorLinearOp<Scalar> > mv_op =
385  rcp_dynamic_cast< Thyra::MultiVectorLinearOp<Scalar> >(op,true);
386  me_outArgs.set_W_op(mv_op->getNonconstLinearOp());
387  }
388  for (int j=0; j<outArgs.Ng(); ++j) {
389  if (!me_outArgs.supports(MEB::OUT_ARG_DgDx_dot,j).none())
390  me_outArgs.set_DgDx_dot(j, outArgs.get_DgDx_dot(j));
391  if (!me_outArgs.supports(MEB::OUT_ARG_DgDx,j).none())
392  me_outArgs.set_DgDx(j, outArgs.get_DgDx(j));
393  for (int l=0; l<outArgs.Np(); ++l)
394  if (!me_outArgs.supports(MEB::OUT_ARG_DgDp,j,l).none())
395  me_outArgs.set_DgDp(j, l, outArgs.get_DgDp(j,l));
396  }
397 
398  // build residual and jacobian
399  model_->evalModel(me_inArgs, me_outArgs);
400 
401  // Compute (df/dx) * (dx/dp) + (df/dxdot) * (dxdot/dp) + (df/dxdotdot) * (dxdotdot/dp) + (df/dp)
402  // if the underlying ME doesn't already do this. This requires computing
403  // df/dx, df/dxdot, df/dxdotdot as separate operators
404  if (!use_dfdp_as_tangent_) {
405  if (dxdp != Teuchos::null && dfdp != Teuchos::null) {
406  if (my_dfdx_ == Teuchos::null)
407  my_dfdx_ = model_->create_W_op();
408  MEB::OutArgs<Scalar> meo = model_->createOutArgs();
409  meo.set_W_op(my_dfdx_);
410  if (me_inArgs.supports(MEB::IN_ARG_alpha))
411  me_inArgs.set_alpha(0.0);
412  if (me_inArgs.supports(MEB::IN_ARG_beta))
413  me_inArgs.set_beta(1.0);
414  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
415  me_inArgs.set_W_x_dot_dot_coeff(0.0);
416  model_->evalModel(me_inArgs, meo);
417  my_dfdx_->apply(Thyra::NOTRANS, *dxdp, dfdp.ptr(), Scalar(1.0), Scalar(1.0));
418  }
419  if (dxdotdp != Teuchos::null && dfdp != Teuchos::null) {
420  if (my_dfdxdot_ == Teuchos::null)
421  my_dfdxdot_ = model_->create_W_op();
422  MEB::OutArgs<Scalar> meo = model_->createOutArgs();
423  meo.set_W_op(my_dfdxdot_);
424  if (me_inArgs.supports(MEB::IN_ARG_alpha))
425  me_inArgs.set_alpha(1.0);
426  if (me_inArgs.supports(MEB::IN_ARG_beta))
427  me_inArgs.set_beta(0.0);
428  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
429  me_inArgs.set_W_x_dot_dot_coeff(0.0);
430  model_->evalModel(me_inArgs, meo);
431  my_dfdxdot_->apply(Thyra::NOTRANS, *dxdotdp, dfdp.ptr(), Scalar(1.0), Scalar(1.0));
432  }
433  if (dxdotdotdp != Teuchos::null && dfdp != Teuchos::null) {
434  if (my_dfdxdotdot_ == Teuchos::null)
435  my_dfdxdotdot_ = model_->create_W_op();
436  MEB::OutArgs<Scalar> meo = model_->createOutArgs();
437  meo.set_W_op(my_dfdxdotdot_);
438  if (me_inArgs.supports(MEB::IN_ARG_alpha))
439  me_inArgs.set_alpha(0.0);
440  if (me_inArgs.supports(MEB::IN_ARG_beta))
441  me_inArgs.set_beta(0.0);
442  if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
443  me_inArgs.set_W_x_dot_dot_coeff(1.0);
444  model_->evalModel(me_inArgs, meo);
445  my_dfdxdotdot_->apply(Thyra::NOTRANS, *dxdotdotdp, dfdp.ptr(), Scalar(1.0), Scalar(1.0));
446  }
447  }
448 }
449 
450 template<class Scalar>
454 {
455  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
456  pl->set<bool>("Use DfDp as Tangent", false);
457  pl->set<int>("Sensitivity Parameter Index", 0);
458  pl->set<int>("Sensitivity X Tangent Index", 1);
459  pl->set<int>("Sensitivity X-Dot Tangent Index", 2);
460  pl->set<int>("Sensitivity X-Dot-Dot Tangent Index", 3);
461  return pl;
462 }
463 
464 } // namespace Tempus
465 
466 #endif
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int p) const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_g_space(int j) const
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_DgDx_dot_op(int j) const
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)
Teuchos::RCP< const Thyra::DefaultMultiVectorProductVectorSpace< Scalar > > dxdp_space_
Teuchos::RCP< const Teuchos::Array< std::string > > get_p_names(int p) const
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_DgDp_op(int j, int l) const
Evaluation< VectorBase< Scalar > > get_f() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_x_space() const
Teuchos::RCP< const Thyra::DefaultMultiVectorProductVectorSpace< Scalar > > x_dxdp_space_
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_DgDx_op(int j) const
Derivative< Scalar > get_DgDp(int j, int l) const
Teuchos::RCP< const Thyra::DefaultMultiVectorProductVectorSpace< Scalar > > f_dfdp_space_
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs) const
virtual std::string description() const
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
Teuchos::RCP< const Thyra::DefaultMultiVectorProductVectorSpace< Scalar > > dfdp_space_
Teuchos::RCP< const Thyra::LinearOpWithSolveFactoryBase< Scalar > > get_W_factory() const
Implicit concrete LinearOpBase subclass that takes a flattended out multi-vector and performs a multi...
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_f_space() const
CombinedForwardSensitivityModelEvaluator(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &model, 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.
Derivative< Scalar > get_DgDx_dot(int j) const
RCP< const VectorBase< Scalar > > get_x_dot_dot() const
#define TEUCHOS_ASSERT(assertion_test)
RCP< LinearOpBase< Scalar > > get_W_op() const
RCP< const VectorBase< Scalar > > get_x() const
RCP< const VectorBase< Scalar > > get_p(int l) const
Teuchos::Range1D Range1D
Derivative< Scalar > get_DgDx(int j) const