Tempus Version of the Day
Time Integration
Loading...
Searching...
No Matches
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
24namespace Tempus_Test {
25
26template <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
71template <class Scalar>
72Thyra::ModelEvaluatorBase::InArgs<Scalar>
74{
76 TEUCHOS_TEST_FOR_EXCEPTION(!isInitialized_, std::logic_error,
77 "Error, setupInOutArgs_ must be called first!\n");
78 Thyra::ModelEvaluatorBase::InArgs<Scalar> inArgs = inArgs_;
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
130template <class Scalar>
131Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
133{
134 return x_space_;
135}
136
137template <class Scalar>
138Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
140{
141 return x_space_;
142}
143
144template <class Scalar>
145Thyra::ModelEvaluatorBase::InArgs<Scalar>
147{
148 TEUCHOS_TEST_FOR_EXCEPTION(!isInitialized_, std::logic_error,
149 "Error, setupInOutArgs_ must be called first!\n");
150 return nominalValues_;
151}
152
153template <class Scalar>
154Teuchos::RCP<Thyra::LinearOpWithSolveBase<Scalar> >
156{
157 Teuchos::RCP<const Thyra::LinearOpWithSolveFactoryBase<Scalar> > W_factory =
158 this->get_W_factory();
159 Teuchos::RCP<Thyra::LinearOpBase<Scalar> > matrix = this->create_W_op();
160 Teuchos::RCP<Thyra::MultiVectorBase<Scalar> > matrix_mv =
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;
165 Teuchos::RCP<Thyra::LinearOpWithSolveBase<Scalar> > W =
166 Thyra::linearOpWithSolve<Scalar>(*W_factory, matrix);
167 return W;
168}
169
170template <class Scalar>
171Teuchos::RCP<Thyra::LinearOpBase<Scalar> >
173{
174 Teuchos::RCP<Thyra::MultiVectorBase<Scalar> > matrix =
175 Thyra::createMembers(x_space_, vecLength_);
176 return (matrix);
177}
178
179template <class Scalar>
180Teuchos::RCP<const Thyra::LinearOpWithSolveFactoryBase<Scalar> >
182{
183 Teuchos::RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> > W_factory =
184 Thyra::defaultSerialDenseLinearOpWithSolveFactory<Scalar>();
185 return W_factory;
186}
187
188template <class Scalar>
189Thyra::ModelEvaluatorBase::InArgs<Scalar>
191{
192 setupInOutArgs_();
193 return inArgs_;
194}
195
196// Private functions overridden from ModelEvaluatorDefaultBase
197
198template <class Scalar>
199Thyra::ModelEvaluatorBase::OutArgs<Scalar>
201{
202 setupInOutArgs_();
203 return outArgs_;
204}
205
206template <class Scalar>
208 const Thyra::ModelEvaluatorBase::InArgs<Scalar> &inArgs,
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()) {
219 TEUCHOS_TEST_FOR_EXCEPTION(
220 true, std::logic_error,
221 "\n ERROR: HarmonicOscillatorModel requires x as InArgs.\n");
222 }
223 Thyra::ConstDetachedVectorView<Scalar> x_in_view(*x_in);
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) {
270 RCP<Thyra::MultiVectorBase<Scalar> > matrix =
271 Teuchos::rcp_dynamic_cast<Thyra::MultiVectorBase<Scalar> >(W_out, true);
272 Thyra::DetachedMultiVectorView<Scalar> matrix_view(*matrix);
273 if (omega == 0.0) {
274 TEUCHOS_TEST_FOR_EXCEPTION(
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
295template <class Scalar>
296Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
298{
299 TEUCHOS_TEST_FOR_EXCEPTION(
300 true, std::logic_error,
301 "\n Error! HarmonicOscillatorModel::get_p_space() is not supported!\n");
302 return Teuchos::null;
303}
304
305template <class Scalar>
306Teuchos::RCP<const Teuchos::Array<std::string> >
308{
309 TEUCHOS_TEST_FOR_EXCEPTION(
310 true, std::logic_error,
311 "\n Error! HarmonicOscillatorModel::get_p_names() is not supported!\n");
312 return Teuchos::null;
313}
314
315template <class Scalar>
316Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> >
318{
319 TEUCHOS_TEST_FOR_EXCEPTION(
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
328template <class Scalar>
330{
331 if (isInitialized_) return;
332
333 // Set up InArgs
334 Thyra::ModelEvaluatorBase::InArgsSetup<Scalar> 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
347 Thyra::ModelEvaluatorBase::OutArgsSetup<Scalar> 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
369template <class Scalar>
371 Teuchos::RCP<Teuchos::ParameterList> const &paramList)
372{
373 using Teuchos::get;
374 using Teuchos::ParameterList;
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)) {
397 TEUCHOS_TEST_FOR_EXCEPTION(
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
406template <class Scalar>
407Teuchos::RCP<const Teuchos::ParameterList>
409{
410 static Teuchos::RCP<const Teuchos::ParameterList> validPL;
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
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_x_space() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_p_space(int l) const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > g_space_
Teuchos::RCP< const Teuchos::Array< std::string > > get_p_names(int l) const
Teuchos::RCP< Thyra::VectorBase< Scalar > > x_dot_vec_
Teuchos::RCP< Thyra::VectorBase< Scalar > > x_vec_
Thyra::ModelEvaluatorBase::InArgs< Scalar > createInArgs() const
Thyra::ModelEvaluatorBase::InArgs< Scalar > getNominalValues() const
Thyra::ModelEvaluatorBase::InArgs< Scalar > getExactSolution(double t) const
void setParameterList(Teuchos::RCP< Teuchos::ParameterList > const &paramList)
Teuchos::RCP< Thyra::LinearOpWithSolveBase< Scalar > > create_W() const
Teuchos::RCP< Teuchos::FancyOStream > out_
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_g_space(int j) const
void evalModelImpl(const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs_bar, const Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs_bar) const
Teuchos::RCP< Thyra::VectorBase< Scalar > > x_dot_dot_vec_
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Teuchos::RCP< const Thyra::LinearOpWithSolveFactoryBase< Scalar > > get_W_factory() const
HarmonicOscillatorModel(Teuchos::RCP< Teuchos::ParameterList > pList=Teuchos::null, const bool use_accel_IC=false)
Teuchos::RCP< Thyra::LinearOpBase< Scalar > > create_W_op() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > get_f_space() const
Thyra::ModelEvaluatorBase::OutArgs< Scalar > createOutArgsImpl() const
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > x_space_