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