Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
21 namespace Tempus_Test {
22 
26 template <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_;
43  Scalar yIntercept_;
45 };
46 
47 // Member functions:
48 
49 template <class Scalar>
51 {
52  isInitialized_ = false;
53 }
54 
55 template <class Scalar>
56 void 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 
66 template <class Scalar>
67 void LinearRegression<Scalar>::validateXYData_(std::vector<Scalar>& x,
68  std::vector<Scalar>& y)
69 {
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 
87 template <class Scalar>
89 {
90  TEUCHOS_TEST_FOR_EXCEPT(!isInitialized_);
91  return slope_;
92 }
93 
94 template <class Scalar>
96 {
97  TEUCHOS_TEST_FOR_EXCEPT(!isInitialized_);
98  return yIntercept_;
99 }
100 
101 template <class Scalar>
103 {
104  TEUCHOS_TEST_FOR_EXCEPT(!isInitialized_);
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:
139 template <class Scalar>
140 Scalar computeLinearRegression(std::vector<Scalar>& x, std::vector<Scalar>& y)
141 {
143  lr.setData(x, y);
144  return (lr.getSlope());
145 }
146 
147 template <class Scalar>
148 void 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 
158 template <class Scalar>
159 Scalar 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 
179 template <class Scalar>
181 {
184  return lr;
185 }
186 
187 template <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,
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 
265 template <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,
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 
283 template <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 
301 template <class Scalar>
303  const std::string filename,
304  Teuchos::RCP<const Tempus::SolutionHistory<Scalar>> solutionHistory)
305 {
306  std::ofstream ftmp(filename);
310  for (int i = 0; i < solutionHistory->getNumStates(); i++) {
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 
330 template <class Scalar>
331 void writeSolution(
332  const std::string filename,
334 {
336  writeSolution(filename, sh);
337 }
338 
339 } // namespace Tempus_Test
340 
341 #endif // TEMPUS_CONVERGENCE_TEST_UTILS_HPP
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
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)
void writeSolution(const std::string filename, Teuchos::RCP< const Tempus::SolutionHistory< Scalar >> solutionHistory)
Thyra Base interface for time steppers.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Scalar computeLinearRegressionLogLog(std::vector< Scalar > &x, std::vector< Scalar > &y)
Teuchos::RCP< LinearRegression< Scalar > > linearRegression()
SolutionHistory is basically a container of SolutionStates. SolutionHistory maintains a collection of...
void validateXYData_(std::vector< Scalar > &x, std::vector< Scalar > &y)
Scalar computeLinearRegression(std::vector< Scalar > &x, std::vector< Scalar > &y)
void setData(std::vector< Scalar > &x, std::vector< Scalar > &y)
bool approxZero(Scalar value, Scalar tol=Teuchos::ScalarTraits< Scalar >::sfmin())
Test if value is approximately zero within tolerance.
Linear regression class. Copied and modified from Rythmos.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)