PFASST++
advection_diffusion_sweeper.hpp
Go to the documentation of this file.
1 
8 #ifndef _EXAMPLES__ADVEC_DIFF__ADVECTION_DIFFUSION_SWEEPER_HPP_
9 #define _EXAMPLES__ADVEC_DIFF__ADVECTION_DIFFUSION_SWEEPER_HPP_
10 
11 #include <cassert>
12 #include <complex>
13 #include <cstdlib>
14 #include <map>
15 #include <ostream>
16 #include <vector>
17 #include <utility>
18 using namespace std;
19 
20 #include <pfasst/globals.hpp>
21 #include <pfasst/config.hpp>
22 #include <pfasst/logging.hpp>
26 
27 #include "fft.hpp"
28 
29 #ifndef PI
30 #define PI 3.1415926535897932385
31 #endif
32 
33 
34 namespace pfasst
35 {
36  namespace examples
37  {
60  namespace advection_diffusion
61  {
66  typedef map<tuple<size_t, size_t>, double> error_map; // step, iteration -> error
67  typedef map<size_t, error_map> residual_map; // level, (step, iteration) -> residual
69 
70  typedef error_map::value_type vtype;
71  typedef error_map::key_type ktype;
72 
77  template<typename time = pfasst::time_precision>
79  : public encap::IMEXSweeper<time>
80  {
81  public:
82  static void init_opts()
83  {
84  pfasst::config::options::add_option<size_t>("Adv/Diff Sweeper", "spatial_dofs", "Number of spatial degrees of freedom");
85  }
86 
87  static void init_logs()
88  {
90  }
91 
92  private:
95  vector<complex<double>> ddx, lap;
97 
99  error_map errors;
100  error_map residuals;
102 
104  double v = 1.0;
105  time t0 = 1.0;
106  double nu = 0.02;
107  size_t nf1evals = 0;
109 
110  public:
112  explicit AdvectionDiffusionSweeper(size_t nvars)
113  {
114  this->ddx.resize(nvars);
115  this->lap.resize(nvars);
116  for (size_t i = 0; i < nvars; i++) {
117  double kx = 2 * PI * ((i <= nvars / 2) ? int(i) : int(i) - int(nvars));
118  this->ddx[i] = complex<double>(0.0, 1.0) * kx;
119  this->lap[i] = (kx * kx < 1e-13) ? 0.0 : -kx * kx;
120  }
121  }
122 
123  AdvectionDiffusionSweeper() = default;
124 
126  {
127  ML_CLOG(INFO, "Advec", "number of f1 evals: " << this->nf1evals);
128  }
130 
132  void exact(shared_ptr<Encapsulation<time>> q, time t)
133  {
134  this->exact(as_vector<double, time>(q), t);
135  }
136 
137  void exact(DVectorT& q, time t)
138  {
139  size_t n = q.size();
140  double a = 1.0 / sqrt(4 * PI * nu * (t + t0));
141 
142  for (size_t i = 0; i < n; i++) {
143  q[i] = 0.0;
144  }
145 
146  for (int ii = -2; ii < 3; ii++) {
147  for (size_t i = 0; i < n; i++) {
148  double x = double(i) / n - 0.5 + ii - t * v;
149  q[i] += a * exp(-x * x / (4 * nu * (t + t0)));
150  }
151  }
152  }
153 
154  void echo_error(time t)
155  {
156  auto& qend = as_vector<double, time>(this->get_end_state());
157  DVectorT qex(qend.size());
158 
159  this->exact(qex, t);
160 
161  double max = 0.0;
162  for (size_t i = 0; i < qend.size(); i++) {
163  double d = abs(qend[i] - qex[i]);
164  if (d > max) { max = d; }
165  }
166 
167  auto n = this->get_controller()->get_step();
168  auto k = this->get_controller()->get_iteration();
169 
170  this->errors.insert(vtype(ktype(n, k), max));
171  }
172 
174  {
175  vector<shared_ptr<Encapsulation<time>>> residuals;
176 
177  for (size_t m = 0; m < this->get_nodes().size(); m++) {
178  residuals.push_back(this->get_factory()->create(pfasst::encap::solution));
179  }
180  this->residual(this->get_controller()->get_step_size(), residuals);
181 
182  vector<time> rnorms;
183  for (auto r: residuals) {
184  rnorms.push_back(r->norm0());
185  }
186  auto rmax = *std::max_element(rnorms.begin(), rnorms.end());
187 
188  auto n = this->get_controller()->get_step();
189  auto k = this->get_controller()->get_iteration();
190 
191  auto err = this->errors[ktype(n, k)];
192 
193  ML_CLOG(INFO, "Advec", (boost::format(this->FORMAT_STR) % (n+1) % k % this->get_nodes().size() % as_vector<double, time>(this->state[0]).size() % rmax % err));
194 
195  this->residuals[ktype(n, k)] = rmax;
196  }
197 
198  error_map get_errors()
199  {
200  return this->errors;
201  }
202 
203  error_map get_residuals()
204  {
205  return this->residuals;
206  }
208 
210 
213  void post_predict() override
214  {
215  time t = this->get_controller()->get_time();
216  time dt = this->get_controller()->get_step_size();
217  this->echo_error(t + dt);
218  this->echo_residual();
219  }
220 
224  void post_sweep() override
225  {
226  time t = this->get_controller()->get_time();
227  time dt = this->get_controller()->get_step_size();
228  this->echo_error(t + dt);
229  this->echo_residual();
230  }
232 
234 
237  void f_expl_eval(shared_ptr<Encapsulation<time>> f_expl_encap,
238  shared_ptr<Encapsulation<time>> u_encap,
239  time t) override
240  {
241  UNUSED(t);
242  auto& u = as_vector<double, time>(u_encap);
243  auto& f_expl = as_vector<double, time>(f_expl_encap);
244 
245  double c = -v / double(u.size());
246 
247  auto* z = this->fft.forward(u);
248  for (size_t i = 0; i < u.size(); i++) {
249  z[i] *= c * this->ddx[i];
250  }
251  this->fft.backward(f_expl);
252 
253  this->nf1evals++;
254  }
255 
259  void f_impl_eval(shared_ptr<Encapsulation<time>> f_impl_encap,
260  shared_ptr<Encapsulation<time>> u_encap,
261  time t) override
262  {
263  UNUSED(t);
264  auto& u = as_vector<double, time>(u_encap);
265  auto& f_impl = as_vector<double, time>(f_impl_encap);
266 
267  double c = nu / double(u.size());
268 
269  auto* z = this->fft.forward(u);
270  for (size_t i = 0; i < u.size(); i++) {
271  z[i] *= c * this->lap[i];
272  }
273  this->fft.backward(f_impl);
274  }
275 
279  void impl_solve(shared_ptr<Encapsulation<time>> f_impl_encap,
280  shared_ptr<Encapsulation<time>> u_encap,
281  time t, time dt,
282  shared_ptr<Encapsulation<time>> rhs_encap) override
283  {
284  UNUSED(t);
285  auto& u = as_vector<double, time>(u_encap);
286  auto& f_impl = as_vector<double, time>(f_impl_encap);
287  auto& rhs = as_vector<double, time>(rhs_encap);
288 
289  double c = nu * double(dt);
290 
291  auto* z = this->fft.forward(rhs);
292  for (size_t i = 0; i < u.size(); i++) {
293  z[i] /= (1.0 - c * this->lap[i]) * double(u.size());
294  }
295  this->fft.backward(u);
296 
297  for (size_t i = 0; i < u.size(); i++) {
298  f_impl[i] = (u[i] - rhs[i]) / double(dt);
299  }
300  }
302  };
303  } // ::pfasst::examples::advection_diffusion
304  } // ::pfasst::examples
305 } // ::pfasst
306 
307 #endif // _EXAMPLES__ADVEC_DIFF__ADVECTION_DIFFUSION_SWEEPER_HPP_
Semi-implicit IMEX sweeper.
void post_predict() override
Compute low-order provisional solution.
STL namespace.
map< tuple< size_t, size_t >, double > error_map
void impl_solve(shared_ptr< Encapsulation< time >> f_impl_encap, shared_ptr< Encapsulation< time >> u_encap, time t, time dt, shared_ptr< Encapsulation< time >> rhs_encap) override
Solve \( U - \Delta t F_{\rm impl}(U) = RHS \) for \( U \).
#define ML_CLOG(level, logger_id, x)
same as CLOG(level, logger, x) from easylogging++
Definition: logging.hpp:117
static void add_custom_logger(const string &id)
Provides convenient way of adding additional named loggers.
Definition: logging.hpp:360
complex< double > * forward(const DVectorT &x)
Definition: fft.hpp:69
void f_impl_eval(shared_ptr< Encapsulation< time >> f_impl_encap, shared_ptr< Encapsulation< time >> u_encap, time t) override
Evaluate the implicit part of the ODE.
void f_expl_eval(shared_ptr< Encapsulation< time >> f_expl_encap, shared_ptr< Encapsulation< time >> u_encap, time t) override
Evaluate the explicit part of the ODE.
static precision max(const vector< precision > &data)
Data/solution encapsulation.
tuple t
Definition: plot.py:12
#define UNUSED(expr)
Denoting unused function parameters for omitting compiler warnings.
Definition: globals.hpp:32
advection-diffusion sweeper with semi-implicit time-integration.
float dt
Definition: plot.py:10
VectorEncapsulation< scalar, time > & as_vector(shared_ptr< Encapsulation< time >> x)