Tempus Version of the Day
Time Integration
Loading...
Searching...
No Matches
Tempus_DIRK_ASA.cpp
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#include "Teuchos_UnitTestHarness.hpp"
11#include "Teuchos_XMLParameterListHelpers.hpp"
12#include "Teuchos_TimeMonitor.hpp"
13#include "Teuchos_DefaultComm.hpp"
14
15#include "Thyra_VectorStdOps.hpp"
16#include "Thyra_MultiVectorStdOps.hpp"
17
18#include "Tempus_IntegratorBasic.hpp"
19#include "Tempus_IntegratorAdjointSensitivity.hpp"
20
21#include "Thyra_DefaultMultiVectorProductVector.hpp"
22#include "Thyra_DefaultProductVector.hpp"
23
24#include "../TestModels/SinCosModel.hpp"
27
28#include <fstream>
29#include <vector>
30
31namespace Tempus_Test {
32
33using Teuchos::getParametersFromXmlFile;
34using Teuchos::ParameterList;
35using Teuchos::RCP;
36using Teuchos::sublist;
37
38using Tempus::IntegratorBasic;
39using Tempus::SolutionHistory;
40using Tempus::SolutionState;
41
42// ************************************************************
43// ************************************************************
44TEUCHOS_UNIT_TEST(DIRK, SinCos_ASA)
45{
46 std::vector<std::string> RKMethods;
47 RKMethods.push_back("General DIRK");
48 RKMethods.push_back("RK Backward Euler");
49 RKMethods.push_back("DIRK 1 Stage Theta Method");
50 RKMethods.push_back("RK Implicit 1 Stage 1st order Radau IA");
51 RKMethods.push_back("SDIRK 2 Stage 2nd order");
52 RKMethods.push_back("RK Implicit 2 Stage 2nd order Lobatto IIIB");
53 RKMethods.push_back("SDIRK 2 Stage 3rd order");
54 RKMethods.push_back("EDIRK 2 Stage 3rd order");
55 RKMethods.push_back("EDIRK 2 Stage Theta Method");
56 RKMethods.push_back("SDIRK 3 Stage 4th order");
57 RKMethods.push_back("SDIRK 5 Stage 4th order");
58 RKMethods.push_back("SDIRK 5 Stage 5th order");
59
60 std::vector<double> RKMethodErrors;
61 RKMethodErrors.push_back(8.48235e-05);
62 RKMethodErrors.push_back(0.0383339);
63 RKMethodErrors.push_back(0.000221028);
64 RKMethodErrors.push_back(0.0428449);
65 RKMethodErrors.push_back(8.48235e-05);
66 RKMethodErrors.push_back(0.000297933);
67 RKMethodErrors.push_back(4.87848e-06);
68 RKMethodErrors.push_back(7.30827e-07);
69 RKMethodErrors.push_back(0.000272997);
70 RKMethodErrors.push_back(3.10132e-07);
71 RKMethodErrors.push_back(7.56838e-10);
72 RKMethodErrors.push_back(1.32374e-10);
73
74 Teuchos::RCP<const Teuchos::Comm<int> > comm =
75 Teuchos::DefaultComm<int>::getComm();
76
77 for (std::vector<std::string>::size_type m = 0; m != RKMethods.size(); m++) {
78 std::string RKMethod_ = RKMethods[m];
79 std::replace(RKMethod_.begin(), RKMethod_.end(), ' ', '_');
80 std::replace(RKMethod_.begin(), RKMethod_.end(), '/', '.');
81 std::vector<double> StepSize;
82 std::vector<double> ErrorNorm;
83 const int nTimeStepSizes = 2; // 7 for error plots
84 double dt = 0.05;
85 double order = 0.0;
86 for (int n = 0; n < nTimeStepSizes; n++) {
87 // Read params from .xml file
88 RCP<ParameterList> pList =
89 getParametersFromXmlFile("Tempus_DIRK_SinCos.xml");
90
91 // Setup the SinCosModel
92 RCP<ParameterList> scm_pl = sublist(pList, "SinCosModel", true);
93 RCP<SinCosModel<double> > model =
94 Teuchos::rcp(new SinCosModel<double>(scm_pl));
95
96 // Set the Stepper
97 RCP<ParameterList> pl = sublist(pList, "Tempus", true);
98 pl->sublist("Default Stepper").set("Stepper Type", RKMethods[m]);
99 if (RKMethods[m] == "DIRK 1 Stage Theta Method" ||
100 RKMethods[m] == "EDIRK 2 Stage Theta Method") {
101 pl->sublist("Default Stepper").set<double>("theta", 0.5);
102 }
103 else if (RKMethods[m] == "SDIRK 2 Stage 2nd order") {
104 pl->sublist("Default Stepper").set("gamma", 0.2928932188134524);
105 }
106 else if (RKMethods[m] == "SDIRK 2 Stage 3rd order") {
107 pl->sublist("Default Stepper")
108 .set<std::string>("Gamma Type", "3rd Order A-stable");
109 }
110
111 dt /= 2;
112
113 // Setup sensitivities
114 ParameterList& sens_pl = pl->sublist("Sensitivities");
115 sens_pl.set("Mass Matrix Is Identity", true); // Necessary for explicit
116 ParameterList& interp_pl = pl->sublist("Default Integrator")
117 .sublist("Solution History")
118 .sublist("Interpolator");
119 interp_pl.set("Interpolator Type", "Lagrange");
120 interp_pl.set("Order", 4); // All RK methods here are at most 5th order
121
122 // Setup the Integrator and reset initial time step
123 pl->sublist("Default Integrator")
124 .sublist("Time Step Control")
125 .set("Initial Time Step", dt);
126 RCP<Tempus::IntegratorAdjointSensitivity<double> > integrator =
128 order = integrator->getStepper()->getOrder();
129
130 // Initial Conditions
131 // During the Integrator construction, the initial SolutionState
132 // is set by default to model->getNominalVales().get_x(). However,
133 // the application can set it also by
134 // integrator->initializeSolutionHistory.
135 RCP<Thyra::VectorBase<double> > x0 =
136 model->getNominalValues().get_x()->clone_v();
137 const int num_param = model->get_p_space(0)->dim();
138 RCP<Thyra::MultiVectorBase<double> > DxDp0 =
139 Thyra::createMembers(model->get_x_space(), num_param);
140 for (int i = 0; i < num_param; ++i)
141 Thyra::assign(DxDp0->col(i).ptr(),
142 *(model->getExactSensSolution(i, 0.0).get_x()));
143 integrator->initializeSolutionHistory(0.0, x0, Teuchos::null,
144 Teuchos::null, DxDp0, Teuchos::null,
145 Teuchos::null);
146
147 // Integrate to timeMax
148 bool integratorStatus = integrator->advanceTime();
149 TEST_ASSERT(integratorStatus)
150
151 // Test if at 'Final Time'
152 double time = integrator->getTime();
153 double timeFinal = pl->sublist("Default Integrator")
154 .sublist("Time Step Control")
155 .get<double>("Final Time");
156 double tol = 100.0 * std::numeric_limits<double>::epsilon();
157 TEST_FLOATING_EQUALITY(time, timeFinal, tol);
158
159 // Time-integrated solution and the exact solution along with
160 // sensitivities (relying on response g(x) = x). Note we must transpose
161 // dg/dp since the integrator returns it in gradient form.
162 RCP<const Thyra::VectorBase<double> > x = integrator->getX();
163 RCP<const Thyra::MultiVectorBase<double> > DgDp = integrator->getDgDp();
164 RCP<Thyra::MultiVectorBase<double> > DxDp =
165 Thyra::createMembers(model->get_x_space(), num_param);
166 {
167 Thyra::ConstDetachedMultiVectorView<double> dgdp_view(*DgDp);
168 Thyra::DetachedMultiVectorView<double> dxdp_view(*DxDp);
169 const int num_g = DgDp->domain()->dim();
170 for (int i = 0; i < num_g; ++i)
171 for (int j = 0; j < num_param; ++j) dxdp_view(i, j) = dgdp_view(j, i);
172 }
173 RCP<const Thyra::VectorBase<double> > x_exact =
174 model->getExactSolution(time).get_x();
175 RCP<Thyra::MultiVectorBase<double> > DxDp_exact =
176 Thyra::createMembers(model->get_x_space(), num_param);
177 for (int i = 0; i < num_param; ++i)
178 Thyra::assign(DxDp_exact->col(i).ptr(),
179 *(model->getExactSensSolution(i, time).get_x()));
180
181 // Plot sample solution and exact solution
182 if (comm->getRank() == 0 && n == nTimeStepSizes - 1) {
183 typedef Thyra::DefaultProductVector<double> DPV;
184 typedef Thyra::DefaultMultiVectorProductVector<double> DMVPV;
185
186 std::ofstream ftmp("Tempus_" + RKMethod_ + "_SinCos_AdjSens.dat");
187 RCP<const SolutionHistory<double> > solutionHistory =
188 integrator->getSolutionHistory();
189 for (int i = 0; i < solutionHistory->getNumStates(); i++) {
190 RCP<const SolutionState<double> > solutionState =
191 (*solutionHistory)[i];
192 const double time_i = solutionState->getTime();
193 RCP<const DPV> x_prod_plot =
194 Teuchos::rcp_dynamic_cast<const DPV>(solutionState->getX());
195 RCP<const Thyra::VectorBase<double> > x_plot =
196 x_prod_plot->getVectorBlock(0);
197 RCP<const DMVPV> adjoint_prod_plot =
198 Teuchos::rcp_dynamic_cast<const DMVPV>(
199 x_prod_plot->getVectorBlock(1));
200 RCP<const Thyra::MultiVectorBase<double> > adjoint_plot =
201 adjoint_prod_plot->getMultiVector();
202 RCP<const Thyra::VectorBase<double> > x_exact_plot =
203 model->getExactSolution(time_i).get_x();
204 ftmp << std::fixed << std::setprecision(7) << time_i << std::setw(11)
205 << get_ele(*(x_plot), 0) << std::setw(11)
206 << get_ele(*(x_plot), 1) << std::setw(11)
207 << get_ele(*(adjoint_plot->col(0)), 0) << std::setw(11)
208 << get_ele(*(adjoint_plot->col(0)), 1) << std::setw(11)
209 << get_ele(*(adjoint_plot->col(1)), 0) << std::setw(11)
210 << get_ele(*(adjoint_plot->col(1)), 1) << std::setw(11)
211 << get_ele(*(x_exact_plot), 0) << std::setw(11)
212 << get_ele(*(x_exact_plot), 1) << std::endl;
213 }
214 ftmp.close();
215 }
216
217 // Calculate the error
218 RCP<Thyra::VectorBase<double> > xdiff = x->clone_v();
219 RCP<Thyra::MultiVectorBase<double> > DxDpdiff = DxDp->clone_mv();
220 Thyra::V_StVpStV(xdiff.ptr(), 1.0, *x_exact, -1.0, *(x));
221 Thyra::V_VmV(DxDpdiff.ptr(), *DxDp_exact, *DxDp);
222 StepSize.push_back(dt);
223 double L2norm = Thyra::norm_2(*xdiff);
224 L2norm *= L2norm;
225 Teuchos::Array<double> L2norm_DxDp(num_param);
226 Thyra::norms_2(*DxDpdiff, L2norm_DxDp());
227 for (int i = 0; i < num_param; ++i)
228 L2norm += L2norm_DxDp[i] * L2norm_DxDp[i];
229 L2norm = std::sqrt(L2norm);
230 ErrorNorm.push_back(L2norm);
231
232 // out << " n = " << n << " dt = " << dt << " error = " << L2norm
233 // << std::endl;
234 }
235
236 if (comm->getRank() == 0) {
237 std::ofstream ftmp("Tempus_" + RKMethod_ + "_SinCos_AdjSens-Error.dat");
238 double error0 = 0.8 * ErrorNorm[0];
239 for (int n = 0; n < (int)StepSize.size(); n++) {
240 ftmp << StepSize[n] << " " << ErrorNorm[n] << " "
241 << error0 * (pow(StepSize[n] / StepSize[0], order)) << std::endl;
242 }
243 ftmp.close();
244 }
245
246 // if (RKMethods[m] == "SDIRK 5 Stage 4th order") {
247 // StepSize.pop_back(); StepSize.pop_back();
248 // ErrorNorm.pop_back(); ErrorNorm.pop_back();
249 // } else if (RKMethods[m] == "SDIRK 5 Stage 5th order") {
250 // StepSize.pop_back(); StepSize.pop_back(); StepSize.pop_back();
251 // ErrorNorm.pop_back(); ErrorNorm.pop_back(); ErrorNorm.pop_back();
252 // }
253
254 // Check the order and intercept
255 double slope = computeLinearRegressionLogLog<double>(StepSize, ErrorNorm);
256 out << " Stepper = " << RKMethods[m] << std::endl;
257 out << " =========================" << std::endl;
258 out << " Expected order: " << order << std::endl;
259 out << " Observed order: " << slope << std::endl;
260 out << " =========================" << std::endl;
261 TEST_FLOATING_EQUALITY(slope, order, 0.03);
262 TEST_FLOATING_EQUALITY(ErrorNorm[0], RKMethodErrors[m], 5.0e-4);
263 }
264 Teuchos::TimeMonitor::summarize();
265}
266
267// ************************************************************
268// ************************************************************
269// Adjoint sensitivities of the time-integrated response
270// J = int_{t0}^{T} x(t) dt, with SDIRK 2 Stage 2nd order.
271TEUCHOS_UNIT_TEST(DIRK, SinCos_ASA_TimeIntegral)
272{
273 std::vector<double> StepSize, ErrorNorm;
274 double order = 0.0;
276 "Tempus_DIRK_SinCos.xml",
277 [](ParameterList& pl) {
278 pl.sublist("Default Stepper")
279 .set("Stepper Type", "SDIRK 2 Stage 2nd order");
280 pl.sublist("Default Stepper").set("gamma", 0.2928932188134524);
281 pl.sublist("Default Stepper")
282 .set("Initial Condition Consistency", "None");
283 pl.sublist("Default Stepper")
284 .set("Initial Condition Consistency Check", false);
285 pl.sublist("Sensitivities").set("Mass Matrix Is Identity", true);
286 // The stage times are between the time steps, a 2nd order method
287 // needs linear interpolation of the forward solution.
288 ParameterList& interp_pl = pl.sublist("Default Integrator")
289 .sublist("Solution History")
290 .sublist("Interpolator");
291 interp_pl.set("Interpolator Type", "Lagrange");
292 interp_pl.set("Order", 1);
293 },
294 "Time Integral", std::vector<double>(), 5, 0.1, false, StepSize, ErrorNorm,
295 order, out, success);
296
297 const double slope = computeLinearRegressionLogLog<double>(StepSize, ErrorNorm);
298 out << " Expected order: " << order << " Observed order: " << slope << std::endl;
299 TEST_FLOATING_EQUALITY(slope, order, 0.04);
300}
301
302// ************************************************************
303// ************************************************************
304// Adjoint sensitivities of the response J = sum_k x(t_k), including the
305// initial and final times, with SDIRK 2 Stage 2nd order.
306TEUCHOS_UNIT_TEST(DIRK, SinCos_ASA_SumOverTimes)
307{
308 std::vector<double> StepSize, ErrorNorm;
309 double order = 0.0;
311 "Tempus_DIRK_SinCos.xml",
312 [](ParameterList& pl) {
313 pl.sublist("Default Stepper")
314 .set("Stepper Type", "SDIRK 2 Stage 2nd order");
315 pl.sublist("Default Stepper").set("gamma", 0.2928932188134524);
316 pl.sublist("Default Stepper")
317 .set("Initial Condition Consistency", "None");
318 pl.sublist("Default Stepper")
319 .set("Initial Condition Consistency Check", false);
320 pl.sublist("Sensitivities").set("Mass Matrix Is Identity", true);
321 // The stage times are between the time steps, a 2nd order method
322 // needs linear interpolation of the forward solution.
323 ParameterList& interp_pl = pl.sublist("Default Integrator")
324 .sublist("Solution History")
325 .sublist("Interpolator");
326 interp_pl.set("Interpolator Type", "Lagrange");
327 interp_pl.set("Order", 1);
328 },
329 "Sum Over Times", {0.0, 0.3, 0.6, 1.0}, 5, 0.1, false, StepSize, ErrorNorm,
330 order, out, success);
331
332 const double slope = computeLinearRegressionLogLog<double>(StepSize, ErrorNorm);
333 out << " Expected order: " << order << " Observed order: " << slope << std::endl;
334 TEST_FLOATING_EQUALITY(slope, order, 0.04);
335}
336
337} // namespace Tempus_Test
Sine-Cosine model problem from Rythmos. This is a canonical Sine-Cosine differential equation.
TEUCHOS_UNIT_TEST(BackwardEuler, SinCos_ASA)
void computeSinCosAdjointResponseErrors(const std::string &xmlFile, const std::function< void(Teuchos::ParameterList &)> &configure, const std::string &responseType, const std::vector< double > &responseTimes, const int nTimeStepSizes, const double dt0, const bool useAdjointModel, std::vector< double > &stepSizes, std::vector< double > &errors, double &stepperOrder, Teuchos::FancyOStream &out, bool &success)
Solve the SinCos adjoint problem with the "Time Integral" or "Sum Over Times" response for a sequence...
Scalar computeLinearRegressionLogLog(std::vector< Scalar > &x, std::vector< Scalar > &y)
Teuchos::RCP< IntegratorAdjointSensitivity< Scalar > > createIntegratorAdjointSensitivity()
Nonmember constructor.