Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
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 
23 namespace Tempus {
24 
25 template <class Scalar>
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),
49  stepMode_(SensitivityStepMode::Forward)
50 {
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 
61 template <class Scalar>
63 {
64  state_integrator_ = createIntegratorBasic<Scalar>();
65  adjoint_integrator_ = createIntegratorBasic<Scalar>();
66  stepMode_ = SensitivityStepMode::Forward;
67 }
68 
69 template <class Scalar>
71 {
72  const Scalar tfinal = state_integrator_->getTimeStepControl()->getFinalTime();
73  return advanceTime(tfinal);
74 }
75 
76 template <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;
87  using Thyra::LinearOpBase;
93  using Thyra::VectorBase;
95  typedef Thyra::ModelEvaluatorBase MEB;
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);
110  stepMode_ = SensitivityStepMode::Forward;
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(),
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  }
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);
218  stepMode_ = SensitivityStepMode::Adjoint;
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 
307 template <class Scalar>
309 {
310  return solutionHistory_->getCurrentTime();
311 }
312 
313 template <class Scalar>
315 {
316  return solutionHistory_->getCurrentIndex();
317 }
318 
319 template <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 
329 template <class Scalar>
331 {
332  state_integrator_->setStatus(st);
333  adjoint_integrator_->setStatus(st);
334 }
335 
336 template <class Scalar>
338  const
339 {
340  return state_integrator_->getStepper();
341 }
342 
343 template <class Scalar>
346 {
347  return solutionHistory_;
348 }
349 
350 template <class Scalar>
353 {
354  return state_integrator_->getSolutionHistory();
355 }
356 
357 template <class Scalar>
360 {
361  return adjoint_integrator_->getSolutionHistory();
362 }
363 
364 template <class Scalar>
367 {
368  return solutionHistory_;
369 }
370 
371 template <class Scalar>
374 {
375  return state_integrator_->getTimeStepControl();
376 }
377 
378 template <class Scalar>
381 {
382  return state_integrator_->getNonConstTimeStepControl();
383 }
384 
385 template <class Scalar>
388 {
389  return state_integrator_->getNonConstTimeStepControl();
390 }
391 
392 template <class Scalar>
395 {
396  return adjoint_integrator_->getNonConstTimeStepControl();
397 }
398 
399 template <class Scalar>
401  Scalar t0, Teuchos::RCP<const Thyra::VectorBase<Scalar>> x0,
403  Teuchos::RCP<const Thyra::VectorBase<Scalar>> xdotdot0,
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 
412 template <class Scalar>
415 {
416  return state_integrator_->getObserver();
417 }
418 
419 template <class Scalar>
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 
429 template <class Scalar>
431 {
432  state_integrator_->initialize();
433  adjoint_integrator_->initialize();
434 }
435 
436 template <class Scalar>
439 {
440  return state_integrator_->getX();
441 }
442 
443 template <class Scalar>
446 {
447  return state_integrator_->getXDot();
448 }
449 
450 template <class Scalar>
453 {
454  return state_integrator_->getXDotDot();
455 }
456 
457 template <class Scalar>
460 {
461  using Teuchos::RCP;
462  using Teuchos::rcp_dynamic_cast;
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 
470 template <class Scalar>
473 {
474  using Teuchos::RCP;
475  using Teuchos::rcp_dynamic_cast;
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 
484 template <class Scalar>
487 {
488  using Teuchos::RCP;
489  using Teuchos::rcp_dynamic_cast;
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 
498 template <class Scalar>
501 {
502  return dgdp_;
503 }
504 
505 template <class Scalar>
507 {
508  std::string name = "Tempus::IntegratorAdjointSensitivity";
509  return (name);
510 }
511 
512 template <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 
525 template <class Scalar>
527 {
528  return stepMode_;
529 }
530 
531 template <class Scalar>
535  const Teuchos::RCP<Thyra::ModelEvaluator<Scalar>>& adjoint_model,
537 {
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 
559 template <class Scalar>
561  const Teuchos::RCP<const SolutionHistory<Scalar>>& state_solution_history,
562  const Teuchos::RCP<const SolutionHistory<Scalar>>& adjoint_solution_history)
563 {
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;
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);
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 
636 template <class Scalar>
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 
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 
700 template <class Scalar>
703 {
706  return (integrator);
707 }
708 
709 } // namespace Tempus
710 #endif // Tempus_IntegratorAdjointSensitivity_impl_hpp
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const override
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getYDot() const
Get the current time derivative of the adjoint solution, ydot.
SensitivityStepMode getStepMode() const
What mode the current time integration step is in.
virtual Teuchos::RCP< TimeStepControl< Scalar > > getNonConstTimeStepControl() override
virtual void setObserver(Teuchos::RCP< IntegratorObserver< Scalar >> obs=Teuchos::null)
Set the Observer.
T & get(const std::string &name, T def_value)
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getXDotDot() const
Get the current second time derivative of the solution, xdotdot.
virtual void setStatus(const Status st) override
Set Status.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void buildSolutionHistory(const Teuchos::RCP< const SolutionHistory< Scalar >> &state_solution_history, const Teuchos::RCP< const SolutionHistory< Scalar >> &adjoint_solution_history)
virtual Teuchos::RCP< SolutionHistory< Scalar > > getNonConstSolutionHistory() override
Get the SolutionHistory.
ModelEvaluator for forming adjoint sensitivity equations.
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getXDot() const
Get the current time derivative of the solution, xdot.
virtual Teuchos::RCP< IntegratorObserver< Scalar > > getObserver()
Get the Observer.
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getX() const
Get the current solution, x.
bool isParameter(const std::string &name) const
bool remove(std::string const &name, bool throwIfNotExists=true)
Teuchos::RCP< IntegratorAdjointSensitivity< Scalar > > createIntegratorAdjointSensitivity(Teuchos::RCP< Teuchos::ParameterList > pList, const Teuchos::RCP< Thyra::ModelEvaluator< Scalar >> &model, const Teuchos::RCP< Thyra::ModelEvaluator< Scalar >> &adjoint_model=Teuchos::null)
Nonmember constructor.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual Teuchos::RCP< const SolutionHistory< Scalar > > getSolutionHistory() const override
Get the SolutionHistory.
Status
Status for the Integrator, the Stepper and the SolutionState.
IntegratorObserver class for time integrators.
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getYDotDot() const
Get the current second time derivative of the adjoint solution, ydotdot.
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)
virtual Teuchos::RCP< const TimeStepControl< Scalar > > getTimeStepControl() const override
Get the TimeStepControl.
RCP< const MultiVectorBase< Scalar > > getMultiVector() const
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
virtual bool advanceTime()
Advance the solution to timeMax, and return true if successful.
Teuchos::RCP< TimeStepControl< Scalar > > getSensNonConstTimeStepControl()
Teuchos::RCP< const SolutionHistory< Scalar > > getSensSolutionHistory() const
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getY() const
Get the current adjoint solution, y.
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)
Teuchos::RCP< const SolutionHistory< Scalar > > getStateSolutionHistory() const
RCP< ImplicitAdjointModelEvaluator< Scalar > > implicitAdjointModelEvaluator(const RCP< const ModelEvaluator< Scalar > > &model)
RCP< std::basic_ostream< char_type, traits_type > > getOStream()
Time integrator suitable for adjoint sensitivity analysis.
virtual int getIndex() const override
Get current index.
Teuchos::RCP< TimeStepControl< Scalar > > getStateNonConstTimeStepControl()
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
virtual Scalar getTime() const override
Get current time.
virtual Status getStatus() const override
Get Status.
virtual void initialize()
Initializes the Integrator after set* function calls.
virtual Teuchos::RCP< Stepper< Scalar > > getStepper() const override
Get the Stepper.
virtual Teuchos::RCP< const Thyra::MultiVectorBase< Scalar > > getDgDp() const
Return adjoint sensitivity stored in gradient format.
IntegratorAdjointSensitivity()
Constructor that requires a subsequent setParameterList, setStepper, and initialize calls...