Tempus Version of the Day
Time Integration
Loading...
Searching...
No Matches
Tempus_ConvergenceTestUtils.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_CONVERGENCE_TEST_UTILS_HPP
11#define TEMPUS_CONVERGENCE_TEST_UTILS_HPP
12
13#include <fstream>
14
15#include "Teuchos_as.hpp"
16
19#include "Tempus_Stepper.hpp"
20
21namespace Tempus_Test {
22
26template <class Scalar>
28 public:
30 void setData(std::vector<Scalar>& x, std::vector<Scalar>& y);
31 Scalar getSlope() const;
32 Scalar getYIntercept() const;
33
34 private:
35 // Private functions
36 void compute_();
37 void validateXYData_(std::vector<Scalar>& x, std::vector<Scalar>& y);
38
39 // Private data
40 std::vector<Scalar> x_;
41 std::vector<Scalar> y_;
42 Scalar slope_;
45};
46
47// Member functions:
48
49template <class Scalar>
51{
52 isInitialized_ = false;
53}
54
55template <class Scalar>
56void LinearRegression<Scalar>::setData(std::vector<Scalar>& x,
57 std::vector<Scalar>& y)
58{
59 validateXYData_(x, y);
60 x_ = x; // copy x data
61 y_ = y; // copy y data
62 isInitialized_ = true;
63 compute_();
64}
65
66template <class Scalar>
68 std::vector<Scalar>& y)
69{
70 TEUCHOS_TEST_FOR_EXCEPTION(
71 x.size() != y.size(), std::logic_error,
72 "x and y data are note the same size for linear regression\n");
73 TEUCHOS_TEST_FOR_EXCEPTION(x.size() < 2, std::logic_error,
74 "Not enough data points for linear regression!\n");
75 int N = Teuchos::as<int>(x.size());
76 // There must be at least two unique x values
77 Scalar alpha = x[0];
78 int numUnique = 1;
79 for (int i = 1; i < N; ++i) {
80 if (x[i] != alpha) {
81 numUnique++;
82 }
83 }
84 TEUCHOS_TEST_FOR_EXCEPT(numUnique == 1);
85}
86
87template <class Scalar>
89{
90 TEUCHOS_TEST_FOR_EXCEPT(!isInitialized_);
91 return slope_;
92}
93
94template <class Scalar>
96{
97 TEUCHOS_TEST_FOR_EXCEPT(!isInitialized_);
98 return yIntercept_;
99}
100
101template <class Scalar>
103{
104 TEUCHOS_TEST_FOR_EXCEPT(!isInitialized_);
105 typedef Teuchos::ScalarTraits<Scalar> ST;
106
107 int N = Teuchos::as<int>(x_.size());
108
109 Scalar sum1 = ST::zero();
110 Scalar sum2 = ST::zero();
111 for (int i = 0; i < N; ++i) {
112 sum1 += x_[i] * y_[i];
113 sum2 += x_[i] * x_[i];
114 }
115 sum1 *= Scalar(-2 * ST::one());
116 sum2 *= Scalar(-2 * ST::one());
117
118 Scalar sum3 = ST::zero();
119 Scalar sum4 = ST::zero();
120 for (int i = 0; i < N; ++i) {
121 for (int j = 0; j < N; ++j) {
122 sum3 += x_[i] * y_[j];
123 sum4 += x_[i] * x_[j];
124 }
125 }
126 sum3 *= Scalar(2 * ST::one() / Scalar(N));
127 sum4 *= Scalar(2 * ST::one() / Scalar(N));
128
129 slope_ = (sum3 + sum1) / (sum4 + sum2);
130
131 yIntercept_ = ST::zero();
132 for (int i = 0; i < N; ++i) {
133 yIntercept_ += y_[i] - slope_ * x_[i];
134 }
135 yIntercept_ *= Scalar(ST::one() / Scalar(N));
136}
137
138// Nonmember helper functions:
139template <class Scalar>
140Scalar computeLinearRegression(std::vector<Scalar>& x, std::vector<Scalar>& y)
141{
143 lr.setData(x, y);
144 return (lr.getSlope());
145}
146
147template <class Scalar>
148void computeLinearRegression(std::vector<Scalar>& x, std::vector<Scalar>& y,
149 Scalar& slope, Scalar& yIntercept)
150{
152 lr.setData(x, y);
153 slope = lr.getSlope();
154 yIntercept = lr.getYIntercept();
155 return;
156}
157
158template <class Scalar>
159Scalar computeLinearRegressionLogLog(std::vector<Scalar>& x,
160 std::vector<Scalar>& y)
161{
162 TEUCHOS_TEST_FOR_EXCEPT(x.size() != y.size());
163 int N = Teuchos::as<int>(x.size());
164 std::vector<Scalar> xlog;
165 std::vector<Scalar> ylog;
166
167 for (int i = 0; i < N; ++i) {
168 if (!(Tempus::approxZero(x[i]) || Tempus::approxZero(y[i]))) {
169 xlog.push_back(log(x[i]));
170 ylog.push_back(log(y[i]));
171 }
172 }
173
175 lr.setData(xlog, ylog);
176 return (lr.getSlope());
177}
178
179template <class Scalar>
180Teuchos::RCP<LinearRegression<Scalar>> linearRegression()
181{
182 Teuchos::RCP<LinearRegression<Scalar>> lr =
183 Teuchos::rcp(new LinearRegression<Scalar>());
184 return lr;
185}
186
187template <class Scalar>
189 const std::string filename, Teuchos::RCP<Tempus::Stepper<Scalar>> stepper,
190 std::vector<Scalar>& StepSize,
191 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>>& solutions,
192 std::vector<Scalar>& xErrorNorm, Scalar& xSlope,
193 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>>& solutionsDot,
194 std::vector<Scalar>& xDotErrorNorm, Scalar& xDotSlope,
195 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>>& solutionsDotDot,
196 std::vector<Scalar>& xDotDotErrorNorm, Scalar& xDotDotSlope,
197 Teuchos::FancyOStream& out)
198{
199 if (solutions.empty()) {
200 out << "No solutions to write out!\n"
201 << std::endl;
202 return;
203 }
204 std::size_t lastElem = solutions.size() - 1; // Last element is the ref soln.
205 std::vector<Scalar> dt;
206
207 auto ref_solution = solutions[lastElem];
208 for (std::size_t i = 0; i < lastElem; ++i) {
209 dt.push_back(StepSize[i]);
210 auto tmp = solutions[i];
211 Thyra::Vp_StV(tmp.ptr(), -1.0, *ref_solution);
212 Scalar L2norm = Thyra::norm_2(*tmp);
213 xErrorNorm.push_back(L2norm);
214 }
215 xSlope = computeLinearRegressionLogLog<Scalar>(dt, xErrorNorm);
216
217 if (!solutionsDot.empty()) {
218 auto ref_solutionDot = solutionsDot[lastElem];
219 for (std::size_t i = 0; i < lastElem; ++i) {
220 auto tmp = solutionsDot[i];
221 Thyra::Vp_StV(tmp.ptr(), -1.0, *ref_solutionDot);
222 Scalar L2norm = Thyra::norm_2(*tmp);
223 xDotErrorNorm.push_back(L2norm);
224 }
225 xDotSlope = computeLinearRegressionLogLog<Scalar>(dt, xDotErrorNorm);
226 }
227
228 if (!solutionsDotDot.empty()) {
229 auto ref_solutionDotDot = solutionsDotDot[solutions.size() - 1];
230 for (std::size_t i = 0; i < lastElem; ++i) {
231 auto tmp = solutionsDotDot[i];
232 Thyra::Vp_StV(tmp.ptr(), -1.0, *ref_solutionDotDot);
233 Scalar L2norm = Thyra::norm_2(*tmp);
234 xDotDotErrorNorm.push_back(L2norm);
235 }
236 xDotDotSlope = computeLinearRegressionLogLog<Scalar>(dt, xDotDotErrorNorm);
237 }
238
239 Scalar order = stepper->getOrder();
240 out << " Stepper = " << stepper->description() << std::endl;
241 out << " =================================" << std::endl;
242 out << " Expected Order = " << order << std::endl;
243 out << " x Order = " << xSlope << std::endl;
244 if (!solutionsDot.empty())
245 out << " xDot Order = " << xDotSlope << std::endl;
246 if (!solutionsDotDot.empty())
247 out << " xDotDot Order = " << xDotDotSlope << std::endl;
248 out << " =================================" << std::endl;
249
250 std::ofstream ftmp(filename);
251 Scalar factor = 0.0;
252 for (std::size_t n = 0; n < lastElem; n++) {
253 factor = 0.8 * (pow(dt[n] / dt[0], order));
254 ftmp << dt[n] << " " << xErrorNorm[n] << " " << factor * xErrorNorm[0];
255 if (xDotErrorNorm.size() == lastElem)
256 ftmp << " " << xDotErrorNorm[n] << " " << factor * xDotErrorNorm[0];
257 if (xDotDotErrorNorm.size() == lastElem)
258 ftmp << " " << xDotDotErrorNorm[n] << " "
259 << factor * xDotDotErrorNorm[0];
260 ftmp << std::endl;
261 }
262 ftmp.close();
263}
264
265template <class Scalar>
267 const std::string filename, Teuchos::RCP<Tempus::Stepper<Scalar>> stepper,
268 std::vector<Scalar>& StepSize,
269 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>>& solutions,
270 std::vector<Scalar>& xErrorNorm, Scalar& xSlope,
271 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>>& solutionsDot,
272 std::vector<Scalar>& xDotErrorNorm, Scalar& xDotSlope,
273 Teuchos::FancyOStream& out)
274{
275 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>> solutionsDotDot;
276 std::vector<Scalar> xDotDotErrorNorm;
277 Scalar xDotDotSlope = Scalar(0.0);
278 writeOrderError(filename, stepper, StepSize, solutions, xErrorNorm, xSlope,
279 solutionsDot, xDotErrorNorm, xDotSlope, solutionsDotDot,
280 xDotDotErrorNorm, xDotDotSlope, out);
281}
282
283template <class Scalar>
285 const std::string filename, Teuchos::RCP<Tempus::Stepper<Scalar>> stepper,
286 std::vector<Scalar>& StepSize,
287 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>>& solutions,
288 std::vector<Scalar>& xErrorNorm, Scalar& xSlope, Teuchos::FancyOStream& out)
289{
290 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>> solutionsDot;
291 std::vector<Scalar> xDotErrorNorm;
292 Scalar xDotSlope = Scalar(0.0);
293 std::vector<Teuchos::RCP<Thyra::VectorBase<Scalar>>> solutionsDotDot;
294 std::vector<Scalar> xDotDotErrorNorm;
295 Scalar xDotDotSlope = Scalar(0.0);
296 writeOrderError(filename, stepper, StepSize, solutions, xErrorNorm, xSlope,
297 solutionsDot, xDotErrorNorm, xDotSlope, solutionsDotDot,
298 xDotDotErrorNorm, xDotDotSlope, out);
299}
300
301template <class Scalar>
303 const std::string filename,
304 Teuchos::RCP<const Tempus::SolutionHistory<Scalar>> solutionHistory)
305{
306 std::ofstream ftmp(filename);
307 Teuchos::RCP<const Thyra::VectorBase<Scalar>> x;
308 Teuchos::RCP<const Thyra::VectorBase<Scalar>> xDot;
309 Teuchos::RCP<const Thyra::VectorBase<Scalar>> xDotDot;
310 for (int i = 0; i < solutionHistory->getNumStates(); i++) {
311 Teuchos::RCP<const Tempus::SolutionState<Scalar>> solutionState =
312 (*solutionHistory)[i];
313 Scalar time = solutionState->getTime();
314 x = solutionState->getX();
315 xDot = solutionState->getXDot();
316 xDotDot = solutionState->getXDotDot();
317 int J = x->space()->dim();
318
319 ftmp << time;
320 for (int j = 0; j < J; j++) ftmp << " " << get_ele(*x, j);
321 if (xDot != Teuchos::null)
322 for (int j = 0; j < J; j++) ftmp << " " << get_ele(*xDot, j);
323 if (xDotDot != Teuchos::null)
324 for (int j = 0; j < J; j++) ftmp << " " << get_ele(*xDotDot, j);
325 ftmp << std::endl;
326 }
327 ftmp.close();
328}
329
330template <class Scalar>
331void writeSolution(
332 const std::string filename,
333 Teuchos::RCP<Tempus::SolutionHistory<Scalar>> solutionHistory)
334{
335 Teuchos::RCP<const Tempus::SolutionHistory<Scalar>> sh(solutionHistory);
336 writeSolution(filename, sh);
337}
338
339} // namespace Tempus_Test
340
341#endif // TEMPUS_CONVERGENCE_TEST_UTILS_HPP
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
Thyra Base interface for time steppers.
Linear regression class. Copied and modified from Rythmos.
void validateXYData_(std::vector< Scalar > &x, std::vector< Scalar > &y)
void setData(std::vector< Scalar > &x, std::vector< Scalar > &y)
void writeSolution(const std::string filename, Teuchos::RCP< const Tempus::SolutionHistory< Scalar > > solutionHistory)
void writeOrderError(const std::string filename, Teuchos::RCP< Tempus::Stepper< Scalar > > stepper, std::vector< Scalar > &StepSize, std::vector< Teuchos::RCP< Thyra::VectorBase< Scalar > > > &solutions, std::vector< Scalar > &xErrorNorm, Scalar &xSlope, std::vector< Teuchos::RCP< Thyra::VectorBase< Scalar > > > &solutionsDot, std::vector< Scalar > &xDotErrorNorm, Scalar &xDotSlope, std::vector< Teuchos::RCP< Thyra::VectorBase< Scalar > > > &solutionsDotDot, std::vector< Scalar > &xDotDotErrorNorm, Scalar &xDotDotSlope, Teuchos::FancyOStream &out)
Scalar computeLinearRegressionLogLog(std::vector< Scalar > &x, std::vector< Scalar > &y)
Scalar computeLinearRegression(std::vector< Scalar > &x, std::vector< Scalar > &y)
Teuchos::RCP< LinearRegression< Scalar > > linearRegression()
bool approxZero(Scalar value, Scalar tol=Teuchos::ScalarTraits< Scalar >::sfmin())
Test if value is approximately zero within tolerance.