Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HarmonicOscillatorModel_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_TEST_HARMONIC_OSCILLATOR_MODEL_IMPL_HPP
11 #define TEMPUS_TEST_HARMONIC_OSCILLATOR_MODEL_IMPL_HPP
12 
13 #include "Teuchos_StandardParameterEntryValidators.hpp"
14 
15 #include "Thyra_DefaultSpmdVectorSpace.hpp"
16 #include "Thyra_DetachedVectorView.hpp"
17 #include "Thyra_DetachedMultiVectorView.hpp"
18 #include "Thyra_DefaultSerialDenseLinearOpWithSolveFactory.hpp"
19 #include "Thyra_DefaultMultiVectorLinearOpWithSolve.hpp"
20 #include "Thyra_DefaultLinearOpSource.hpp"
21 #include "Thyra_VectorStdOps.hpp"
22 #include <iostream>
23 
24 namespace Tempus_Test {
25 
26 template <class Scalar>
28  Teuchos::RCP<Teuchos::ParameterList> pList_, const bool use_accel_IC)
29  : out_(Teuchos::VerboseObjectBase::getDefaultOStream())
30 {
31  isInitialized_ = false;
32  setParameterList(pList_);
33  *out_ << "\n\nDamping coeff c = " << c_ << "\n";
34  *out_ << "Forcing coeff f = " << f_ << "\n";
35  *out_ << "x coeff k = " << k_ << "\n";
36  *out_ << "Mass coeff m = " << m_ << "\n";
37  // Divide all coefficients by m_
38  k_ /= m_;
39  f_ /= m_;
40  c_ /= m_;
41  m_ = 1.0;
42  // Set up space and initial guess for solution vector
43  vecLength_ = 1;
44  x_space_ = Thyra::defaultSpmdVectorSpace<Scalar>(vecLength_);
45  x_vec_ = createMember(x_space_);
46  Thyra::put_scalar(0.0, x_vec_.ptr());
47  x_dot_vec_ = createMember(x_space_);
48  Thyra::put_scalar(1.0, x_dot_vec_.ptr());
49  x_dot_dot_vec_ = createMember(x_space_);
50  // The following is the initial condition for the acceleration
51  // Commenting this out to check that IC for acceleration
52  // is computed correctly using displacement and velocity ICs
53  // inside 2nd order steppers.
54  // Thyra::put_scalar(f_-c_, x_dot_dot_vec_.ptr());
55  if (use_accel_IC == true) {
56  Thyra::put_scalar(-2.0, x_dot_dot_vec_.ptr());
57  }
58  else {
59  // Instead of real IC, putting arbitrary, incorrect IC to check correctness
60  // in stepper involving calculation of a IC.
61  Thyra::put_scalar(7.0, x_dot_dot_vec_.ptr());
62  }
63 
64  // Set up responses
65  numResponses_ = 1;
66  g_space_ = Thyra::defaultSpmdVectorSpace<Scalar>(numResponses_);
67 
69 }
70 
71 template <class Scalar>
74 {
75  using Thyra::VectorBase;
76  TEUCHOS_TEST_FOR_EXCEPTION(!isInitialized_, std::logic_error,
77  "Error, setupInOutArgs_ must be called first!\n");
79  double exact_t = t;
80  inArgs.set_t(exact_t);
81  Teuchos::RCP<VectorBase<Scalar> > exact_x = createMember(x_space_);
82  { // scope to delete DetachedVectorView
83  Thyra::DetachedVectorView<Scalar> exact_x_view(*exact_x);
84  if (k_ == 0) {
85  if (c_ == 0)
86  exact_x_view[0] = t * (1.0 + 0.5 * f_ * t);
87  else
88  exact_x_view[0] =
89  (c_ - f_) / (c_ * c_) * (1.0 - exp(-c_ * t)) + f_ * t / c_;
90  }
91  else {
92  exact_x_view[0] = 1.0 / sqrt(k_) * sin(sqrt(k_) * t) +
93  f_ / k_ * (1.0 - cos(sqrt(k_) * t));
94  }
95  }
96  inArgs.set_x(exact_x);
97  Teuchos::RCP<VectorBase<Scalar> > exact_x_dot = createMember(x_space_);
98  { // scope to delete DetachedVectorView
99  Thyra::DetachedVectorView<Scalar> exact_x_dot_view(*exact_x_dot);
100  if (k_ == 0) {
101  if (c_ == 0)
102  exact_x_dot_view[0] = 1.0 + f_ * t;
103  else
104  exact_x_dot_view[0] = (c_ - f_) / c_ * exp(-c_ * t) + f_ / c_;
105  }
106  else {
107  exact_x_dot_view[0] =
108  cos(sqrt(k_) * t) + f_ / sqrt(k_) * sin(sqrt(k_) * t);
109  }
110  }
111  inArgs.set_x_dot(exact_x_dot);
112  Teuchos::RCP<VectorBase<Scalar> > exact_x_dot_dot = createMember(x_space_);
113  { // scope to delete DetachedVectorView
114  Thyra::DetachedVectorView<Scalar> exact_x_dot_dot_view(*exact_x_dot_dot);
115  if (k_ == 0) {
116  if (c_ == 0)
117  exact_x_dot_dot_view[0] = f_;
118  else
119  exact_x_dot_dot_view[0] = (f_ - c_) * exp(-c_ * t);
120  }
121  else {
122  exact_x_dot_dot_view[0] =
123  f_ * cos(sqrt(k_) * t) - sqrt(k_) * sin(sqrt(k_) * t);
124  }
125  }
126  inArgs.set_x_dot_dot(exact_x_dot_dot);
127  return (inArgs);
128 }
129 
130 template <class Scalar>
133 {
134  return x_space_;
135 }
136 
137 template <class Scalar>
140 {
141  return x_space_;
142 }
143 
144 template <class Scalar>
147 {
148  TEUCHOS_TEST_FOR_EXCEPTION(!isInitialized_, std::logic_error,
149  "Error, setupInOutArgs_ must be called first!\n");
150  return nominalValues_;
151 }
152 
153 template <class Scalar>
156 {
158  this->get_W_factory();
159  Teuchos::RCP<Thyra::LinearOpBase<Scalar> > matrix = this->create_W_op();
161  Teuchos::rcp_dynamic_cast<Thyra::MultiVectorBase<Scalar> >(matrix, true);
162  Thyra::DetachedMultiVectorView<Scalar> matrix_view(*matrix_mv);
163  // IKT: is it necessary for W to be non-singular when initialized?
164  matrix_view(0, 0) = 1.0;
166  Thyra::linearOpWithSolve<Scalar>(*W_factory, matrix);
167  return W;
168 }
169 
170 template <class Scalar>
173 {
175  Thyra::createMembers(x_space_, vecLength_);
176  return (matrix);
177 }
178 
179 template <class Scalar>
182 {
184  Thyra::defaultSerialDenseLinearOpWithSolveFactory<Scalar>();
185  return W_factory;
186 }
187 
188 template <class Scalar>
191 {
192  setupInOutArgs_();
193  return inArgs_;
194 }
195 
196 // Private functions overridden from ModelEvaluatorDefaultBase
197 
198 template <class Scalar>
201 {
202  setupInOutArgs_();
203  return outArgs_;
204 }
205 
206 template <class Scalar>
209  const Thyra::ModelEvaluatorBase::OutArgs<Scalar> &outArgs) const
210 {
211  using Teuchos::RCP;
212  using Thyra::VectorBase;
213  TEUCHOS_TEST_FOR_EXCEPTION(!isInitialized_, std::logic_error,
214  "Error, setupInOutArgs_ must be called first!\n");
215 
216  RCP<const VectorBase<Scalar> > x_in = inArgs.get_x();
217  double beta = inArgs.get_beta();
218  if (!x_in.get()) {
220  true, std::logic_error,
221  "\n ERROR: HarmonicOscillatorModel requires x as InArgs.\n");
222  }
224  // IKT, FIXME: check that subDim() is the write routine to get local length of
225  // a Thyra::ConstDetachedVectorView
226  auto myVecLength = x_in_view.subDim();
227 
228  RCP<const VectorBase<Scalar> > x_dot_in = inArgs.get_x_dot();
229  double alpha = inArgs.get_alpha();
230 
231  RCP<const VectorBase<Scalar> > x_dotdot_in = inArgs.get_x_dot_dot();
232  double omega = inArgs.get_W_x_dot_dot_coeff();
233 
234  // Parse OutArgs
235  RCP<VectorBase<Scalar> > f_out = outArgs.get_f();
236  RCP<VectorBase<Scalar> > g_out = outArgs.get_g(0);
237  const RCP<Thyra::LinearOpBase<Scalar> > W_out = outArgs.get_W_op();
238 
239  Scalar neg_sign = 1.0;
240  // Explicit ODE
241  if (inArgs.get_x_dot_dot().is_null()) neg_sign = -1.0;
242 
243  // Populate residual and Jacobian
244  if (f_out != Teuchos::null) {
245  Thyra::DetachedVectorView<Scalar> f_out_view(*f_out);
246  for (int i = 0; i < myVecLength; i++) {
247  f_out_view[i] = f_;
248  }
249  if (x_dotdot_in != Teuchos::null) {
250  Thyra::ConstDetachedVectorView<Scalar> x_dotdot_in_view(*x_dotdot_in);
251  for (int i = 0; i < myVecLength; i++) {
252  f_out_view[i] = x_dotdot_in_view[i] - f_out_view[i];
253  }
254  }
255  if (x_dot_in != Teuchos::null) {
256  Thyra::ConstDetachedVectorView<Scalar> x_dot_in_view(*x_dot_in);
257  for (int i = 0; i < myVecLength; i++) {
258  f_out_view[i] += neg_sign * c_ * x_dot_in_view[i];
259  }
260  }
261  if (x_in != Teuchos::null) {
262  for (int i = 0; i < myVecLength; i++) {
263  f_out_view[i] += neg_sign * k_ * x_in_view[i];
264  }
265  }
266  }
267 
268  // Note: W = alpha*df/dxdot + beta*df/dx + omega*df/dxdotdot
269  if (W_out != Teuchos::null) {
271  Teuchos::rcp_dynamic_cast<Thyra::MultiVectorBase<Scalar> >(W_out, true);
272  Thyra::DetachedMultiVectorView<Scalar> matrix_view(*matrix);
273  if (omega == 0.0) {
275  true, std::logic_error,
276  "\n ERROR: omega = 0 in HarmonicOscillatorModel!\n");
277  }
278  matrix_view(0, 0) = omega;
279  if (x_dot_in != Teuchos::null) {
280  matrix_view(0, 0) += neg_sign * c_ * alpha;
281  }
282  if (x_in != Teuchos::null) {
283  matrix_view(0, 0) += neg_sign * k_ * beta;
284  }
285  }
286 
287  // Calculated response(s) g
288  // g = mean value of x
289  if (g_out != Teuchos::null) {
290  Thyra::DetachedVectorView<Scalar> g_out_view(*g_out);
291  g_out_view[0] = Thyra::sum(*x_in) / vecLength_;
292  }
293 }
294 
295 template <class Scalar>
298 {
300  true, std::logic_error,
301  "\n Error! HarmonicOscillatorModel::get_p_space() is not supported!\n");
302  return Teuchos::null;
303 }
304 
305 template <class Scalar>
308 {
310  true, std::logic_error,
311  "\n Error! HarmonicOscillatorModel::get_p_names() is not supported!\n");
312  return Teuchos::null;
313 }
314 
315 template <class Scalar>
318 {
320  j != 0, std::logic_error,
321  "\n Error! HarmonicOscillatorModel::get_g_space() only "
322  << " supports 1 parameter vector. Supplied index l = " << j << "\n");
323  return g_space_;
324 }
325 
326 // private
327 
328 template <class Scalar>
330 {
331  if (isInitialized_) return;
332 
333  // Set up InArgs
335  inArgs.setModelEvalDescription(this->description());
336  inArgs.set_Np(0);
337  inArgs.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_x);
338  inArgs.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_x_dot);
339  inArgs.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_x_dot_dot);
340  inArgs.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_t);
341  inArgs.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_W_x_dot_dot_coeff);
342  inArgs.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_alpha);
343  inArgs.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_beta);
344  inArgs_ = inArgs;
345 
346  // Set up OutArgs
348  outArgs.setModelEvalDescription(this->description());
349  outArgs.set_Np_Ng(0, numResponses_);
350 
351  outArgs.setSupports(Thyra::ModelEvaluatorBase::OUT_ARG_f);
352  outArgs.setSupports(Thyra::ModelEvaluatorBase::OUT_ARG_W_op);
353  // outArgs.setSupports(OUT_ARG_W,true);
354  // IKT, what is the following supposed to do??
355  // outArgs.set_W_properties( DerivativeProperties(
356  // DERIV_LINEARITY_UNKNOWN, DERIV_RANK_FULL, true));
357  outArgs_ = outArgs;
358 
359  // Set up nominal values
360  nominalValues_ = inArgs_;
361  nominalValues_.set_t(0.0);
362  nominalValues_.set_x(x_vec_);
363  nominalValues_.set_x_dot(x_dot_vec_);
364  nominalValues_.set_x_dot_dot(x_dot_dot_vec_);
365 
366  isInitialized_ = true;
367 }
368 
369 template <class Scalar>
371  Teuchos::RCP<Teuchos::ParameterList> const &paramList)
372 {
373  using Teuchos::get;
375  using Teuchos::RCP;
376  RCP<ParameterList> tmpPL =
377  Teuchos::rcp(new ParameterList("HarmonicOscillatorModel"));
378  if (paramList != Teuchos::null) tmpPL = paramList;
379  tmpPL->validateParametersAndSetDefaults(*this->getValidParameters());
380  this->setMyParamList(tmpPL);
381  RCP<ParameterList> pl = this->getMyNonconstParamList();
382  c_ = get<Scalar>(*pl, "Damping coeff c");
383  f_ = get<Scalar>(*pl, "Forcing coeff f");
384  k_ = get<Scalar>(*pl, "x coeff k");
385  m_ = get<Scalar>(*pl, "Mass coeff m");
386  if (m_ <= 0.0) {
387  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
388  "Error: invalid value of Mass coeff m = "
389  << m_ << "! Mass coeff m must be > 0.\n");
390  }
391  if (k_ < 0.0) {
392  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
393  "Error: invalid value of x coeff k = "
394  << k_ << "! x coeff k must be >= 0.\n");
395  }
396  if ((k_ > 0.0) && (c_ != 0.0)) {
398  true, std::logic_error,
399  "Error: HarmonicOscillator model only supports x coeff k > 0 when "
400  "Damping coeff c = 0. You have "
401  << "specified x coeff k = " << k_ << " and Damping coeff c = " << c_
402  << ".\n");
403  }
404 }
405 
406 template <class Scalar>
409 {
411  if (is_null(validPL)) {
412  Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
413  validPL = pl;
414  Teuchos::setDoubleParameter("Damping coeff c", 0.0,
415  "Damping coefficient in model", &*pl);
416  Teuchos::setDoubleParameter("Forcing coeff f", -1.0,
417  "Forcing coefficient in model", &*pl);
418  Teuchos::setDoubleParameter("x coeff k", 0.0, "x coefficient in model",
419  &*pl);
420  Teuchos::setDoubleParameter("Mass coeff m", 1.0,
421  "Mass coefficient in model", &*pl);
422  }
423  return validPL;
424 }
425 
426 } // namespace Tempus_Test
427 #endif // TEMPUS_TEST_HARMONIC_OSCILLATOR_MODEL_IMPL_HPP
Thyra::ModelEvaluatorBase::InArgs< Scalar > getNominalValues() const
Thyra::ModelEvaluatorBase::OutArgs< Scalar > createOutArgsImpl() const
bool is_null(const boost::shared_ptr< T > &p)
void set_x_dot_dot(const RCP< const VectorBase< Scalar > > &x_dot_dot)
RCP< const VectorBase< Scalar > > get_x_dot() const
void setModelEvalDescription(const std::string &modelEvalDescription)
Teuchos::RCP< Thyra::VectorBase< Scalar > > x_dot_vec_
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > g_space_
Teuchos::RCP< const Thyra::LinearOpWithSolveFactoryBase< Scalar > > get_W_factory() const
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Evaluation< VectorBase< Scalar > > get_g(int j) const
Evaluation< VectorBase< Scalar > > get_f() const
T * get() const
Teuchos::RCP< const Teuchos::Array< std::string > > get_p_names(int l) const
Thyra::ModelEvaluatorBase::InArgs< Scalar > getExactSolution(double t) const
void evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs_bar, const Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs_bar) const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_x_space() const
void setSupports(EInArgsMembers arg, bool supports=true)
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_g_space(int j) const
void set_x(const RCP< const VectorBase< Scalar > > &x)
Teuchos::RCP< Teuchos::FancyOStream > out_
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< Thyra::VectorBase< Scalar > > x_dot_dot_vec_
Teuchos_Ordinal subDim() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int l) const
Teuchos::RCP< Thyra::LinearOpWithSolveBase< Scalar > > create_W() const
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
void set_x_dot(const RCP< const VectorBase< Scalar > > &x_dot)
void setParameterList(Teuchos::RCP< Teuchos::ParameterList > const &paramList)
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > x_space_
void setSupports(EOutArgsMembers arg, bool supports=true)
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_W_op() const
HarmonicOscillatorModel(Teuchos::RCP< Teuchos::ParameterList > pList=Teuchos::null, const bool use_accel_IC=false)
Teuchos::RCP< Thyra::VectorBase< Scalar > > x_vec_
RCP< const VectorBase< Scalar > > get_x_dot_dot() const
void setModelEvalDescription(const std::string &modelEvalDescription)
Thyra::ModelEvaluatorBase::InArgs< Scalar > createInArgs() const
RCP< LinearOpBase< Scalar > > get_W_op() const
RCP< const VectorBase< Scalar > > get_x() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_f_space() const