22 * Advection/diffusion example using the encapsulated IMEX sweeper.
33 */
44
5+ #define PFASST_ENABLE_GNUPLOT
6+
57#include < algorithm>
68#include < cmath>
79#include < complex>
10+ #include < map>
811
912#include < pfasst.hpp>
1013#include < pfasst-imex.hpp>
@@ -21,20 +24,72 @@ using namespace std;
2124// config
2225//
2326
24- const int nlevs = 1 ;
25- const int ndofs = 512 ;
26- const int nnodes = 5 ;
27+ const int nlevs = 2 ;
2728const int xrat = 2 ;
2829const int trat = 2 ;
2930
30- const int nsteps = 32 ;
31+ const int nsteps = 1 ;
3132const double dt = 0.01 ;
3233
3334typedef double scalar;
3435
3536using namespace std ;
3637using pfasst::encap::Encapsulation;
37- using dvector = pfasst::encap::VectorEncapsulation<scalar>;
38+ using dvector = pfasst::encap::VectorEncapsulation<double ,double >;
39+
40+ //
41+ // fft helper
42+ //
43+ class FFT {
44+
45+ struct workspace {
46+ fftw_plan ffft;
47+ fftw_plan ifft;
48+ fftw_complex* wk;
49+ complex <scalar>* z;
50+ };
51+
52+ map<int ,workspace*> workspaces;
53+
54+ public:
55+
56+ ~FFT ()
57+ {
58+ // XXX
59+ }
60+
61+ workspace* get_workspace (int ndofs)
62+ {
63+ if (workspaces.find (ndofs) == workspaces.end ()) {
64+ workspace* wk = new workspace;
65+ wk->wk = fftw_alloc_complex (ndofs);
66+ wk->ffft = fftw_plan_dft_1d (ndofs, wk->wk , wk->wk , FFTW_FORWARD, FFTW_ESTIMATE);
67+ wk->ifft = fftw_plan_dft_1d (ndofs, wk->wk , wk->wk , FFTW_BACKWARD, FFTW_ESTIMATE);
68+ wk->z = reinterpret_cast <complex <scalar>*>(wk->wk );
69+ workspaces.insert (pair<int ,workspace*>(ndofs, wk));
70+ }
71+
72+ return workspaces[ndofs];
73+ }
74+
75+ complex <double >* forward (const dvector& x)
76+ {
77+ workspace *wk = get_workspace (x.size ());
78+ for (int i=0 ; i<x.size (); i++)
79+ wk->z [i] = x[i];
80+ fftw_execute_dft (wk->ffft , wk->wk , wk->wk );
81+ return wk->z ;
82+ }
83+
84+ void backward (dvector &x)
85+ {
86+ workspace *wk = get_workspace (x.size ());
87+ fftw_execute_dft (wk->ifft , wk->wk , wk->wk );
88+ for (int i=0 ; i<x.size (); i++)
89+ x[i] = real (wk->z [i]);
90+ }
91+
92+ } fft;
3893
3994
4095//
@@ -44,10 +99,6 @@ using dvector = pfasst::encap::VectorEncapsulation<scalar>;
4499template <typename time>
45100class ADIMEX : public pfasst ::imex::IMEX<time> {
46101
47- fftw_plan ffft;
48- fftw_plan ifft;
49- fftw_complex* wk;
50-
51102 vector<complex <scalar>> ddx, lap;
52103
53104 scalar v = 1.0 ;
@@ -58,11 +109,6 @@ class ADIMEX : public pfasst::imex::IMEX<time> {
58109
59110 ADIMEX (int nvars)
60111 {
61- // XXX: this fft stuff almost certainly DOES NOT work when 'scalar' is not 'double'
62- wk = fftw_alloc_complex (nvars);
63- ffft = fftw_plan_dft_1d (nvars, wk, wk, FFTW_FORWARD, FFTW_ESTIMATE);
64- ifft = fftw_plan_dft_1d (nvars, wk, wk, FFTW_BACKWARD, FFTW_ESTIMATE);
65-
66112 ddx.resize (nvars);
67113 lap.resize (nvars);
68114 for (int i=0 ; i<nvars; i++) {
@@ -73,12 +119,6 @@ class ADIMEX : public pfasst::imex::IMEX<time> {
73119
74120 }
75121
76- ~ADIMEX () {
77- fftw_destroy_plan (ffft);
78- fftw_destroy_plan (ifft);
79- fftw_free (wk);
80- }
81-
82122 void exact (dvector& q, scalar t)
83123 {
84124 int n = q.size ();
@@ -95,79 +135,112 @@ class ADIMEX : public pfasst::imex::IMEX<time> {
95135 }
96136 }
97137
98- void sweep (time t, time dt )
138+ void echo_error (time t)
99139 {
100- pfasst::imex::IMEX<time>::sweep (t, dt);
101-
102- auto & qend = *dynamic_cast <dvector*>(this ->get_qend ());
140+ auto & qend = *dynamic_cast <dvector*>(this ->get_q (this ->get_nodes ().size ()-1 ));
103141 auto qex = dvector (qend.size ());
104142
105- exact (qex, t+dt );
143+ exact (qex, t);
106144
107145 scalar max = 0.0 ;
108146 for (int i=0 ; i<qend.size (); i++) {
109147 scalar d = abs (qend[i]-qex[i]);
110148 if (d > max)
111149 max = d;
112150 }
113- cout << " err: " << scientific << max << endl;
151+ cout << " err: " << scientific << max << " (" << qend.size () << " )" << endl;
152+ }
153+
154+ void predict (time t, time dt)
155+ {
156+ // cout << "PREDICTOR" << endl;
157+ pfasst::imex::IMEX<time>::predict (t, dt);
158+ echo_error (t+dt);
114159 }
115160
116- void f1eval (Encapsulation *F, Encapsulation *Q, time t)
161+ void sweep (time t, time dt)
162+ {
163+ // cout << "SWEEPING" << endl;
164+ pfasst::imex::IMEX<time>::sweep (t, dt);
165+ echo_error (t+dt);
166+ }
167+
168+ void f1eval (Encapsulation<scalar> *F, Encapsulation<scalar> *Q, time t)
117169 {
118170 auto & f = *dynamic_cast <dvector*>(F);
119171 auto & q = *dynamic_cast <dvector*>(Q);
120172
121- complex <scalar>* z = reinterpret_cast <complex <scalar>*>(wk);
122173 scalar c = -v / scalar (q.size ());
123174
124- copy (q.begin (), q.end (), z);
125- fftw_execute_dft (ffft, wk, wk);
175+ auto * z = fft.forward (q);
126176 for (int i=0 ; i<q.size (); i++)
127177 z[i] *= c * ddx[i];
128- fftw_execute_dft (ifft, wk, wk);
129-
130- for (int i=0 ; i<q.size (); i++)
131- f[i] = real (z[i]);
178+ fft.backward (f);
132179 }
133180
134- void f2eval (Encapsulation *F, Encapsulation *Q, time t)
181+ void f2eval (Encapsulation<scalar> *F, Encapsulation<scalar> *Q, time t)
135182 {
136183 auto & f = *dynamic_cast <dvector*>(F);
137184 auto & q = *dynamic_cast <dvector*>(Q);
138185
139- complex <scalar>* z = reinterpret_cast <complex <scalar>*>(wk);
140186 scalar c = nu / scalar (q.size ());
141187
142- copy (q.begin (), q.end (), z);
143- fftw_execute_dft (ffft, wk, wk);
188+ auto * z = fft.forward (q);
144189 for (int i=0 ; i<q.size (); i++)
145190 z[i] *= c * lap[i];
146- fftw_execute_dft (ifft, wk, wk);
147-
148- for (int i=0 ; i<q.size (); i++)
149- f[i] = real (z[i]);
191+ fft.backward (f);
150192 }
151193
152- void f2comp (Encapsulation *F, Encapsulation *Q, time t, time dt, Encapsulation *RHS)
194+ void f2comp (Encapsulation<scalar> *F, Encapsulation<scalar> *Q, scalar t, scalar dt, Encapsulation<scalar> *RHS)
153195 {
154196 auto & f = *dynamic_cast <dvector*>(F);
155197 auto & q = *dynamic_cast <dvector*>(Q);
156198 auto & rhs = *dynamic_cast <dvector*>(RHS);
157199
158- complex <scalar>* z = reinterpret_cast <complex <scalar>*>(wk);
159-
160- copy (rhs.begin (), rhs.end (), z);
161- fftw_execute_dft (ffft, wk, wk);
200+ auto * z = fft.forward (rhs);
162201 for (int i=0 ; i<q.size (); i++)
163202 z[i] /= (1.0 - nu * dt * lap[i]) * scalar (q.size ());
164- fftw_execute_dft (ifft, wk, wk );
203+ fft. backward (q );
165204
166- for (int i=0 ; i<q.size (); i++) {
167- q[i] = real (z[i]);
205+ for (int i=0 ; i<q.size (); i++)
168206 f[i] = (q[i] - rhs[i]) / dt;
169- }
207+ }
208+
209+ };
210+
211+ template <typename scalar>
212+ class ADTRANS : public pfasst ::encap::PolyInterpMixin<scalar> {
213+ public:
214+
215+ void interpolate (Encapsulation<scalar> *dst, const Encapsulation<scalar> *src) {
216+ auto & crse = *dynamic_cast <const dvector*>(src);
217+ auto & fine = *dynamic_cast <dvector*>(dst);
218+
219+ auto * crse_z = fft.forward (crse);
220+ auto * fine_z = fft.get_workspace (fine.size ())->z ;
170221
222+ for (int i=0 ; i<fine.size (); i++)
223+ fine_z[i] = 0.0 ;
224+
225+ double c = 1.0 / crse.size ();
226+
227+ for (int i=0 ; i<crse.size ()/2 ; i++)
228+ fine_z[i] = c * crse_z[i];
229+
230+ for (int i=1 ; i<crse.size ()/2 ; i++)
231+ fine_z[fine.size ()-crse.size ()/2 +i] = c * crse_z[crse.size ()/2 +i];
232+
233+ fft.backward (fine);
234+ }
235+
236+ void restrict (Encapsulation<scalar> *dst, const Encapsulation<scalar> *src) {
237+ auto & crse = *dynamic_cast <dvector*>(dst);
238+ auto & fine = *dynamic_cast <const dvector*>(src);
239+
240+ int xrat = fine.size () / crse.size ();
241+
242+ for (int i=0 ; i<crse.size (); i++)
243+ crse[i] = fine[xrat*i];
171244 }
172245
173246};
@@ -179,14 +252,14 @@ class ADIMEX : public pfasst::imex::IMEX<time> {
179252
180253int main (int argc, char **argv)
181254{
182- int ndofs = 512 ;
255+ int ndofs = 256 ;
183256 int nnodes = 5 ;
184257
185258 if (nlevs == 1 ) {
186259 pfasst::SDC<scalar> sdc;
187260
188261 auto nodes = pfasst::compute_nodes<scalar>(nnodes, " gauss-lobatto" );
189- auto * factory = new pfasst::encap::VectorFactory<scalar>(ndofs);
262+ auto * factory = new pfasst::encap::VectorFactory<scalar, double >(ndofs);
190263 auto * sweeper = new ADIMEX<scalar>(ndofs);
191264
192265 sweeper->set_nodes (nodes);
@@ -198,11 +271,37 @@ int main(int argc, char **argv)
198271
199272 dvector q0 (ndofs);
200273 sweeper->exact (q0, 0.0 );
201- sweeper->set_q0 (&q0);
274+ sweeper->set_q (&q0, 0 );
202275
203276 sdc.run ();
204277 } else {
205- // ...
278+ pfasst::MLSDC<scalar> mlsdc;
279+
280+ for (int l=0 ; l<nlevs; l++) {
281+ auto nodes = pfasst::compute_nodes<scalar>(nnodes, " gauss-lobatto" );
282+ auto * factory = new pfasst::encap::VectorFactory<scalar,double >(ndofs);
283+ auto * sweeper = new ADIMEX<scalar>(ndofs);
284+ auto * transfer = new ADTRANS<scalar>();
285+
286+ sweeper->set_nodes (nodes);
287+ sweeper->set_factory (factory);
288+
289+ ndofs = ndofs / 2 ;
290+ nnodes = (nnodes-1 )/2 + 1 ;
291+
292+ mlsdc.add_level (sweeper, transfer);
293+ }
294+
295+ mlsdc.set_duration (dt, nsteps, 4 );
296+ mlsdc.setup ();
297+
298+ for (int l=0 ; l<nlevs; l++) {
299+ auto * sweeper = mlsdc.get_level <ADIMEX<scalar>>(l);
300+ dvector& q0 = *dynamic_cast <dvector*>(sweeper->get_q (0 ));
301+ sweeper->exact (q0, 0.0 );
302+ }
303+
304+ mlsdc.run ();
206305 }
207306
208307 return 0 ;
0 commit comments