forked from mdelorme/fv2d
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUpdate.h
194 lines (159 loc) · 5.95 KB
/
Update.h
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
#pragma once
#include "SimInfo.h"
#include "RiemannSolvers.h"
#include "BoundaryConditions.h"
#include "ThermalConduction.h"
#include "Viscosity.h"
namespace fv2d {
namespace {
KOKKOS_INLINE_FUNCTION
State reconstruct(Array Q, Array slopes, int i, int j, real_t sign, IDir dir, const Params ¶ms) {
State q = getStateFromArray(Q, i, j);
State slope = getStateFromArray(slopes, i, j);
State res;
switch (params.reconstruction) {
case PLM: res = q + slope * sign * 0.5; break; // Piecewise Linear
case PCM_WB: // Piecewise constant + Well-balancing
res[IR] = q[IR];
res[IU] = q[IU];
res[IV] = q[IV];
res[IP] = (dir == IX ? q[IP] : q[IP] + sign * q[IR] * params.g * params.dy * 0.5);
break;
default: res = q; // Piecewise Constant
}
return swap_component(res, dir);
}
}
class UpdateFunctor {
public:
Params params;
BoundaryManager bc_manager;
ThermalConductionFunctor tc_functor;
ViscosityFunctor visc_functor;
Array slopesX, slopesY;
UpdateFunctor(const Params ¶ms)
: params(params), bc_manager(params),
tc_functor(params), visc_functor(params) {
slopesX = Array("SlopesX", params.Nty, params.Ntx, Nfields);
slopesY = Array("SlopesY", params.Nty, params.Ntx, Nfields);
};
~UpdateFunctor() = default;
KOKKOS_INLINE_FUNCTION
void computeSlopes(const Array &Q) const {
auto slopesX = this->slopesX;
auto slopesY = this->slopesY;
auto params = this->params;
Kokkos::parallel_for(
"Slopes",
params.range_slopes,
KOKKOS_LAMBDA(const int i, const int j) {
for (int ivar=0; ivar < Nfields; ++ivar) {
real_t dL = Q(j, i, ivar) - Q(j, i-1, ivar);
real_t dR = Q(j, i+1, ivar) - Q(j, i, ivar);
real_t dU = Q(j, i, ivar) - Q(j-1, i, ivar);
real_t dD = Q(j+1, i, ivar) - Q(j, i, ivar);
auto minmod = [](real_t dL, real_t dR) -> real_t {
if (dL*dR < 0.0)
return 0.0;
else if (fabs(dL) < fabs(dR))
return dL;
else
return dR;
};
slopesX(j, i, ivar) = minmod(dL, dR);
slopesY(j, i, ivar) = minmod(dU, dD);
}
});
}
void computeFluxesAndUpdate(Array Q, Array Unew, real_t dt) const {
auto params = this->params;
auto slopesX = this->slopesX;
auto slopesY = this->slopesY;
Kokkos::parallel_for(
"Update",
params.range_dom,
KOKKOS_LAMBDA(const int i, const int j) {
// Lambda to update the cell along a direction
auto updateAlongDir = [&](int i, int j, IDir dir) {
auto& slopes = (dir == IX ? slopesX : slopesY);
int dxm = (dir == IX ? -1 : 0);
int dxp = (dir == IX ? 1 : 0);
int dym = (dir == IY ? -1 : 0);
int dyp = (dir == IY ? 1 : 0);
State qCL = reconstruct(Q, slopes, i, j, -1.0, dir, params);
State qCR = reconstruct(Q, slopes, i, j, 1.0, dir, params);
State qL = reconstruct(Q, slopes, i+dxm, j+dym, 1.0, dir, params);
State qR = reconstruct(Q, slopes, i+dxp, j+dyp, -1.0, dir, params);
// Calling the right Riemann solver
auto riemann = [&](State qL, State qR, State &flux, real_t &pout) {
switch (params.riemann_solver) {
case HLL: hll(qL, qR, flux, pout, params); break;
default: hllc(qL, qR, flux, pout, params); break;
}
};
// Calculating flux left and right of the cell
State fluxL, fluxR;
real_t poutL, poutR;
riemann(qL, qCL, fluxL, poutL);
riemann(qCR, qR, fluxR, poutR);
fluxL = swap_component(fluxL, dir);
fluxR = swap_component(fluxR, dir);
// Remove mechanical flux in a well-balanced fashion
if (params.well_balanced_flux_at_y_bc && (j==params.jbeg || j==params.jend-1) && dir == IY) {
if (j==params.jbeg)
fluxL = State{0.0, 0.0, poutR - Q(j, i, IR)*params.g*params.dy, 0.0};
else
fluxR = State{0.0, 0.0, poutL + Q(j, i, IR)*params.g*params.dy, 0.0};
}
auto un_loc = getStateFromArray(Unew, i, j);
un_loc += dt*(fluxL - fluxR)/(dir == IX ? params.dx : params.dy);
if (dir == IY && params.gravity) {
un_loc[IV] += dt * Q(j, i, IR) * params.g;
un_loc[IE] += dt * 0.5 * (fluxL[IR] + fluxR[IR]) * params.g;
}
setStateInArray(Unew, i, j, un_loc);
};
updateAlongDir(i, j, IX);
updateAlongDir(i, j, IY);
Unew(j, i, IR) = fmax(1.0e-6, Unew(j, i, IR));
});
}
void euler_step(Array Q, Array Unew, real_t dt) {
// First filling up boundaries for ghosts terms
bc_manager.fillBoundaries(Q);
// Hypperbolic udpate
if (params.reconstruction == PLM)
computeSlopes(Q);
computeFluxesAndUpdate(Q, Unew, dt);
// Splitted terms
if (params.thermal_conductivity_active)
tc_functor.applyThermalConduction(Q, Unew, dt);
if (params.viscosity_active)
visc_functor.applyViscosity(Q, Unew, dt);
}
void update(Array Q, Array Unew, real_t dt) {
if (params.time_stepping == TS_EULER)
euler_step(Q, Unew, dt);
else if (params.time_stepping == TS_RK2) {
Array U0 = Array("U0", params.Nty, params.Ntx, Nfields);
Array Ustar = Array("Ustar", params.Nty, params.Ntx, Nfields);
// Step 1
Kokkos::deep_copy(U0, Unew);
Kokkos::deep_copy(Ustar, Unew);
euler_step(Q, Ustar, dt);
// Step 2
Kokkos::deep_copy(Unew, Ustar);
consToPrim(Ustar, Q, params);
euler_step(Q, Unew, dt);
// SSP-RK2
Kokkos::parallel_for(
"RK2 Correct",
params.range_dom,
KOKKOS_LAMBDA(const int i, const int j) {
for (int ivar=0; ivar < Nfields; ++ivar)
Unew(j, i, ivar) = 0.5 * (U0(j, i, ivar) + Unew(j, i, ivar));
});
}
}
};
}