PFASST++
vdp_sweeper.hpp
Go to the documentation of this file.
1 
8 #ifndef _EXAMPLES__VANDERPOL__VDP_SWEEPER_HPP_
9 #define _EXAMPLES__VANDERPOL__VDP_SWEEPER_HPP_
10 
11 #include <iostream>
12 #include <fstream>
13 #include <vector>
14 using namespace std;
15 
16 #include <pfasst/logging.hpp>
18 #include <pfasst/encap/vector.hpp>
19 
20 
21 namespace pfasst
22 {
23  namespace examples
24  {
37  namespace vdp
38  {
52  template<typename time = pfasst::time_precision>
53  class VdpSweeper
54  : public encap::ImplicitSweeper<time>
55  {
56  private:
58 
61 
63  double nu;
64 
66  double x0, y0;
67 
69  size_t newton_maxit;
70 
72  double newton_tol;
73 
75  size_t n_f_impl_eval, n_impl_solve, n_newton_iter;
76 
78  fstream output_file;
79 
81  double error;
82 
83  public:
91  VdpSweeper(double nu, double x0, double y0)
92  : nu(nu)
93  , x0(x0)
94  , y0(y0)
95  , newton_maxit(50)
96  , newton_tol(1e-12)
97  , n_f_impl_eval(0)
98  , n_impl_solve(0)
99  , n_newton_iter(0)
100  {
101  this->output_file.open("./vanderpol.txt", ios_base::out);
102 
103  // The file should also contain the initial value, so perform a first write here
104  this->output_file << x0 << " " << y0 << endl;
105  }
106 
110  virtual ~VdpSweeper()
111  {
112  ML_LOG(INFO, "Number of implicit evaluations:" << this->n_f_impl_eval);
113  ML_LOG(INFO, "Number of implicit solves: " << this->n_impl_solve);
114  this->output_file.close();
115  }
116 
124  void echo_error(time t)
125  {
126  auto& qend = encap::as_vector<double, time>(this->get_end_state());
127 
128  real_vector_type qex(qend.size());
129 
130  this->exact(qex, t);
131 
132  if (this->nu==0)
133  {
134  double max_err = max(abs(qend[0] - qex[0])/abs(qex[0]) , abs(qend[1]-qex[1])/abs(qex[1]) );
135  ML_LOG(INFO, "error:" << max_err);
136  this->error = max_err;
137  }
138  this->output_file << qend[0] << " " << qend[1] << endl;
139  }
140 
144  double get_errors()
145  {
146  return this->error;
147  }
148 
152  void post_predict() override
153  {
154  time t = this->get_controller()->get_time();
155  time dt = this->get_controller()->get_step_size();
156  this->echo_error(t + dt);
157  }
158 
162  void post_sweep() override
163  {
164  time t = this->get_controller()->get_time();
165  time dt = this->get_controller()->get_step_size();
166  this->echo_error(t + dt);
167  }
168 
169  // I don't know why Doxygen is eating up so many backslashes here ...
178  void exact(real_vector_type& q, time t)
179  {
180  if (this->nu==0)
181  {
193  q[0] = this->y0*sin(t) + this->x0*cos(t);
194  q[1] = -this->x0*sin(t) + this->y0*cos(t);
195  }
196  else
197  {
198  // For the nonlinear case, there is no analytic solution for the vdP oscillator, so
199  // simply return the initial value
200  q[0] = this->x0;
201  q[1] = this->y0;
202  }
203  }
204 
205  void exact(shared_ptr<encap_type> q_encap, time t)
206  {
207  auto& q = encap::as_vector<double, time>(q_encap);
208  this->exact(q, t);
209  }
210 
214  void f_impl_eval(shared_ptr<encap_type> f_encap,
215  shared_ptr<encap_type> q_encap, time t) override
216  {
217  UNUSED(t);
218  auto& f = encap::as_vector<double, time>(f_encap);
219  auto& q = encap::as_vector<double, time>(q_encap);
220 
221  // x' = y
222  f[0] = q[1];
223  // y' = nu(1-x^2)*y - x
224  f[1] = this->nu*(1.0-q[0]*q[0])*q[1] - q[0];
225 
226  this->n_f_impl_eval++;
227  }
228 
229  // I don't know why Doxygen is eating up so many backslashes here ...
234  void impl_solve(shared_ptr<encap_type> f_encap,
235  shared_ptr<encap_type> q_encap, time t, time dt,
236  shared_ptr<encap_type> rhs_encap) override
237  {
238  UNUSED(t);
239  auto& f = encap::as_vector<double, time>(f_encap);
240  auto& q = encap::as_vector<double, time>(q_encap);
241  auto& rhs = encap::as_vector<double, time>(rhs_encap);
242 
243  // I don't know why Doxygen is eating up so many backslashes here ...
270  // initialize residual
271  double residual = this->newton_tol + 1.0;
272  size_t iter = 0.0;
273 
274  // Initial value for q is just rhs: For small dt, P is approximately the identity
275  q[0] = rhs[0];
276  q[1] = rhs[1];
277 
278  // NEWTON ITERATION: q_new = q + inv(J(q))*(-f(q))
279  do {
280  // Store -P(q) in f0, f1
281  double f0 = -( q[0] - dt*q[1] - rhs[0] );
282  double f1 = -( q[1] - dt*( this->nu*(1-q[0]*q[0])*q[1]-q[0]) - rhs[1] );
283 
307  double a = dt * q[0] * q[0] - dt + 1.0;
308  double b = -2.0 * dt * this->nu * q[0] * q[1] - dt;
309  double c = 2.0 * this->nu * q[0] * q[1] * dt * dt + dt * dt + dt * q[0] * q[0] - dt + 1.0;
310 
311  // Compute inv(J(q))*(-f(q)) and store it in f
312  f[0] = (1.0/c)*( a*f0 + dt*f1 );
313  f[1] = (1.0/c)*( b*f0 + f1 );
314 
315  // Perform Newton update q_new = q + inv(J(q))*(-f(q))
316  q[0] += f[0];
317  q[1] += f[1];
318 
319  // Compute relative residual; note that f = q_new - q is the update
320  residual = fmax( abs(f[0]), abs(f[1]) ) / fmax( abs(q[0]), abs(q[1]) );
321 
322  iter++;
323  this->n_newton_iter++;
324 
325  } while ( (iter<this->newton_maxit) && (residual>this->newton_tol) );
326 
327  // Say something, only if the residual tolerance has not been reach in the maximum
328  // number of iterations
329  if (residual >=this->newton_tol)
330  {
331  cout << "Newton failed to converge: res = " << scientific << residual << " -- n_iter = " << iter << " of maxit = " << this->newton_maxit << endl;
332  }
333 
334  // Set f to f(q)
335  f[0] = q[1];
336  f[1] = this->nu*(1.0-q[0]*q[0])*q[1] - q[0];
337 
338  this->n_impl_solve++;
339  }
340  };
341  } // ::pfasst::examples::vdp
342  } // ::pfasst::examples
343 } // ::pfasst
344 
345 #endif // _EXAMPLES__VANDERPOL__VDP_SWEEPER_HPP_
void echo_error(time t)
computes and prints out error, which is meaningful only for \( \nu=0 \).
STL namespace.
void f_impl_eval(shared_ptr< encap_type > f_encap, shared_ptr< encap_type > q_encap, time t) override
Evaluate the implicit part of the right hand side.
size_t newton_maxit
Maximum number of iterations for the nonlinear Newton solver.
Definition: vdp_sweeper.hpp:69
Sweeper for the van der Pol oscillator.
Definition: vdp_sweeper.hpp:53
double get_errors()
returns error, but does not update it!
virtual ~VdpSweeper()
upon destruction, report final error and number of function calls and close output file...
void impl_solve(shared_ptr< encap_type > f_encap, shared_ptr< encap_type > q_encap, time t, time dt, shared_ptr< encap_type > rhs_encap) override
for given \( b \), solve \( \left( u - \Delta t f(u) \right) u = b \) for \( u \) and set f_encap to ...
double newton_tol
Tolerance for the nonlinear Newton iteration.
Definition: vdp_sweeper.hpp:72
void exact(real_vector_type &q, time t)
if \( \nu=0 \), this computes the exact solution at time t.
#define ML_LOG(level, x)
same as LOG(level, x) from easylogging++
Definition: logging.hpp:110
encap::Encapsulation< time > encap_type
Definition: vdp_sweeper.hpp:57
double error
error: For \( \nu=0 \), vdP reduces to linear oscillator, otherwise no analytic solution is available...
Definition: vdp_sweeper.hpp:81
VdpSweeper(double nu, double x0, double y0)
generic constructor; initialize all function call counters with zero.
Definition: vdp_sweeper.hpp:91
encap::VectorEncapsulation< double > real_vector_type
Define a type for a complex PFASST vector encapsulation.
Definition: vdp_sweeper.hpp:60
static precision max(const vector< precision > &data)
Data/solution encapsulation.
void post_predict() override
post prediction step, update error.
tuple t
Definition: plot.py:12
#define UNUSED(expr)
Denoting unused function parameters for omitting compiler warnings.
Definition: globals.hpp:32
fstream output_file
Output file.
Definition: vdp_sweeper.hpp:78
float dt
Definition: plot.py:10
void post_sweep() override
post sweep, update error.
void exact(shared_ptr< encap_type > q_encap, time t)
double nu
Parameter \( \nu \) in the van-der-Pol oscillator.
Definition: vdp_sweeper.hpp:63