Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Tempus_WrapperModelEvaluatorPairPartIMEX_CombinedFSA_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_ModelEvaluatorPairPartIMEX_CombinedFSA_impl_hpp
11 #define Tempus_ModelEvaluatorPairPartIMEX_CombinedFSA_impl_hpp
12 
13 #include "Thyra_VectorStdOps.hpp"
14 #include "Thyra_MultiVectorStdOps.hpp"
15 
16 namespace Tempus {
17 
18 template <typename Scalar>
22  Scalar> >& forwardModel,
24  : forwardModel_(forwardModel),
25  use_dfdp_as_tangent_(false),
26  y_tangent_index_(3)
27 {
28  using Teuchos::RCP;
29  using Teuchos::rcp;
30  using Thyra::multiVectorProductVectorSpace;
31 
32  RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
33  if (pList != Teuchos::null) *pl = *pList;
35  use_dfdp_as_tangent_ = pl->get<bool>("Use DfDp as Tangent");
36  y_tangent_index_ = pl->get<int>("Sensitivity Y Tangent Index");
37  pl->remove("Sensitivity Y Tangent Index");
38 
39  appExplicitModel_ = forwardModel_->getExplicitModel();
40  appImplicitModel_ = forwardModel_->getImplicitModel();
45 
46  const int y_param_index = forwardModel_->getParameterIndex();
47  const int sens_param_index = pl->get<int>("Sensitivity Parameter Index");
48  const int num_sens_param =
49  appImplicitModel_->get_p_space(sens_param_index)->dim();
50  RCP<const Thyra::VectorSpaceBase<Scalar> > explicit_y_space =
51  appImplicitModel_->get_p_space(y_param_index);
52  RCP<const Thyra::VectorSpaceBase<Scalar> > implicit_x_space =
53  appImplicitModel_->get_x_space();
55  multiVectorProductVectorSpace(explicit_y_space, num_sens_param + 1);
57  multiVectorProductVectorSpace(explicit_y_space, num_sens_param);
59  multiVectorProductVectorSpace(implicit_x_space, num_sens_param + 1);
60 
62  forwardModel_->getNumExplicitOnlyBlocks(), y_param_index);
63 }
64 
65 template <typename Scalar>
67 {
68  using Teuchos::RCP;
69  using Teuchos::rcp_dynamic_cast;
70 
71  this->useImplicitModel_ = true;
72  this->wrapperImplicitInArgs_ = this->createInArgs();
73  this->wrapperImplicitOutArgs_ = this->createOutArgs();
74  this->useImplicitModel_ = false;
75 
76  RCP<const Thyra::VectorBase<Scalar> > z =
77  this->explicitModel_->getNominalValues().get_x();
78 
79  // A Thyra::VectorSpace requirement
81  !(getIMEXVector(z)->space()->isCompatible(
82  *(this->implicitModel_->get_x_space()))),
83  std::logic_error,
84  "Error - WrapperModelEvaluatorPairIMEX_CombinedFSA::initialize()\n"
85  << " Explicit and Implicit vector x spaces are incompatible!\n"
86  << " Explicit vector x space = "
87  << *(getIMEXVector(z)->space())
88  << "\n Implicit vector x space = "
89  << *(this->implicitModel_->get_x_space()) << "\n");
90 
91  // Valid number of blocks?
92  const RCP<const DMVPV> z_dmvpv = rcp_dynamic_cast<const DMVPV>(z, true);
93  const RCP<const Thyra::MultiVectorBase<Scalar> > z_mv =
94  z_dmvpv->getMultiVector();
95  RCP<const PMVB> zPVector = rcp_dynamic_cast<const PMVB>(z_mv);
97  zPVector == Teuchos::null, std::logic_error,
98  "Error - WrapperModelEvaluatorPairPartIMEX_CombinedFSA::initialize()\n"
99  " was given a VectorBase that could not be cast to a\n"
100  " ProductVectorBase!\n");
101 
102  int numBlocks = zPVector->productSpace()->numBlocks();
103 
104  TEUCHOS_TEST_FOR_EXCEPTION(
105  !(0 <= this->numExplicitOnlyBlocks_ &&
106  this->numExplicitOnlyBlocks_ < numBlocks),
107  std::logic_error,
108  "Error - WrapperModelEvaluatorPairPartIMEX_CombinedFSA::initialize()\n"
109  "Invalid number of explicit-only blocks = "
110  << this->numExplicitOnlyBlocks_
111  << "\nShould be in the interval [0, numBlocks) = [0, "
112  << numBlocks << ")\n");
113 }
114 
115 template <typename Scalar>
118 {
119  if (this->useImplicitModel_) {
120  if (i == this->parameterIndex_)
121  return explicit_y_dydp_prod_space_;
122  else
123  return appImplicitModel_->get_p_space(i);
124  }
125 
126  return appExplicitModel_->get_p_space(i);
127 }
128 
129 template <typename Scalar>
132  const Teuchos::RCP<Thyra::VectorBase<Scalar> >& full) const
133 {
134  using Teuchos::RCP;
135  using Teuchos::rcp_dynamic_cast;
137  using Thyra::multiVectorProductVector;
138  using Thyra::VectorBase;
139 
140  // CombinedFSA ME stores vectors as DMVPV's. To extract the implicit
141  // part of the vector, cast it to DMVPV, extract the multi-vector,
142  // cast it to a product multi-vector, extract the IMEX block, then
143  // create a DMVPV from it.
144 
145  if (full == Teuchos::null) return Teuchos::null;
146 
147  if (this->numExplicitOnlyBlocks_ == 0) return full;
148 
149  const RCP<DMVPV> full_dmvpv = rcp_dynamic_cast<DMVPV>(full, true);
150  const RCP<MultiVectorBase<Scalar> > full_mv =
151  full_dmvpv->getNonconstMultiVector();
152  const RCP<PMVB> blk_full_mv = rcp_dynamic_cast<PMVB>(full_mv, true);
153 
154  // special case where the implicit terms are not blocked
155  const int numBlocks = blk_full_mv->productSpace()->numBlocks();
156  const int numExplicitBlocks = this->numExplicitOnlyBlocks_;
157  if (numBlocks == numExplicitBlocks + 1) {
158  const RCP<MultiVectorBase<Scalar> > imex_mv =
159  blk_full_mv->getNonconstMultiVectorBlock(numExplicitBlocks);
160  return multiVectorProductVector(imex_x_dxdp_prod_space_, imex_mv);
161  }
162 
163  // Not supposed to get here, apparently
164  TEUCHOS_ASSERT(false);
165  return Teuchos::null;
166 }
167 
168 template <typename Scalar>
171  const Teuchos::RCP<const Thyra::VectorBase<Scalar> >& full) const
172 {
173  using Teuchos::RCP;
174  using Teuchos::rcp_dynamic_cast;
176  using Thyra::multiVectorProductVector;
177  using Thyra::VectorBase;
178 
179  // CombinedFSA ME stores vectors as DMVPV's. To extract the implicit
180  // part of the vector, cast it to DMVPV, extract the multi-vector,
181  // cast it to a product multi-vector, extract the IMEX block, then
182  // create a DMVPV from it.
183 
184  if (full == Teuchos::null) return Teuchos::null;
185 
186  if (this->numExplicitOnlyBlocks_ == 0) return full;
187 
188  const RCP<const DMVPV> full_dmvpv = rcp_dynamic_cast<const DMVPV>(full, true);
189  const RCP<const MultiVectorBase<Scalar> > full_mv =
190  full_dmvpv->getMultiVector();
191  const RCP<const PMVB> blk_full_mv =
192  rcp_dynamic_cast<const PMVB>(full_mv, true);
193 
194  // special case where the implicit terms are not blocked
195  const int numBlocks = blk_full_mv->productSpace()->numBlocks();
196  const int numExplicitBlocks = this->numExplicitOnlyBlocks_;
197  if (numBlocks == numExplicitBlocks + 1) {
198  const RCP<const MultiVectorBase<Scalar> > imex_mv =
199  blk_full_mv->getMultiVectorBlock(numExplicitBlocks);
200  return multiVectorProductVector(imex_x_dxdp_prod_space_, imex_mv);
201  }
202 
203  // Not supposed to get here, apparently
204  TEUCHOS_ASSERT(false);
205  return Teuchos::null;
206 }
207 
208 template <typename Scalar>
211  const Teuchos::RCP<Thyra::VectorBase<Scalar> >& full) const
212 {
213  using Teuchos::RCP;
214  using Teuchos::rcp_dynamic_cast;
216  using Thyra::multiVectorProductVector;
217  using Thyra::multiVectorProductVectorSpace;
218  using Thyra::VectorBase;
219 
220  // CombinedFSA ME stores vectors as DMVPV's. To extract the explicit
221  // part of the vector, cast it to DMVPV, extract the multi-vector,
222  // cast it to a product multi-vector, extract the explicit block, then
223  // create a DMVPV from it.
224 
225  if (full == Teuchos::null) return Teuchos::null;
226 
227  if (this->numExplicitOnlyBlocks_ == 0) return full;
228 
229  const RCP<DMVPV> full_dmvpv = rcp_dynamic_cast<DMVPV>(full, true);
230  const RCP<MultiVectorBase<Scalar> > full_mv =
231  full_dmvpv->getNonconstMultiVector();
232  const RCP<PMVB> blk_full_mv = rcp_dynamic_cast<PMVB>(full_mv, true);
233 
234  // special case where the explicit terms are not blocked
235  const int numExplicitBlocks = this->numExplicitOnlyBlocks_;
236  if (numExplicitBlocks == 1) {
237  const RCP<MultiVectorBase<Scalar> > explicit_mv =
238  blk_full_mv->getNonconstMultiVectorBlock(0);
239  return multiVectorProductVector(explicit_y_dydp_prod_space_, explicit_mv);
240  }
241 
242  // Not supposed to get here, apparently
243  TEUCHOS_ASSERT(false);
244  return Teuchos::null;
245 }
246 
247 template <typename Scalar>
250  const Teuchos::RCP<const Thyra::VectorBase<Scalar> >& full) const
251 {
252  using Teuchos::RCP;
253  using Teuchos::rcp_dynamic_cast;
255  using Thyra::multiVectorProductVector;
256  using Thyra::multiVectorProductVectorSpace;
257  using Thyra::VectorBase;
258 
259  // CombinedFSA ME stores vectors as DMVPV's. To extract the explicit
260  // part of the vector, cast it to DMVPV, extract the multi-vector,
261  // cast it to a product multi-vector, extract the explicit block, then
262  // create a DMVPV from it.
263 
264  if (full == Teuchos::null) return Teuchos::null;
265 
266  if (this->numExplicitOnlyBlocks_ == 0) return full;
267 
268  const RCP<const DMVPV> full_dmvpv = rcp_dynamic_cast<const DMVPV>(full, true);
269  const RCP<const MultiVectorBase<Scalar> > full_mv =
270  full_dmvpv->getMultiVector();
271  const RCP<const PMVB> blk_full_mv =
272  rcp_dynamic_cast<const PMVB>(full_mv, true);
273 
274  // special case where the explicit terms are not blocked
275  const int numExplicitBlocks = this->numExplicitOnlyBlocks_;
276  if (numExplicitBlocks == 1) {
277  const RCP<const MultiVectorBase<Scalar> > explicit_mv =
278  blk_full_mv->getMultiVectorBlock(0);
279  return multiVectorProductVector(explicit_y_dydp_prod_space_, explicit_mv);
280  }
281 
282  // Not supposed to get here, apparently
283  TEUCHOS_ASSERT(false);
284  return Teuchos::null;
285 }
286 
287 template <typename Scalar>
290 {
291  return forwardModel_;
292 }
293 
294 template <typename Scalar>
297 {
298  using Teuchos::RCP;
299  using Teuchos::rcp_dynamic_cast;
300  using Thyra::createMember;
301 
302  Thyra::ModelEvaluatorBase::InArgs<Scalar> inArgs = Base::createInArgs();
303 
304  // Set p to be the correct product vector form for the explicit only vector y
305  if (this->useImplicitModel_ == true) {
306  RCP<const Thyra::VectorBase<Scalar> > y =
307  inArgs.get_p(this->parameterIndex_);
308  if (y != Teuchos::null) {
309  RCP<DMVPV> y_dydp =
310  rcp_dynamic_cast<DMVPV>(createMember(*explicit_y_dydp_prod_space_));
311  Thyra::assign(y_dydp->getNonconstMultiVector().ptr(), Scalar(0.0));
312  Thyra::assign(y_dydp->getNonconstMultiVector()->col(0).ptr(), *y);
313  inArgs.set_p(this->parameterIndex_, y_dydp);
314  }
315  }
316  return inArgs;
317 }
318 
319 template <typename Scalar>
322  const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs) const
323 {
324  typedef Thyra::ModelEvaluatorBase MEB;
325  using Teuchos::Range1D;
326  using Teuchos::RCP;
327  using Teuchos::rcp_dynamic_cast;
328 
329  const int p_index = this->parameterIndex_;
330 
331  //
332  // From Base::evalModelImpl()
333  //
334  RCP<const Thyra::VectorBase<Scalar> > x = inArgs.get_x();
335  RCP<Thyra::VectorBase<Scalar> > x_dot =
336  Thyra::createMember(fsaImplicitModel_->get_x_space());
337  this->timeDer_->compute(x, x_dot);
338 
339  MEB::InArgs<Scalar> fsaImplicitInArgs(this->wrapperImplicitInArgs_);
340  MEB::OutArgs<Scalar> fsaImplicitOutArgs(this->wrapperImplicitOutArgs_);
341  fsaImplicitInArgs.set_x(x);
342  fsaImplicitInArgs.set_x_dot(x_dot);
343  for (int i = 0; i < fsaImplicitModel_->Np(); ++i) {
344  // Copy over parameters except for the parameter for explicit-only vector!
345  if ((inArgs.get_p(i) != Teuchos::null) && (i != p_index))
346  fsaImplicitInArgs.set_p(i, inArgs.get_p(i));
347  }
348 
349  // p-vector for index parameterIndex_ is part of the IMEX solution vector,
350  // and therefore is an n+1 column multi-vector where n is the number of
351  // sensitivity parameters. Pull out the sensitivity components before
352  // passing along to the ME, then use them for adding in dg/dy*dy/dp term.
353  RCP<const Thyra::VectorBase<Scalar> > y;
354  RCP<const Thyra::MultiVectorBase<Scalar> > dydp;
355  if (fsaImplicitInArgs.get_p(p_index) != Teuchos::null) {
356  RCP<const Thyra::VectorBase<Scalar> > p = fsaImplicitInArgs.get_p(p_index);
357  RCP<const Thyra::MultiVectorBase<Scalar> > p_mv =
358  rcp_dynamic_cast<const DMVPV>(p, true)->getMultiVector();
359  const int num_param = p_mv->domain()->dim() - 1;
360  y = p_mv->col(0);
361  dydp = p_mv->subView(Range1D(1, num_param));
362  fsaImplicitInArgs.set_p(p_index, y);
363  }
364  if (use_dfdp_as_tangent_) {
365  RCP<const Thyra::VectorBase<Scalar> > dydp_vec =
366  Thyra::multiVectorProductVector(explicit_dydp_prod_space_, dydp);
367  fsaImplicitInArgs.set_p(y_tangent_index_, dydp_vec);
368  }
369 
370  fsaImplicitOutArgs.set_f(outArgs.get_f());
371  fsaImplicitOutArgs.set_W_op(outArgs.get_W_op());
372 
373  fsaImplicitModel_->evalModel(fsaImplicitInArgs, fsaImplicitOutArgs);
374 
375  // Compute derivative of implicit residual with respect to explicit only
376  // vector y, which is passed as a parameter
377  if (!use_dfdp_as_tangent_ && outArgs.get_f() != Teuchos::null) {
378  MEB::InArgs<Scalar> appImplicitInArgs =
379  appImplicitModel_->getNominalValues();
380  RCP<const Thyra::VectorBase<Scalar> > app_x =
381  rcp_dynamic_cast<const DMVPV>(x, true)->getMultiVector()->col(0);
382  RCP<const Thyra::VectorBase<Scalar> > app_x_dot =
383  rcp_dynamic_cast<const DMVPV>(x_dot, true)->getMultiVector()->col(0);
384  appImplicitInArgs.set_x(app_x);
385  appImplicitInArgs.set_x_dot(app_x_dot);
386  for (int i = 0; i < appImplicitModel_->Np(); ++i) {
387  if (i != p_index) appImplicitInArgs.set_p(i, inArgs.get_p(i));
388  }
389  appImplicitInArgs.set_p(p_index, y);
390  if (appImplicitInArgs.supports(MEB::IN_ARG_t))
391  appImplicitInArgs.set_t(inArgs.get_t());
392  MEB::OutArgs<Scalar> appImplicitOutArgs =
393  appImplicitModel_->createOutArgs();
394  MEB::DerivativeSupport dfdp_support =
395  appImplicitOutArgs.supports(MEB::OUT_ARG_DfDp, p_index);
397  if (dfdp_support.supports(MEB::DERIV_LINEAR_OP)) {
398  if (my_dfdp_op_ == Teuchos::null)
399  my_dfdp_op_ = appImplicitModel_->create_DfDp_op(p_index);
400  appImplicitOutArgs.set_DfDp(p_index,
401  MEB::Derivative<Scalar>(my_dfdp_op_));
402  trans = Thyra::NOTRANS;
403  }
404  else if (dfdp_support.supports(MEB::DERIV_MV_JACOBIAN_FORM)) {
405  if (my_dfdp_mv_ == Teuchos::null)
406  my_dfdp_mv_ = Thyra::createMembers(
407  appImplicitModel_->get_f_space(),
408  appImplicitModel_->get_p_space(p_index)->dim());
409  appImplicitOutArgs.set_DfDp(
410  p_index,
411  MEB::Derivative<Scalar>(my_dfdp_mv_, MEB::DERIV_MV_JACOBIAN_FORM));
412  my_dfdp_op_ = my_dfdp_mv_;
413  trans = Thyra::NOTRANS;
414  }
415  else if (dfdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
416  if (my_dfdp_mv_ == Teuchos::null)
417  my_dfdp_mv_ =
418  Thyra::createMembers(appImplicitModel_->get_p_space(p_index),
419  appImplicitModel_->get_f_space()->dim());
420  appImplicitOutArgs.set_DfDp(
421  p_index,
422  MEB::Derivative<Scalar>(my_dfdp_mv_, MEB::DERIV_MV_GRADIENT_FORM));
423  my_dfdp_op_ = my_dfdp_mv_;
424  trans = Thyra::TRANS;
425  }
426  else
427  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
428  "Invalid df/dp support");
429 
430  appImplicitModel_->evalModel(appImplicitInArgs, appImplicitOutArgs);
431 
432  // Add df/dy*dy/dp term to residual
433  RCP<DMVPV> f_dfdp = rcp_dynamic_cast<DMVPV>(outArgs.get_f(), true);
434  const int num_param = f_dfdp->getNonconstMultiVector()->domain()->dim() - 1;
435  RCP<Thyra::MultiVectorBase<Scalar> > dfdp =
436  f_dfdp->getNonconstMultiVector()->subView(Range1D(1, num_param));
437  my_dfdp_op_->apply(trans, *dydp, dfdp.ptr(), Scalar(1.0), Scalar(1.0));
438  }
439 }
440 
441 template <typename Scalar>
444  const
445 {
448  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList(*fsa_pl);
449  pl->set<int>("Sensitivity Y Tangent Index", 3);
450  return pl;
451 }
452 
453 } // namespace Tempus
454 
455 #endif // Tempus_ModelEvaluatorPairPartIMEX_CombinedFSA_impl_hpp
WrapperModelEvaluatorPairPartIMEX_CombinedFSA(const Teuchos::RCP< const WrapperModelEvaluatorPairPartIMEX_Basic< Scalar > > &forwardModel, const Teuchos::RCP< const Teuchos::ParameterList > &pList=Teuchos::null)
Constructor.
EOpTransp
virtual Teuchos::RCP< const ProductVectorSpaceBase< Scalar > > productSpace() const =0
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual Teuchos::RCP< MultiVectorBase< Scalar > > getNonconstMultiVectorBlock(const int k)=0
Evaluation< VectorBase< Scalar > > get_f() const
virtual Teuchos::RCP< Thyra::VectorBase< Scalar > > getExplicitOnlyVector(const Teuchos::RCP< Thyra::VectorBase< Scalar > > &full) const
Extract explicit-only vector from a full solution vector.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
virtual Teuchos::RCP< const MultiVectorBase< Scalar > > getMultiVectorBlock(const int k) const =0
virtual Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > getForwardModel() const
Get the underlying forward model.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
ModelEvaluator pair for implicit and explicit (IMEX) evaulations.
virtual Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int i) const
Get the p space.
RCP< const VectorBase< Scalar > > col(Ordinal j) const
RCP< const MultiVectorBase< Scalar > > getMultiVector() const
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
void setup(const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &explicitModel, const Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > &implicitModel, int numExplicitOnlyBlocks=0, int parameterIndex=-1)
Setup ME when using default constructor – for derived classes.
void set_p(int l, const RCP< const VectorBase< Scalar > > &p_l)
RCP< MultiVectorBase< Scalar > > getNonconstMultiVector()
#define TEUCHOS_ASSERT(assertion_test)
Teuchos::RCP< const WrapperModelEvaluatorPairPartIMEX_Basic< Scalar > > forwardModel_
RCP< LinearOpBase< Scalar > > get_W_op() const
virtual void evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs) const
RCP< const VectorBase< Scalar > > get_x() const
RCP< const VectorBase< Scalar > > get_p(int l) const
Teuchos::Range1D Range1D
virtual Teuchos::RCP< Thyra::VectorBase< Scalar > > getIMEXVector(const Teuchos::RCP< Thyra::VectorBase< Scalar > > &full) const
Extract IMEX vector from a full solution vector.