Tempus Version of the Day
Time Integration
Loading...
Searching...
No Matches
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
16namespace Tempus {
17
18template <typename Scalar>
21 const Teuchos::RCP<const WrapperModelEvaluatorPairPartIMEX_Basic<
22 Scalar> >& forwardModel,
23 const Teuchos::RCP<const Teuchos::ParameterList>& pList)
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;
34 pl->validateParametersAndSetDefaults(*this->getValidParameters());
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
65template <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
80 TEUCHOS_TEST_FOR_EXCEPTION(
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);
96 TEUCHOS_TEST_FOR_EXCEPTION(
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
115template <typename Scalar>
116Teuchos::RCP<const Thyra::VectorSpaceBase<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
129template <typename Scalar>
130Teuchos::RCP<Thyra::VectorBase<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
168template <typename Scalar>
169Teuchos::RCP<const Thyra::VectorBase<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
208template <typename Scalar>
209Teuchos::RCP<Thyra::VectorBase<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
247template <typename Scalar>
248Teuchos::RCP<const Thyra::VectorBase<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
287template <typename Scalar>
288Teuchos::RCP<const Thyra::ModelEvaluator<Scalar> >
293
294template <typename Scalar>
295Thyra::ModelEvaluatorBase::InArgs<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
319template <typename Scalar>
321 const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs,
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);
396 Thyra::EOpTransp trans = Thyra::NOTRANS;
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
441template <typename Scalar>
442Teuchos::RCP<const Teuchos::ParameterList>
444 const
445{
446 Teuchos::RCP<const Teuchos::ParameterList> fsa_pl =
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
ModelEvaluator pair for implicit and explicit (IMEX) evaulations.
Teuchos::RCP< const WrapperModelEvaluatorPairPartIMEX_Basic< Scalar > > forwardModel_
WrapperModelEvaluatorPairPartIMEX_CombinedFSA(const Teuchos::RCP< const WrapperModelEvaluatorPairPartIMEX_Basic< Scalar > > &forwardModel, const Teuchos::RCP< const Teuchos::ParameterList > &pList=Teuchos::null)
Constructor.
virtual void evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs) 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.
virtual Teuchos::RCP< Thyra::VectorBase< Scalar > > getIMEXVector(const Teuchos::RCP< Thyra::VectorBase< Scalar > > &full) const
Extract IMEX vector from a full solution vector.
virtual Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int i) const
Get the p space.
virtual Teuchos::RCP< const Thyra::ModelEvaluator< Scalar > > getForwardModel() const
Get the underlying forward model.