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: Copyright (2017) Sandia Corporation
4 //
5 // Distributed under BSD 3-clause license (See accompanying file Copyright.txt)
6 // ****************************************************************************
7 // @HEADER
8 
9 #ifndef Tempus_IntegratorAdjointSensitivity_impl_hpp
10 #define Tempus_IntegratorAdjointSensitivity_impl_hpp
11 
12 #include "Thyra_DefaultMultiVectorProductVectorSpace.hpp"
13 #include "Thyra_DefaultMultiVectorProductVector.hpp"
14 #include "Thyra_DefaultProductVectorSpace.hpp"
15 #include "Thyra_DefaultProductVector.hpp"
16 #include "Thyra_VectorStdOps.hpp"
17 #include "Thyra_MultiVectorStdOps.hpp"
18 
19 
20 namespace Tempus {
21 
22 template<class Scalar>
27 {
28  model_ = model;
29  setParameterList(inputPL);
30  state_integrator_ = integratorBasic<Scalar>(inputPL, model_);
31 
32  TEUCHOS_TEST_FOR_EXCEPTION( getStepper()->getUseFSAL(), std::logic_error,
33  "Error - IntegratorAdjointSensitivity(): Cannot use FSAL with\n"
34  " IntegratorAdjointSensitivity, because the state and adjoint\n"
35  " integrators require ModelEvaluator evaluation in the\n"
36  " constructor to make the initial conditions consistent.\n"
37  " For the adjoint integrator, this requires special construction\n"
38  " which has not been implemented yet.\n");
39 
40  adjoint_model_ = createAdjointModel(model_, inputPL);
41  adjoint_integrator_ = integratorBasic<Scalar>(inputPL, adjoint_model_);
42 }
43 
44 template<class Scalar>
47 {
48  state_integrator_ = integratorBasic<Scalar>();
49  adjoint_integrator_ = integratorBasic<Scalar>();
50 }
51 
52 template<class Scalar>
53 bool
56 {
57  const Scalar tfinal =
58  state_integrator_->getTimeStepControl()->getFinalTime();
59  return advanceTime(tfinal);
60 }
61 
62 template<class Scalar>
63 bool
65 advanceTime(const Scalar timeFinal)
66 {
67  using Teuchos::RCP;
68  using Teuchos::rcp_dynamic_cast;
69  using Thyra::VectorBase;
72  using Thyra::LinearOpBase;
74  using Thyra::createMember;
75  using Thyra::createMembers;
76  using Thyra::assign;
77  typedef Thyra::ModelEvaluatorBase MEB;
80 
81  // Get initial state for later
82  RCP<const SolutionHistory<Scalar> > state_solution_history =
83  state_integrator_->getSolutionHistory();
84  RCP<const SolutionState<Scalar> > initial_state =
85  (*state_solution_history)[0];
86 
87  // Run state integrator and get solution
88  bool state_status = state_integrator_->advanceTime(timeFinal);
89 
90  // Set solution history in adjoint stepper
91  adjoint_model_->setForwardSolutionHistory(state_solution_history);
92 
93  // Compute dg/dx
94  RCP<const VectorSpaceBase<Scalar> > g_space = model_->get_g_space(g_index_);
95  RCP<const VectorSpaceBase<Scalar> > x_space = model_->get_x_space();
96  const int num_g = g_space->dim();
97  RCP<MultiVectorBase<Scalar> > dgdx = createMembers(x_space, num_g);
98  MEB::InArgs<Scalar> inargs = model_->getNominalValues();
99  RCP<const SolutionState<Scalar> > state =
100  state_solution_history->getCurrentState();
101  inargs.set_t(state->getTime());
102  inargs.set_x(state->getX());
103  inargs.set_x_dot(state->getXDot());
104  MEB::OutArgs<Scalar> outargs = model_->createOutArgs();
105  outargs.set_DgDx(g_index_,
106  MEB::Derivative<Scalar>(dgdx, MEB::DERIV_MV_GRADIENT_FORM));
107  model_->evalModel(inargs, outargs);
108  outargs.set_DgDx(g_index_, MEB::Derivative<Scalar>());
109 
110  // Compute ICs == [ (df/dx_dot)^{-T} (dg/dx)^T; 0 ]
111  // For explicit form, we are relying on the user to inform us the
112  // the mass matrix is the identity. It would be nice to be able to determine
113  // somehow automatically that we are using an explicit stepper.
114  RCP<DPV> adjoint_init =
115  rcp_dynamic_cast<DPV>(Thyra::createMember(adjoint_model_->get_x_space()));
116  RCP<MultiVectorBase<Scalar> > adjoint_init_mv =
117  rcp_dynamic_cast<DMVPV>(adjoint_init->getNonconstVectorBlock(0))->getNonconstMultiVector();
118  assign(adjoint_init->getNonconstVectorBlock(1).ptr(),
120  if (mass_matrix_is_identity_)
121  assign(adjoint_init_mv.ptr(), *dgdx);
122  else {
123  inargs.set_alpha(1.0);
124  inargs.set_beta(0.0);
125  RCP<LinearOpWithSolveBase<Scalar> > W = model_->create_W();
126  outargs.set_W(W);
127  model_->evalModel(inargs, outargs);
128  W->solve(Thyra::CONJTRANS, *dgdx, adjoint_init_mv.ptr());
129  outargs.set_W(Teuchos::null);
130  }
131 
132  // Run sensitivity integrator and get solution
133  adjoint_integrator_->initializeSolutionHistory(Scalar(0.0), adjoint_init);
134  bool sens_status = adjoint_integrator_->advanceTime(timeFinal);
135  RCP<const SolutionHistory<Scalar> > adjoint_solution_history =
136  adjoint_integrator_->getSolutionHistory();
137 
138  // Compute dg/dp at final time T
139  RCP<const VectorSpaceBase<Scalar> > p_space = model_->get_p_space(p_index_);
140  dgdp_ = createMembers(p_space, num_g);
141  if (g_depends_on_p_) {
142  MEB::DerivativeSupport dgdp_support =
143  outargs.supports(MEB::OUT_ARG_DgDp, g_index_, p_index_);
144  if (dgdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
145  outargs.set_DgDp(g_index_, p_index_,
146  MEB::Derivative<Scalar>(dgdp_,
147  MEB::DERIV_MV_GRADIENT_FORM));
148  model_->evalModel(inargs, outargs);
149  }
150  else if (dgdp_support.supports(MEB::DERIV_MV_JACOBIAN_FORM)) {
151  const int num_p = p_space->dim();
152  RCP<MultiVectorBase<Scalar> > dgdp_trans =
153  createMembers(g_space, num_p);
154  outargs.set_DgDp(g_index_, p_index_,
155  MEB::Derivative<Scalar>(dgdp_trans,
156  MEB::DERIV_MV_JACOBIAN_FORM));
157  model_->evalModel(inargs, outargs);
158  Thyra::DetachedMultiVectorView<Scalar> dgdp_view(*dgdp_);
159  Thyra::DetachedMultiVectorView<Scalar> dgdp_trans_view(*dgdp_trans);
160  for (int i=0; i<num_p; ++i)
161  for (int j=0; j<num_g; ++j)
162  dgdp_view(i,j) = dgdp_trans_view(j,i);
163  }
164  else
165  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
166  "Invalid dg/dp support");
167  outargs.set_DgDp(g_index_, p_index_, MEB::Derivative<Scalar>());
168  }
169  else
170  assign(dgdp_.ptr(), Scalar(0.0));
171 
172  // Add in initial condition term = (dx/dp^T(0))*(df/dx_dot^T(0))*y(0)
173  // If dxdp_init_ is null, assume it is zero
174  if (ic_depends_on_p_ && dxdp_init_ != Teuchos::null) {
175  RCP<const SolutionState<Scalar> > adjoint_state =
176  adjoint_solution_history->getCurrentState();
177  RCP<const VectorBase<Scalar> > adjoint_x =
178  rcp_dynamic_cast<const DPV>(adjoint_state->getX())->getVectorBlock(0);
179  RCP<const MultiVectorBase<Scalar> > adjoint_mv =
180  rcp_dynamic_cast<const DMVPV>(adjoint_x)->getMultiVector();
181  if (mass_matrix_is_identity_)
182  dxdp_init_->apply(Thyra::CONJTRANS, *adjoint_mv, dgdp_.ptr(), Scalar(1.0),
183  Scalar(1.0));
184  else {
185  inargs.set_t(initial_state->getTime());
186  inargs.set_x(initial_state->getX());
187  inargs.set_x_dot(initial_state->getXDot());
188  inargs.set_alpha(1.0);
189  inargs.set_beta(0.0);
190  RCP<LinearOpBase<Scalar> > W_op = model_->create_W_op();
191  outargs.set_W_op(W_op);
192  model_->evalModel(inargs, outargs);
193  outargs.set_W_op(Teuchos::null);
194  RCP<MultiVectorBase<Scalar> > tmp = createMembers(x_space, num_g);
195  W_op->apply(Thyra::CONJTRANS, *adjoint_mv, tmp.ptr(), Scalar(1.0),
196  Scalar(0.0));
197  dxdp_init_->apply(Thyra::CONJTRANS, *tmp, dgdp_.ptr(), Scalar(1.0),
198  Scalar(1.0));
199  }
200  }
201 
202  // Add in model parameter term = \int_0^T( (df/dp^T(t)*y(t) )dt which
203  // is computed during the adjoint integration as an auxiliary integral
204  // (2nd block of the solution vector)
205  if (f_depends_on_p_) {
206  RCP<const SolutionState<Scalar> > adjoint_state =
207  adjoint_solution_history->getCurrentState();
208  RCP<const VectorBase<Scalar> > z =
209  rcp_dynamic_cast<const DPV>(adjoint_state->getX())->getVectorBlock(1);
210  RCP<const MultiVectorBase<Scalar> > z_mv =
211  rcp_dynamic_cast<const DMVPV>(z)->getMultiVector();
212  Thyra::V_VmV(dgdp_.ptr(), *dgdp_, *z_mv);
213  }
214 
215  buildSolutionHistory(state_solution_history, adjoint_solution_history);
216 
217  return state_status && sens_status;
218 }
219 
220 template<class Scalar>
221 Scalar
223 getTime() const
224 {
225  return solutionHistory_->getCurrentTime();
226 }
227 
228 template<class Scalar>
229 int
231 getIndex() const
232 {
233  return solutionHistory_->getCurrentIndex();
234 }
235 
236 template<class Scalar>
237 Status
239 getStatus() const
240 {
241  Status state_status = state_integrator_->getStatus();
242  Status sens_status = adjoint_integrator_->getStatus();
243  if (state_status == FAILED || sens_status == FAILED)
244  return FAILED;
245  if (state_status == WORKING || sens_status == WORKING)
246  return WORKING;
247  return PASSED;
248 }
249 
250 template<class Scalar>
253 getStepper() const
254 {
255  return state_integrator_->getStepper();
256 }
257 
258 template<class Scalar>
262 {
263  return state_integrator_->getTempusParameterList();
264 }
265 
266 template<class Scalar>
267 void
270 {
271  state_integrator_->setTempusParameterList(pl);
272  adjoint_integrator_->setTempusParameterList(pl);
273 }
274 
275 template<class Scalar>
279 {
280  return solutionHistory_;
281 }
282 
283 template<class Scalar>
287 {
288  return state_integrator_->getTimeStepControl();
289 }
290 
291 template<class Scalar>
295 {
296  return state_integrator_->getNonConstTimeStepControl();
297 }
298 
299 template<class Scalar>
304  Teuchos::RCP<const Thyra::VectorBase<Scalar> > xdotdot0,
306  Teuchos::RCP<const Thyra::MultiVectorBase<Scalar> > /* DxdotDp0 */,
307  Teuchos::RCP<const Thyra::MultiVectorBase<Scalar> > /* DxdotdotDp0 */)
308 {
309  state_integrator_->initializeSolutionHistory(t0, x0, xdot0, xdotdot0);
310  dxdp_init_ = DxDp0;
311 }
312 
313 template<class Scalar>
316 {
317  state_integrator_->setObserver(obs);
318  // Currently not setting observer on adjoint integrator because it isn't
319  // clear what we want to do with it
320  //adjoint_integrator_->setObserver(obs);
321 }
322 
323 template<class Scalar>
326 {
327  state_integrator_->initialize();
328  adjoint_integrator_->initialize();
329 }
330 
331 template<class Scalar>
334 getX() const
335 {
336  return state_integrator_->getX();
337 }
338 
339 template<class Scalar>
342 getXDot() const
343 {
344  return state_integrator_->getXDot();
345 }
346 
347 template<class Scalar>
350 getXDotDot() const
351 {
352  return state_integrator_->getXDotDot();
353 }
354 
355 template<class Scalar>
358 getDgDp() const
359 {
360  return dgdp_;
361 }
362 
363 template<class Scalar>
364 std::string
366 description() const
367 {
368  std::string name = "Tempus::IntegratorAdjointSensitivity";
369  return(name);
370 }
371 
372 template<class Scalar>
373 void
377  const Teuchos::EVerbosityLevel verbLevel) const
378 {
379 
380  auto l_out = Teuchos::fancyOStream( out.getOStream() );
381  l_out->setOutputToRootOnly(0);
382  *l_out << description() << "::describe" << std::endl;
383  state_integrator_->describe(out, verbLevel);
384  adjoint_integrator_->describe(out, verbLevel);
385 }
386 
387 template<class Scalar>
388 void
391 {
392  if (state_integrator_ != Teuchos::null)
393  state_integrator_->setParameterList(inputPL);
394  if (adjoint_integrator_ != Teuchos::null)
395  adjoint_integrator_->setParameterList(inputPL);
396  Teuchos::ParameterList& spl = inputPL->sublist("Sensitivities");
397  p_index_ = spl.get<int>("Sensitivity Parameter Index", 0);
398  g_index_ = spl.get<int>("Response Function Index", 0);
399  g_depends_on_p_ = spl.get<bool>("Response Depends on Parameters", true);
400  f_depends_on_p_ = spl.get<bool>("Residual Depends on Parameters", true);
401  ic_depends_on_p_ = spl.get<bool>("IC Depends on Parameters", true);
402  mass_matrix_is_identity_ = spl.get<bool>("Mass Matrix Is Identity", false);
403 }
404 
405 template<class Scalar>
409 {
410  state_integrator_->unsetParameterList();
411  return adjoint_integrator_->unsetParameterList();
412 }
413 
414 template<class Scalar>
418 {
419  using Teuchos::RCP;
421  using Teuchos::parameterList;
422 
423  RCP<ParameterList> pl = parameterList();
424  RCP<const ParameterList> integrator_pl =
425  state_integrator_->getValidParameters();
426  RCP<const ParameterList> sensitivity_pl =
428  pl->setParameters(*integrator_pl);
429  ParameterList& spl = pl->sublist("Sensitivities");
430  spl.setParameters(*sensitivity_pl);
431  spl.set<bool>("Response Depends on Parameters", true);
432  spl.set<bool>("Residual Depends on Parameters", true);
433  spl.set<bool>("IC Depends on Parameters", true);
434 
435  return pl;
436 }
437 
438 template<class Scalar>
442 {
443  return state_integrator_->getNonconstParameterList();
444 }
445 
446 template <class Scalar>
452 {
453  using Teuchos::RCP;
454  using Teuchos::rcp;
456 
457  RCP<ParameterList> spl = Teuchos::parameterList();
458  if (inputPL != Teuchos::null) {
459  *spl = inputPL->sublist("Sensitivities");
460  }
461  spl->remove("Response Depends on Parameters");
462  spl->remove("Residual Depends on Parameters");
463  spl->remove("IC Depends on Parameters");
464  const Scalar tfinal = state_integrator_->getTimeStepControl()->getFinalTime();
466  model, tfinal, spl));
467 }
468 
469 template<class Scalar>
470 void
473  const Teuchos::RCP<const SolutionHistory<Scalar> >& state_solution_history,
474  const Teuchos::RCP<const SolutionHistory<Scalar> >& adjoint_solution_history)
475 {
476  using Teuchos::RCP;
477  using Teuchos::rcp;
478  using Teuchos::rcp_dynamic_cast;
480  using Thyra::VectorBase;
483  using Thyra::createMembers;
484  using Thyra::multiVectorProductVector;
485  using Thyra::assign;
488 
489  // Create combined solution histories combining the forward and adjoint
490  // solutions. We do not include the auxiliary part from the adjoint solution.
491  RCP<ParameterList> shPL =
492  Teuchos::sublist(state_integrator_->getIntegratorParameterList(),
493  "Solution History", true);
494  solutionHistory_ = createSolutionHistoryPL<Scalar>(shPL);
495 
496  RCP<const VectorSpaceBase<Scalar> > x_space = model_->get_x_space();
497  RCP<const VectorSpaceBase<Scalar> > adjoint_space =
498  rcp_dynamic_cast<const DPVS>(adjoint_model_->get_x_space())->getBlock(0);
500  spaces[0] = x_space;
501  spaces[1] = adjoint_space;
502  RCP<const DPVS > prod_space = Thyra::productVectorSpace(spaces());
503 
504  int num_states = state_solution_history->getNumStates();
505  const Scalar t_final = state_integrator_->getTime();
506  for (int i=0; i<num_states; ++i) {
507  RCP<const SolutionState<Scalar> > forward_state =
508  (*state_solution_history)[i];
509  RCP<const SolutionState<Scalar> > adjoint_state =
510  adjoint_solution_history->findState(t_final-forward_state->getTime());
511 
512  // X
513  RCP<DPV> x = Thyra::defaultProductVector(prod_space);
514  RCP<const VectorBase<Scalar> > adjoint_x =
515  rcp_dynamic_cast<const DPV>(adjoint_state->getX())->getVectorBlock(0);
516  assign(x->getNonconstVectorBlock(0).ptr(), *(forward_state->getX()));
517  assign(x->getNonconstVectorBlock(1).ptr(), *(adjoint_x));
518  RCP<VectorBase<Scalar> > x_b = x;
519 
520  // X-Dot
521  RCP<DPV> x_dot = Thyra::defaultProductVector(prod_space);
522  RCP<const VectorBase<Scalar> > adjoint_x_dot =
523  rcp_dynamic_cast<const DPV>(adjoint_state->getXDot())->getVectorBlock(0);
524  assign(x_dot->getNonconstVectorBlock(0).ptr(), *(forward_state->getXDot()));
525  assign(x_dot->getNonconstVectorBlock(1).ptr(), *(adjoint_x_dot));
526  RCP<VectorBase<Scalar> > x_dot_b = x_dot;
527 
528  // X-Dot-Dot
529  RCP<DPV> x_dot_dot;
530  if (forward_state->getXDotDot() != Teuchos::null) {
531  x_dot_dot = Thyra::defaultProductVector(prod_space);
532  RCP<const VectorBase<Scalar> > adjoint_x_dot_dot =
533  rcp_dynamic_cast<const DPV>(
534  adjoint_state->getXDotDot())->getVectorBlock(0);
535  assign(x_dot_dot->getNonconstVectorBlock(0).ptr(),
536  *(forward_state->getXDotDot()));
537  assign(x_dot_dot->getNonconstVectorBlock(1).ptr(),
538  *(adjoint_x_dot_dot));
539  }
540  RCP<VectorBase<Scalar> > x_dot_dot_b = x_dot_dot;
541 
542  RCP<SolutionState<Scalar> > prod_state = forward_state->clone();
543  prod_state->setX(x_b);
544  prod_state->setXDot(x_dot_b);
545  prod_state->setXDotDot(x_dot_dot_b);
546  prod_state->setPhysicsState(Teuchos::null);
547  solutionHistory_->addState(prod_state);
548  }
549 }
550 
552 template<class Scalar>
557 {
560  return(integrator);
561 }
562 
564 template<class Scalar>
567 {
570  return(integrator);
571 }
572 
573 } // namespace Tempus
574 #endif // Tempus_IntegratorAdjointSensitivity_impl_hpp
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const override
Teuchos::RCP< Teuchos::ParameterList > getNonconstParameterList() override
virtual Teuchos::RCP< TimeStepControl< Scalar > > getNonConstTimeStepControl() override
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const override
static Teuchos::RCP< const Teuchos::ParameterList > getValidParameters()
T & get(const std::string &name, T def_value)
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getXDotDot() const
Get current the second time derivative of the solution, xdotdot.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
ModelEvaluator for forming adjoint sensitivity equations.
Teuchos::RCP< Teuchos::ParameterList > unsetParameterList() override
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getXDot() const
Get current the time derivative of the solution, xdot.
Teuchos::RCP< IntegratorAdjointSensitivity< Scalar > > integratorAdjointSensitivity(Teuchos::RCP< Teuchos::ParameterList > pList, const Teuchos::RCP< Thyra::ModelEvaluator< Scalar > > &model)
Nonmember constructor.
void buildSolutionHistory(const Teuchos::RCP< const SolutionHistory< Scalar > > &state_solution_history, const Teuchos::RCP< const SolutionHistory< Scalar > > &adjoint_solution_history)
virtual Teuchos::RCP< const Thyra::VectorBase< Scalar > > getX() const
Get current the solution, x.
bool remove(std::string const &name, bool throwIfNotExists=true)
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.
virtual Teuchos::RCP< Teuchos::ParameterList > getTempusParameterList() override
Return a copy of the Tempus ParameterList.
IntegratorObserver class for time integrators.
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< const TimeStepControl< Scalar > > getTimeStepControl() const override
Get the TimeStepControl.
virtual void setTempusParameterList(Teuchos::RCP< Teuchos::ParameterList > pl) override
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.
virtual void setObserver(Teuchos::RCP< IntegratorObserver< Scalar > > obs=Teuchos::null)
Set the Observer.
RCP< std::basic_ostream< char_type, traits_type > > getOStream()
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &pl) override
Time integrator suitable for adjoint sensitivity analysis.
virtual int getIndex() const override
Get current index.
Teuchos::RCP< AdjointAuxSensitivityModelEvaluator< Scalar > > createAdjointModel(const Teuchos::RCP< Thyra::ModelEvaluator< Scalar > > &model, const Teuchos::RCP< Teuchos::ParameterList > &inputPL)
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.