Tempus Version of the Day
Time Integration
Loading...
Searching...
No Matches
Tempus_IntegratorAdjointSensitivity_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_IntegratorAdjointSensitivity_impl_hpp
11#define Tempus_IntegratorAdjointSensitivity_impl_hpp
12
13#include "Teuchos_ParameterList.hpp"
14#include "Thyra_DefaultMultiVectorProductVectorSpace.hpp"
15#include "Thyra_DefaultMultiVectorProductVector.hpp"
16#include "Thyra_DefaultProductVectorSpace.hpp"
17#include "Thyra_DefaultProductVector.hpp"
18#include "Thyra_VectorStdOps.hpp"
19#include "Thyra_MultiVectorStdOps.hpp"
21#include "Thyra_LinearOpWithSolveFactoryHelpers.hpp"
22
23namespace Tempus {
24
25template <class Scalar>
27 const Teuchos::RCP<Thyra::ModelEvaluator<Scalar>>& model,
28 const Teuchos::RCP<IntegratorBasic<Scalar>>& state_integrator,
29 const Teuchos::RCP<Thyra::ModelEvaluator<Scalar>>& adjoint_model,
31 adjoint_aux_model,
32 const Teuchos::RCP<IntegratorBasic<Scalar>>& adjoint_integrator,
33 const Teuchos::RCP<SolutionHistory<Scalar>>& solutionHistory,
34 const int p_index, const int g_index, const bool g_depends_on_p,
35 const bool f_depends_on_p, const bool ic_depends_on_p,
36 const bool mass_matrix_is_identity)
37 : model_(model),
38 state_integrator_(state_integrator),
39 adjoint_model_(adjoint_model),
40 adjoint_aux_model_(adjoint_aux_model),
41 adjoint_integrator_(adjoint_integrator),
42 solutionHistory_(solutionHistory),
43 p_index_(p_index),
44 g_index_(g_index),
45 g_depends_on_p_(g_depends_on_p),
46 f_depends_on_p_(f_depends_on_p),
47 ic_depends_on_p_(ic_depends_on_p),
48 mass_matrix_is_identity_(mass_matrix_is_identity),
50{
51 TEUCHOS_TEST_FOR_EXCEPTION(
52 getStepper()->getUseFSAL(), std::logic_error,
53 "Error - IntegratorAdjointSensitivity(): Cannot use FSAL with\n"
54 " IntegratorAdjointSensitivity, because the state and adjoint\n"
55 " integrators require ModelEvaluator evaluation in the\n"
56 " constructor to make the initial conditions consistent.\n"
57 " For the adjoint integrator, this requires special construction\n"
58 " which has not been implemented yet.\n");
59}
60
61template <class Scalar>
63{
64 state_integrator_ = createIntegratorBasic<Scalar>();
65 adjoint_integrator_ = createIntegratorBasic<Scalar>();
67}
68
69template <class Scalar>
71{
72 const Scalar tfinal = state_integrator_->getTimeStepControl()->getFinalTime();
73 return advanceTime(tfinal);
74}
75
76template <class Scalar>
78{
79 TEMPUS_FUNC_TIME_MONITOR_DIFF(
80 "Tempus::IntegratorAdjointSensitivity::advanceTime()", TEMPUS_AS_AT);
81
82 using Teuchos::RCP;
83 using Teuchos::rcp_dynamic_cast;
84 using Thyra::assign;
85 using Thyra::createMember;
86 using Thyra::createMembers;
94 using Thyra::VectorSpaceBase;
95 typedef Thyra::ModelEvaluatorBase MEB;
96 typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
97 typedef Thyra::DefaultProductVector<Scalar> DPV;
98
99 // Get initial state for later
100 RCP<const SolutionHistory<Scalar>> state_solution_history =
101 state_integrator_->getSolutionHistory();
102 RCP<const SolutionState<Scalar>> initial_state = (*state_solution_history)[0];
103
104 // Run state integrator and get solution
105 bool state_status = true;
106 {
107 TEMPUS_FUNC_TIME_MONITOR_DIFF(
108 "Tempus::IntegratorAdjointSensitivity::advanceTime::state",
109 TEMPUS_AS_AT_FWD);
111 state_status = state_integrator_->advanceTime(timeFinal);
112 }
113
114 // For at least some time-stepping methods, the time of the last time step
115 // may not be timeFinal (e.g., it may be greater by at most delta_t).
116 // But since the adjoint model requires timeFinal in its formulation, reset
117 // it to the achieved final time.
118 adjoint_aux_model_->setFinalTime(state_integrator_->getTime());
119
120 // Set solution history in adjoint stepper
121 adjoint_aux_model_->setForwardSolutionHistory(state_solution_history);
122
123 // Compute dg/dx
124 RCP<const VectorSpaceBase<Scalar>> g_space = model_->get_g_space(g_index_);
125 RCP<const VectorSpaceBase<Scalar>> x_space = model_->get_x_space();
126 const int num_g = g_space->dim();
127 RCP<MultiVectorBase<Scalar>> dgdx = createMembers(x_space, num_g);
128 MEB::InArgs<Scalar> inargs = model_->getNominalValues();
129 RCP<const SolutionState<Scalar>> state =
130 state_solution_history->getCurrentState();
131 inargs.set_t(state->getTime());
132 inargs.set_x(state->getX());
133 inargs.set_x_dot(state->getXDot());
134 MEB::OutArgs<Scalar> outargs = model_->createOutArgs();
135 MEB::OutArgs<Scalar> adj_outargs = adjoint_model_->createOutArgs();
136 outargs.set_DgDx(g_index_,
137 MEB::Derivative<Scalar>(dgdx, MEB::DERIV_MV_GRADIENT_FORM));
138 model_->evalModel(inargs, outargs);
139 outargs.set_DgDx(g_index_, MEB::Derivative<Scalar>());
140
141 // Compute ICs == [ (df/dx_dot)^{-T} (dg/dx)^T; 0 ]
142 // For explicit form, we are relying on the user to inform us the
143 // the mass matrix is the identity. It would be nice to be able to determine
144 // somehow automatically that we are using an explicit stepper.
145 RCP<DPV> adjoint_init = rcp_dynamic_cast<DPV>(
146 Thyra::createMember(adjoint_aux_model_->get_x_space()));
147 RCP<MultiVectorBase<Scalar>> adjoint_init_mv =
148 rcp_dynamic_cast<DMVPV>(adjoint_init->getNonconstVectorBlock(0))
149 ->getNonconstMultiVector();
150 assign(adjoint_init->getNonconstVectorBlock(1).ptr(),
151 Teuchos::ScalarTraits<Scalar>::zero());
152 if (mass_matrix_is_identity_)
153 assign(adjoint_init_mv.ptr(), *dgdx);
154 else {
155 inargs.set_alpha(1.0);
156 inargs.set_beta(0.0);
157 RCP<LinearOpWithSolveBase<Scalar>> W;
158 if (adj_outargs.supports(MEB::OUT_ARG_W)) {
159 // Model supports W
160 W = adjoint_model_->create_W();
161 adj_outargs.set_W(W);
162 adjoint_model_->evalModel(inargs, adj_outargs);
163 adj_outargs.set_W(Teuchos::null);
164 }
165 else {
166 // Otherwise model must support a W_op and W factory
167 RCP<const LinearOpWithSolveFactoryBase<Scalar>> lowsfb =
168 adjoint_model_->get_W_factory();
169 TEUCHOS_TEST_FOR_EXCEPTION(lowsfb == Teuchos::null, std::logic_error,
170 "Adjoint ME must support W out-arg or provide "
171 "a W_factory for non-identity mass matrix");
172
173 // Compute W_op (and W_prec if supported)
174 RCP<LinearOpBase<Scalar>> W_op = adjoint_model_->create_W_op();
175 adj_outargs.set_W_op(W_op);
176 RCP<PreconditionerFactoryBase<Scalar>> prec_factory =
177 lowsfb->getPreconditionerFactory();
178 RCP<PreconditionerBase<Scalar>> W_prec;
179 if (prec_factory != Teuchos::null)
180 W_prec = prec_factory->createPrec();
181 else if (adj_outargs.supports(MEB::OUT_ARG_W_prec)) {
182 W_prec = adjoint_model_->create_W_prec();
183 adj_outargs.set_W_prec(W_prec);
184 }
185 adjoint_model_->evalModel(inargs, adj_outargs);
186 adj_outargs.set_W_op(Teuchos::null);
187 if (adj_outargs.supports(MEB::OUT_ARG_W_prec))
188 adj_outargs.set_W_prec(Teuchos::null);
189
190 // Create and initialize W
191 W = lowsfb->createOp();
192 if (W_prec != Teuchos::null) {
193 if (prec_factory != Teuchos::null)
194 prec_factory->initializePrec(
195 Thyra::defaultLinearOpSource<Scalar>(W_op), W_prec.get());
196 Thyra::initializePreconditionedOp<Scalar>(*lowsfb, W_op, W_prec,
197 W.ptr());
198 }
199 else
200 Thyra::initializeOp<Scalar>(*lowsfb, W_op, W.ptr());
201 }
202 TEUCHOS_TEST_FOR_EXCEPTION(
203 W == Teuchos::null, std::logic_error,
204 "A null W has been encountered in "
205 "Tempus::IntegratorAdjointSensitivity::advanceTime!\n");
206 // Initialize adjoint_init_mv to zero before solve for linear solvers that
207 // use what is passed in as the initial guess
208 assign(adjoint_init_mv.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
209 W->solve(Thyra::NOTRANS, *dgdx, adjoint_init_mv.ptr());
210 }
211
212 // Run sensitivity integrator and get solution
213 bool sens_status = true;
214 {
215 TEMPUS_FUNC_TIME_MONITOR_DIFF(
216 "Tempus::IntegratorAdjointSensitivity::advanceTime::adjoint",
217 TEMPUS_AS_AT_ADJ);
219 const Scalar tinit =
220 adjoint_integrator_->getTimeStepControl()->getInitTime();
221 adjoint_integrator_->initializeSolutionHistory(tinit, adjoint_init);
222 sens_status = adjoint_integrator_->advanceTime(timeFinal);
223 }
224 RCP<const SolutionHistory<Scalar>> adjoint_solution_history =
225 adjoint_integrator_->getSolutionHistory();
226
227 // Compute dg/dp at final time T
228 RCP<const VectorSpaceBase<Scalar>> p_space = model_->get_p_space(p_index_);
229 dgdp_ = createMembers(p_space, num_g);
230 if (g_depends_on_p_) {
231 MEB::DerivativeSupport dgdp_support =
232 outargs.supports(MEB::OUT_ARG_DgDp, g_index_, p_index_);
233 if (dgdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
234 outargs.set_DgDp(
235 g_index_, p_index_,
236 MEB::Derivative<Scalar>(dgdp_, MEB::DERIV_MV_GRADIENT_FORM));
237 model_->evalModel(inargs, outargs);
238 }
239 else if (dgdp_support.supports(MEB::DERIV_MV_JACOBIAN_FORM)) {
240 const int num_p = p_space->dim();
241 RCP<MultiVectorBase<Scalar>> dgdp_trans = createMembers(g_space, num_p);
242 outargs.set_DgDp(
243 g_index_, p_index_,
244 MEB::Derivative<Scalar>(dgdp_trans, MEB::DERIV_MV_JACOBIAN_FORM));
245 model_->evalModel(inargs, outargs);
246 Thyra::DetachedMultiVectorView<Scalar> dgdp_view(*dgdp_);
247 Thyra::DetachedMultiVectorView<Scalar> dgdp_trans_view(*dgdp_trans);
248 for (int i = 0; i < num_p; ++i)
249 for (int j = 0; j < num_g; ++j) dgdp_view(i, j) = dgdp_trans_view(j, i);
250 }
251 else
252 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
253 "Invalid dg/dp support");
254 outargs.set_DgDp(g_index_, p_index_, MEB::Derivative<Scalar>());
255 }
256 else
257 assign(dgdp_.ptr(), Scalar(0.0));
258
259 // Add in initial condition term = (dx/dp^T(0))*(df/dx_dot^T(0))*y(0)
260 // If dxdp_init_ is null, assume it is zero
261 if (ic_depends_on_p_ && dxdp_init_ != Teuchos::null) {
262 RCP<const SolutionState<Scalar>> adjoint_state =
263 adjoint_solution_history->getCurrentState();
264 RCP<const VectorBase<Scalar>> adjoint_x =
265 rcp_dynamic_cast<const DPV>(adjoint_state->getX())->getVectorBlock(0);
266 RCP<const MultiVectorBase<Scalar>> adjoint_mv =
267 rcp_dynamic_cast<const DMVPV>(adjoint_x)->getMultiVector();
268 if (mass_matrix_is_identity_)
269 dxdp_init_->apply(Thyra::CONJTRANS, *adjoint_mv, dgdp_.ptr(), Scalar(1.0),
270 Scalar(1.0));
271 else {
272 inargs.set_t(initial_state->getTime());
273 inargs.set_x(initial_state->getX());
274 inargs.set_x_dot(initial_state->getXDot());
275 inargs.set_alpha(1.0);
276 inargs.set_beta(0.0);
277 RCP<LinearOpBase<Scalar>> W_op = adjoint_model_->create_W_op();
278 adj_outargs.set_W_op(W_op);
279 adjoint_model_->evalModel(inargs, adj_outargs);
280 adj_outargs.set_W_op(Teuchos::null);
281 RCP<MultiVectorBase<Scalar>> tmp = createMembers(x_space, num_g);
282 W_op->apply(Thyra::NOTRANS, *adjoint_mv, tmp.ptr(), Scalar(1.0),
283 Scalar(0.0));
284 dxdp_init_->apply(Thyra::CONJTRANS, *tmp, dgdp_.ptr(), Scalar(1.0),
285 Scalar(1.0));
286 }
287 }
288
289 // Add in model parameter term = \int_0^T( (df/dp^T(t)*y(t) )dt which
290 // is computed during the adjoint integration as an auxiliary integral
291 // (2nd block of the solution vector)
292 if (f_depends_on_p_) {
293 RCP<const SolutionState<Scalar>> adjoint_state =
294 adjoint_solution_history->getCurrentState();
295 RCP<const VectorBase<Scalar>> z =
296 rcp_dynamic_cast<const DPV>(adjoint_state->getX())->getVectorBlock(1);
297 RCP<const MultiVectorBase<Scalar>> z_mv =
298 rcp_dynamic_cast<const DMVPV>(z)->getMultiVector();
299 Thyra::V_VmV(dgdp_.ptr(), *dgdp_, *z_mv);
300 }
301
302 buildSolutionHistory(state_solution_history, adjoint_solution_history);
303
304 return state_status && sens_status;
305}
306
307template <class Scalar>
309{
310 return solutionHistory_->getCurrentTime();
311}
312
313template <class Scalar>
315{
316 return solutionHistory_->getCurrentIndex();
317}
318
319template <class Scalar>
321{
322 Status state_status = state_integrator_->getStatus();
323 Status sens_status = adjoint_integrator_->getStatus();
324 if (state_status == FAILED || sens_status == FAILED) return FAILED;
325 if (state_status == WORKING || sens_status == WORKING) return WORKING;
326 return PASSED;
327}
328
329template <class Scalar>
331{
332 state_integrator_->setStatus(st);
333 adjoint_integrator_->setStatus(st);
334}
335
336template <class Scalar>
338 const
339{
340 return state_integrator_->getStepper();
341}
342
343template <class Scalar>
344Teuchos::RCP<const SolutionHistory<Scalar>>
346{
347 return solutionHistory_;
348}
349
350template <class Scalar>
351Teuchos::RCP<const SolutionHistory<Scalar>>
353{
354 return state_integrator_->getSolutionHistory();
355}
356
357template <class Scalar>
358Teuchos::RCP<const SolutionHistory<Scalar>>
360{
361 return adjoint_integrator_->getSolutionHistory();
362}
363
364template <class Scalar>
365Teuchos::RCP<SolutionHistory<Scalar>>
370
371template <class Scalar>
372Teuchos::RCP<const TimeStepControl<Scalar>>
374{
375 return state_integrator_->getTimeStepControl();
376}
377
378template <class Scalar>
379Teuchos::RCP<TimeStepControl<Scalar>>
381{
382 return state_integrator_->getNonConstTimeStepControl();
383}
384
385template <class Scalar>
386Teuchos::RCP<TimeStepControl<Scalar>>
388{
389 return state_integrator_->getNonConstTimeStepControl();
390}
391
392template <class Scalar>
393Teuchos::RCP<TimeStepControl<Scalar>>
395{
396 return adjoint_integrator_->getNonConstTimeStepControl();
397}
398
399template <class Scalar>
401 Scalar t0, Teuchos::RCP<const Thyra::VectorBase<Scalar>> x0,
402 Teuchos::RCP<const Thyra::VectorBase<Scalar>> xdot0,
403 Teuchos::RCP<const Thyra::VectorBase<Scalar>> xdotdot0,
404 Teuchos::RCP<const Thyra::MultiVectorBase<Scalar>> DxDp0,
405 Teuchos::RCP<const Thyra::MultiVectorBase<Scalar>> /* DxdotDp0 */,
406 Teuchos::RCP<const Thyra::MultiVectorBase<Scalar>> /* DxdotdotDp0 */)
407{
408 state_integrator_->initializeSolutionHistory(t0, x0, xdot0, xdotdot0);
409 dxdp_init_ = DxDp0;
410}
411
412template <class Scalar>
413Teuchos::RCP<IntegratorObserver<Scalar>>
415{
416 return state_integrator_->getObserver();
417}
418
419template <class Scalar>
421 Teuchos::RCP<IntegratorObserver<Scalar>> obs)
422{
423 state_integrator_->setObserver(obs);
424 // ETP 1/12/22 Disabling passing of the observer to the adjoint
425 // integrator to work around issues in Piro
426 // adjoint_integrator_->setObserver(obs);
427}
428
429template <class Scalar>
431{
432 state_integrator_->initialize();
433 adjoint_integrator_->initialize();
434}
435
436template <class Scalar>
437Teuchos::RCP<const Thyra::VectorBase<Scalar>>
439{
440 return state_integrator_->getX();
441}
442
443template <class Scalar>
444Teuchos::RCP<const Thyra::VectorBase<Scalar>>
446{
447 return state_integrator_->getXDot();
448}
449
450template <class Scalar>
451Teuchos::RCP<const Thyra::VectorBase<Scalar>>
453{
454 return state_integrator_->getXDotDot();
455}
456
457template <class Scalar>
458Teuchos::RCP<const Thyra::MultiVectorBase<Scalar>>
460{
461 using Teuchos::RCP;
462 using Teuchos::rcp_dynamic_cast;
463 typedef Thyra::DefaultProductVector<Scalar> DPV;
464 typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
465 RCP<const DPV> pv = rcp_dynamic_cast<const DPV>(adjoint_integrator_->getX());
466 RCP<const DMVPV> mvpv = rcp_dynamic_cast<const DMVPV>(pv->getVectorBlock(0));
467 return mvpv->getMultiVector();
468}
469
470template <class Scalar>
471Teuchos::RCP<const Thyra::MultiVectorBase<Scalar>>
473{
474 using Teuchos::RCP;
475 using Teuchos::rcp_dynamic_cast;
476 typedef Thyra::DefaultProductVector<Scalar> DPV;
477 typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
478 RCP<const DPV> pv =
479 rcp_dynamic_cast<const DPV>(adjoint_integrator_->getXDot());
480 RCP<const DMVPV> mvpv = rcp_dynamic_cast<const DMVPV>(pv->getVectorBlock(0));
481 return mvpv->getMultiVector();
482}
483
484template <class Scalar>
485Teuchos::RCP<const Thyra::MultiVectorBase<Scalar>>
487{
488 using Teuchos::RCP;
489 using Teuchos::rcp_dynamic_cast;
490 typedef Thyra::DefaultProductVector<Scalar> DPV;
491 typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
492 RCP<const DPV> pv =
493 rcp_dynamic_cast<const DPV>(adjoint_integrator_->getXDotDot());
494 RCP<const DMVPV> mvpv = rcp_dynamic_cast<const DMVPV>(pv->getVectorBlock(0));
495 return mvpv->getMultiVector();
496}
497
498template <class Scalar>
499Teuchos::RCP<const Thyra::MultiVectorBase<Scalar>>
501{
502 return dgdp_;
503}
504
505template <class Scalar>
507{
508 std::string name = "Tempus::IntegratorAdjointSensitivity";
509 return (name);
510}
511
512template <class Scalar>
514 Teuchos::FancyOStream& out, const Teuchos::EVerbosityLevel verbLevel) const
515{
516 auto l_out = Teuchos::fancyOStream(out.getOStream());
517 Teuchos::OSTab ostab(*l_out, 2, this->description());
518 l_out->setOutputToRootOnly(0);
519
520 *l_out << description() << "::describe" << std::endl;
521 state_integrator_->describe(*l_out, verbLevel);
522 adjoint_integrator_->describe(*l_out, verbLevel);
523}
524
525template <class Scalar>
530
531template <class Scalar>
532Teuchos::RCP<AdjointAuxSensitivityModelEvaluator<Scalar>>
534 const Teuchos::RCP<Thyra::ModelEvaluator<Scalar>>& model,
535 const Teuchos::RCP<Thyra::ModelEvaluator<Scalar>>& adjoint_model,
536 const Teuchos::RCP<Teuchos::ParameterList>& inputPL)
537{
538 using Teuchos::ParameterList;
539 using Teuchos::RCP;
540 using Teuchos::rcp;
541
542 RCP<ParameterList> spl = Teuchos::parameterList();
543 if (inputPL != Teuchos::null) {
544 *spl = inputPL->sublist("Sensitivities");
545 }
546 if (spl->isParameter("Response Depends on Parameters"))
547 spl->remove("Response Depends on Parameters");
548 if (spl->isParameter("Residual Depends on Parameters"))
549 spl->remove("Residual Depends on Parameters");
550 if (spl->isParameter("IC Depends on Parameters"))
551 spl->remove("IC Depends on Parameters");
552
553 const Scalar tinit = state_integrator_->getTimeStepControl()->getInitTime();
554 const Scalar tfinal = state_integrator_->getTimeStepControl()->getFinalTime();
556 model, adjoint_model, tinit, tfinal, spl));
557}
558
559template <class Scalar>
561 const Teuchos::RCP<const SolutionHistory<Scalar>>& state_solution_history,
562 const Teuchos::RCP<const SolutionHistory<Scalar>>& adjoint_solution_history)
563{
564 using Teuchos::ParameterList;
565 using Teuchos::RCP;
566 using Teuchos::rcp;
567 using Teuchos::rcp_dynamic_cast;
568 using Thyra::assign;
569 using Thyra::createMembers;
571 using Thyra::multiVectorProductVector;
572 using Thyra::VectorBase;
573 using Thyra::VectorSpaceBase;
574 typedef Thyra::DefaultProductVectorSpace<Scalar> DPVS;
575 typedef Thyra::DefaultProductVector<Scalar> DPV;
576
577 RCP<const VectorSpaceBase<Scalar>> x_space = model_->get_x_space();
578 RCP<const VectorSpaceBase<Scalar>> adjoint_space =
579 rcp_dynamic_cast<const DPVS>(adjoint_aux_model_->get_x_space())
580 ->getBlock(0);
581 Teuchos::Array<RCP<const VectorSpaceBase<Scalar>>> spaces(2);
582 spaces[0] = x_space;
583 spaces[1] = adjoint_space;
584 RCP<const DPVS> prod_space = Thyra::productVectorSpace(spaces());
585
586 int num_states = state_solution_history->getNumStates();
587 const Scalar t_init = state_integrator_->getTimeStepControl()->getInitTime();
588 const Scalar t_final = state_integrator_->getTime();
589 for (int i = 0; i < num_states; ++i) {
590 RCP<const SolutionState<Scalar>> forward_state =
591 (*state_solution_history)[i];
592 RCP<const SolutionState<Scalar>> adjoint_state =
593 adjoint_solution_history->findState(t_final + t_init -
594 forward_state->getTime());
595
596 // X
597 RCP<DPV> x = Thyra::defaultProductVector(prod_space);
598 RCP<const VectorBase<Scalar>> adjoint_x =
599 rcp_dynamic_cast<const DPV>(adjoint_state->getX())->getVectorBlock(0);
600 assign(x->getNonconstVectorBlock(0).ptr(), *(forward_state->getX()));
601 assign(x->getNonconstVectorBlock(1).ptr(), *(adjoint_x));
602 RCP<VectorBase<Scalar>> x_b = x;
603
604 // X-Dot
605 RCP<DPV> x_dot = Thyra::defaultProductVector(prod_space);
606 RCP<const VectorBase<Scalar>> adjoint_x_dot =
607 rcp_dynamic_cast<const DPV>(adjoint_state->getXDot())
608 ->getVectorBlock(0);
609 assign(x_dot->getNonconstVectorBlock(0).ptr(), *(forward_state->getXDot()));
610 assign(x_dot->getNonconstVectorBlock(1).ptr(), *(adjoint_x_dot));
611 RCP<VectorBase<Scalar>> x_dot_b = x_dot;
612
613 // X-Dot-Dot
614 RCP<DPV> x_dot_dot;
615 if (forward_state->getXDotDot() != Teuchos::null) {
616 x_dot_dot = Thyra::defaultProductVector(prod_space);
617 RCP<const VectorBase<Scalar>> adjoint_x_dot_dot =
618 rcp_dynamic_cast<const DPV>(adjoint_state->getXDotDot())
619 ->getVectorBlock(0);
620 assign(x_dot_dot->getNonconstVectorBlock(0).ptr(),
621 *(forward_state->getXDotDot()));
622 assign(x_dot_dot->getNonconstVectorBlock(1).ptr(), *(adjoint_x_dot_dot));
623 }
624 RCP<VectorBase<Scalar>> x_dot_dot_b = x_dot_dot;
625
626 RCP<SolutionState<Scalar>> prod_state = forward_state->clone();
627 prod_state->setX(x_b);
628 prod_state->setXDot(x_dot_b);
629 prod_state->setXDotDot(x_dot_dot_b);
630 prod_state->setPhysicsState(Teuchos::null);
631 solutionHistory_->addState(prod_state);
632 }
633}
634
636template <class Scalar>
637Teuchos::RCP<IntegratorAdjointSensitivity<Scalar>>
639 Teuchos::RCP<Teuchos::ParameterList> inputPL,
640 const Teuchos::RCP<Thyra::ModelEvaluator<Scalar>>& model,
641 const Teuchos::RCP<Thyra::ModelEvaluator<Scalar>>& adjoint_model)
642{
643 // set the parameters
644 Teuchos::RCP<Teuchos::ParameterList> spl = Teuchos::parameterList();
645 if (inputPL != Teuchos::null) *spl = inputPL->sublist("Sensitivities");
646
647 int p_index = spl->get<int>("Sensitivity Parameter Index", 0);
648 int g_index = spl->get<int>("Response Function Index", 0);
649 bool g_depends_on_p = spl->get<bool>("Response Depends on Parameters", true);
650 bool f_depends_on_p = spl->get<bool>("Residual Depends on Parameters", true);
651 bool ic_depends_on_p = spl->get<bool>("IC Depends on Parameters", true);
652 bool mass_matrix_is_identity =
653 spl->get<bool>("Mass Matrix Is Identity", false);
654
655 auto state_integrator = createIntegratorBasic<Scalar>(inputPL, model);
656
657 // createAdjointModel
658 if (spl->isParameter("Response Depends on Parameters"))
659 spl->remove("Response Depends on Parameters");
660 if (spl->isParameter("Residual Depends on Parameters"))
661 spl->remove("Residual Depends on Parameters");
662 if (spl->isParameter("IC Depends on Parameters"))
663 spl->remove("IC Depends on Parameters");
664
665 const Scalar tinit = state_integrator->getTimeStepControl()->getInitTime();
666 const Scalar tfinal = state_integrator->getTimeStepControl()->getFinalTime();
667 // auto adjoint_model = Teuchos::rcp(new
668 // AdjointAuxSensitivityModelEvaluator<Scalar>(model, tfinal, spl));
669 // TODO: where is the adjoint ME coming from?
670
671 Teuchos::RCP<Thyra::ModelEvaluator<Scalar>> adjt_model = adjoint_model;
672 if (adjoint_model == Teuchos::null)
673 adjt_model = Thyra::implicitAdjointModelEvaluator(model);
674
675 auto adjoint_aux_model =
677 model, adjt_model, tinit, tfinal, spl));
678
679 // Create combined solution histories combining the forward and adjoint
680 // solutions. We do not include the auxiliary part from the adjoint solution.
681 auto integrator_name = inputPL->get<std::string>("Integrator Name");
682 auto integratorPL = Teuchos::sublist(inputPL, integrator_name, true);
683 auto shPL = Teuchos::sublist(integratorPL, "Solution History", true);
684 auto combined_solution_History = createSolutionHistoryPL<Scalar>(shPL);
685
686 auto adjoint_integrator =
687 createIntegratorBasic<Scalar>(inputPL, adjoint_aux_model);
688
689 Teuchos::RCP<IntegratorAdjointSensitivity<Scalar>> integrator =
691 model, state_integrator, adjt_model, adjoint_aux_model,
692 adjoint_integrator, combined_solution_History, p_index, g_index,
693 g_depends_on_p, f_depends_on_p, ic_depends_on_p,
694 mass_matrix_is_identity));
695
696 return (integrator);
697}
698
700template <class Scalar>
701Teuchos::RCP<IntegratorAdjointSensitivity<Scalar>>
703{
704 Teuchos::RCP<IntegratorAdjointSensitivity<Scalar>> integrator =
705 Teuchos::rcp(new IntegratorAdjointSensitivity<Scalar>());
706 return (integrator);
707}
708
709} // namespace Tempus
710#endif // Tempus_IntegratorAdjointSensitivity_impl_hpp
ModelEvaluator for forming adjoint sensitivity equations.
Time integrator suitable for adjoint sensitivity analysis.
Teuchos::RCP< const SolutionHistory< Scalar > > getSensSolutionHistory() const
virtual Teuchos::RCP< SolutionHistory< Scalar > > getNonConstSolutionHistory() override
Get the SolutionHistory.
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getYDot() const
Get the current time derivative of the adjoint solution, ydot.
virtual void setObserver(Teuchos::RCP< IntegratorObserver< Scalar > > obs=Teuchos::null)
Set the Observer.
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getXDotDot() const
Get the current second time derivative of the solution, xdotdot.
virtual Scalar getTime() const override
Get current time.
virtual int getIndex() const override
Get current index.
virtual Teuchos::RCP< const SolutionHistory< Scalar > > getSolutionHistory() const override
Get the SolutionHistory.
void buildSolutionHistory(const Teuchos::RCP< const SolutionHistory< Scalar > > &state_solution_history, const Teuchos::RCP< const SolutionHistory< Scalar > > &adjoint_solution_history)
Teuchos::RCP< TimeStepControl< Scalar > > getSensNonConstTimeStepControl()
virtual void initialize()
Initializes the Integrator after set* function calls.
IntegratorAdjointSensitivity()
Constructor that requires a subsequent setParameterList, setStepper, and initialize calls.
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getX() const
Get the current solution, x.
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getYDotDot() const
Get the current second time derivative of the adjoint solution, ydotdot.
virtual bool advanceTime()
Advance the solution to timeMax, and return true if successful.
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getXDot() const
Get the current time derivative of the solution, xdot.
virtual void setStatus(const Status st) override
Set Status.
SensitivityStepMode getStepMode() const
What mode the current time integration step is in.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const override
virtual Teuchos::RCP< const TimeStepControl< Scalar > > getTimeStepControl() const override
Get the TimeStepControl.
virtual Teuchos::RCP< TimeStepControl< Scalar > > getNonConstTimeStepControl() override
virtual void initializeSolutionHistory(Scalar t0, Teuchos::RCP< const Thyra::VectorBase< Scalar > > x0, Teuchos::RCP< const Thyra::VectorBase< Scalar > > xdot0=Teuchos::null, Teuchos::RCP< const Thyra::VectorBase< Scalar > > xdotdot0=Teuchos::null, Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > DxDp0=Teuchos::null, Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > DxdotDp0=Teuchos::null, Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > DxdotdotDp0=Teuchos::null)
Set the initial state from Thyra::VectorBase(s)
virtual Teuchos::RCP< Stepper< Scalar > > getStepper() const override
Get the Stepper.
Teuchos::RCP< const SolutionHistory< Scalar > > getStateSolutionHistory() const
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getDgDp() const
Return adjoint sensitivity stored in gradient format.
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getY() const
Get the current adjoint solution, y.
virtual Teuchos::RCP< IntegratorObserver< Scalar > > getObserver()
Get the Observer.
Teuchos::RCP< TimeStepControl< Scalar > > getStateNonConstTimeStepControl()
Teuchos::RCP< AdjointAuxSensitivityModelEvaluator< Scalar > > createAdjointModel(const Teuchos::RCP< Thyra::ModelEvaluator< Scalar > > &model, const Teuchos::RCP< Thyra::ModelEvaluator< Scalar > > &adjoint_model, const Teuchos::RCP< Teuchos::ParameterList > &inputPL)
IntegratorObserver class for time integrators.
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
Status
Status for the Integrator, the Stepper and the SolutionState.
Teuchos::RCP< IntegratorAdjointSensitivity< Scalar > > createIntegratorAdjointSensitivity()
Nonmember constructor.
RCP< ImplicitAdjointModelEvaluator< Scalar > > implicitAdjointModelEvaluator(const RCP< const ModelEvaluator< Scalar > > &model)