Skip to content

Commit 830c7fc

Browse files
committed
MLSDC: Get MLSDC almost working (FAS currently missing).
1 parent 547b11d commit 830c7fc

File tree

9 files changed

+619
-141
lines changed

9 files changed

+619
-141
lines changed

examples/ad/main.cpp

Lines changed: 154 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
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;
2728
const int xrat = 2;
2829
const int trat = 2;
2930

30-
const int nsteps = 32;
31+
const int nsteps = 1;
3132
const double dt = 0.01;
3233

3334
typedef double scalar;
3435

3536
using namespace std;
3637
using 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>;
4499
template<typename time>
45100
class 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

180253
int 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

Comments
 (0)