-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEuler_1D.C
384 lines (308 loc) · 9.55 KB
/
Euler_1D.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
/* This program is designed to simulate the Euler equations
in 1 dimension, using the FORCE solver.
It provides output in ASCII format, suitable for plotting in gnuplot.
*/
#include <array>
#include <vector>
#include <iostream>
#include <fstream>
#include <cmath>
#include <tuple>
#include <limits>
// Calculate energy using equations on slide 14 of Euler lecture notes
double calc_E(double r, double u, double p, double gamma) {
// where r is density, u is velocity, and p is pressure of an ideal gas
return p/(gamma-1) + (0.5 * r * u * u);
}
std::array<double, 3> array_addition(std::array<double, 3> firstArray, std::array<double, 3> secondArray)
{
std::array<double, firstArray.size() > outputArray;
for (int i = 0; i < firstArray.size(); i++)
{
outputArray[i] = firstArray[i] + secondArray[i];
}
return outputArray;
}
std::array<double, 3> array_subtraction(std::array<double, 3> firstArray, std::array<double, 3> secondArray)
{
std::array<double, firstArray.size() > outputArray;
for (int i = 0; i < firstArray.size(); i++)
{
outputArray[i] = firstArray[i] - secondArray[i];
}
return outputArray;
}
// Convert from conserved variables to primitive variables
std::array<double, 3> primitive(std::array<double, 3>& q_i, double gamma){
std::array<double, 3> w_i;
// Convert the conserved state variables q_i to the primitive variables w_i
w_i[0] = q_i[0]; // density
w_i[1] = q_i[1] / q_i[0]; // velocity
w_i[2] = (gamma-1) * (q_i[2] - 0.5 * q_i[0] * w_i[1] * w_i[1]); // pressure
return w_i;
}
// Convert primitive state vector to conservative state vector
std::array<double, 3> conservative(std::array<double, 3>& w_i, double gamma)
{
std::array<double, 3> q_i;
// Convert the primitive variables w_i to the conserved variables q_i
// w_i = (r, u, p) and q_i = (r, r * u, E) - from slides 11 and 18
q_i[0] = w_i[0]; // density
q_i[1] = w_i[0] * w_i[1]; // momentum
q_i[2] = calc_E(w_i[0], w_i[1], w_i[2], gamma); // energy
return q_i;
}
// Fill the conservative state vector with the initial data
void initialiseData(double gamma, std::vector<std::array<double, 3> >& q, int test, double& finalT)
{
int n = q.size();
if(test == 1)
{
finalT = 0.25;
for(int i = 0; i < n; ++i)
{
std::array<double, 3> w;
if(i < n/2)
{
w = {1.0,0.0,1.0};
}
else
{
w = {0.125,0.0,0.1};
}
std::array<double, 3> q_i = conservative(w, gamma);
q.at(i)[0] = q_i[0];
q.at(i)[1] = q_i[1];
q.at(i)[2] = q_i[2];
}
}
else if(test == 2)
{
finalT = 0.25;
for(int i = 0; i < n; ++i)
{
std::array<double, 3> w;
if(i < n/2)
{
w = {1.0,0.0,1.0};
}
else
{
w = {0.125,0.0,0.1};
}
std::array<double, 3> q_i = conservative(w, gamma);
q[i][0] = q_i[0];
q[i][1] = q_i[1];
q[i][2] = q_i[2];
}
}
else if(test == 3)
{
finalT = 0.25;
for(int i = 0; i < n; ++i)
{
std::array<double, 3> w;
if(i < n/2)
{
w = {1.0,0.0,1.0};
}
else
{
w = {0.125,0.0,0.1};
}
std::array<double, 3> q_i = conservative(w, gamma);
q[i][0] = q_i[0];
q[i][1] = q_i[1];
q[i][2] = q_i[2];
}
}
else if(test == 4)
{
finalT = 0.25;
for(int i = 0; i < n; ++i)
{
std::array<double, 3> w;
if(i < n/2)
{
w = {1.0,0.0,1.0};
}
else
{
w = {0.125,0.0,0.1};
}
std::array<double, 3> q_i = conservative(w, gamma);
q[i][0] = q_i[0];
q[i][1] = q_i[1];
q[i][2] = q_i[2];
}
}
else if(test == 5)
{
finalT = 0.25;
for(int i = 0; i < n; ++i)
{
std::array<double, 3> w;
if(i < n/2)
{
w = {1.0,0.0,1.0};
}
else
{
w = {0.125,0.0,0.1};
}
std::array<double, 3> q_i = conservative(w, gamma);
q[i][0] = q_i[0];
q[i][1] = q_i[1];
q[i][2] = q_i[2];
}
}
else
{
// TODO
// Add suitable error handling
}
}
bool computeDomainBoundaries(std::vector<std::array<double, 3> >& q)
{
q.front()[0] = q.at(front() + 1)[0];
q.front()[1] = q.at(front() + 1)[1];
q.front()[2] = q.at(front() + 1)[2];
q.back()[0] = q.at(back() - 1)[0];
q.back()[1] = q.at(back() - 1)[1];
q.back()[2] = q.at(back() - 1)[2];
return true;
}
// Compute flux-vector corresponding to given state vector
// Equations for flux given on slide 11 of Euler notes
std::array<double, 3> flux(std::array<double, 3>& q_i, double gamma)
{
std::array<double, 3> f;
std::array<double, 3> w_i = primitive(q_i, gamma);
f[0] = w_i[0] * w_i[1]; // r * u
f[1] = w_i[0] * w_i[1] * w_i[1] + w_i[2]; // r * u^2 + p
f[2] = (q_i[2] + w_i[2]) * w_i[1]; // (E + p) * u
return f;
}
// Compute the maximum stable time-step for the given data
double computeTimestep(double gamma, int cellNumber, std::vector<std::array<double, 3>> &q, double dx, double CFL)
{
double dt = 0, alphaOld = 0, alphaMax = 0;
std::vector<double> Cs;
std::cout << "Gamma: " << gamma << std::endl;
std::cout << "cellNumber: " << cellNumber << std::endl;
std::cout << "dx: " << dx << std::endl;
std::cout << "CFL: " << CFL << std::endl;
// Compute the maximum wavespeed over the entire domain, and use this to compute the timestep
for(int i=0 ; i < cellNumber ; i++)
{
/* w_i = (r, u, p) */
Cs.push_back(sqrt( gamma * (q[2][i]/q[0][i]) ));
std::cout << "Cs: " << Cs[i] << std::endl;
alphaOld = abs(q.at(1)[i]) + Cs[i];
std::cout << "alpha: " << alphaOld << std::endl;
if (alphaOld > alphaMax) alphaMax = alphaOld;
}
dt = (CFL*dx)/alphaMax;
std::cout << "dt: " << dt << std::endl;
return dt;
}
// Compute the FORCE flux between two states uL and uR in coordinate direction coord.
std::array<double, 3> FORCEflux(double gamma, std::array<double, 3>& q_iMinus1, std::array<double, 3>& q_i, double dx, double dt)
{
std::array<double, 3> fluxLF_temp1;
std::array<double, 3> fluxLF_temp2;
// Compute the Richtmyer flux using q_i and q_iMinus1
std::array<double, 3> fluxRM;
std::array<double, 3> q_iHalf;
double halfDeltaTDeltaX = 0.5 * (dt/dx);
fluxLF_temp1 = array_addition(q_iMinus1, q_i);
fluxLF_temp2 = array_subtraction(flux(q_iMinus1, gamma), flux(q_i, gamma));
// q_iHalf = 0.5 * (array_addition(q_iMinus1, q_i)) + halfdelta *
for (int i=0;i < fluxLF_temp1.size(); i++){
fluxLF_temp1[i] *= 0.5;
fluxLF_temp2[i] *= halfDeltaTDeltaX;
}
q_iHalf = array_addition(fluxLF_temp1, fluxLF_temp2);
fluxRM = flux(q_iHalf, gamma);
// Compute the Lax-Friedrichs flux using q_i and q_iMinus1
std::array<double, 3> fluxLF;
double halfDeltaXDeltaT = 0.5 * (dx/dt);
// fluxLF = flux_temp1 + flux_temp2;
fluxLF_temp1 = array_addition(flux(q_iMinus1, gamma), flux(q_i, gamma));
fluxLF_temp2 = array_subtraction(q_iMinus1, q_i);
for (int i=0;i < fluxLF_temp1.size(); i++){
fluxLF_temp1[i] *= 0.5;
fluxLF_temp2[i] *= halfDeltaXDeltaT;
}
fluxLF = array_addition(fluxLF_temp1, fluxLF_temp2);
std::array<double, 3> fluxForce;
// Compute the FORCE flux
// fluxForce = 0.5 * (fluxRM + fluxLF);
for (int i=0; i<3; i++){
fluxForce[i] = 0.5 * (fluxLF[i] + fluxRM[i]);
}
return fluxForce;
}
// Compute the array of fluxes from the given data array
void computeFluxes(double gamma, std::vector<std::array<double, 3> >& q, std::vector<std::array<double, 3> >& flux, double dx, double dt)
{
int n = q.size();
std::cout << "N: " << n << std::endl;
// Flux for current cell calculated using values from previous cell. Don't have values for cell i=-1 so can't start loop at i=0
for(unsigned int i=1 ; i < n ; i++)
{
flux[i] = FORCEflux(gamma, q[i-1], q[i], dx, dt);
}
}
int main(void)
{
// User-defined parameters
int cells;
int test;
std::cout << "Number of cells: " << std::flush;
std::cin >> cells;
std::cout << "Test number (1-5): " << std::flush;
std::cin >> test;
const double gamma = 1.4;
const double CFL = 0.9;
double finalT;
// Set initial vectors:
std::vector<std::array<double, 3> > q(cells+2);
std::vector<std::array<double, 3> > flux(cells+2);
// TODO - consider the extent of the vectors, the flux vector actually contains one more cell than it needs to
initialiseData(gamma, q, test, finalT);
// Do simulation
double t = 0;
double dx = 1.0 / cells;
// You may wish to change the 1.0 to a specification of your own domain size
std::cout << "Simulation started..." << std::endl;
while( t < finalT )
{
computeDomainBoundaries(q);
double dt = computeTimestep(gamma, cells, q, dx, CFL);
computeFluxes(gamma, q, flux, dx, dt);
// TODO - consider why these are the limits chosen
for(int i = 1; i < cells + 1; ++i)
{
for(int var = 0; var < 3; ++var)
{
q[i][var] = q[i][var] - (dt/dx) * (flux[i+1][var] - flux[i][var]);
}
}
t += dt;
// Output some useful data to screen here so you know the code is running as expected
std::cout << " t = " << t << " => " << t/finalT * 100.0 << "%" << std::endl;
}
// Output
std::ofstream rhoOutput("density.dat");
std::ofstream velOutput("velocity.dat");
std::ofstream preOutput("pressure.dat");
for(unsigned int i=1 ; i < cells + 1 ; i++) {
double x = (double(i) + 0.5) * dx;
std::array<double, 3> w = primitive(q[i], gamma);
rhoOutput << x << " " << w[0] << std::endl;
velOutput << x << " " << w[1] << std::endl;
preOutput << x << " " << w[2] << std::endl;
}
return 0;
}