Mallard 0.8.0
Unstructured, GPU accelerated, high-order finite volume CFD solver
Mallard website
Loading...
Searching...
No Matches
transport.h
Go to the documentation of this file.
1
13#ifndef CHEMISTRY_TRANSPORT_H
14#define CHEMISTRY_TRANSPORT_H
15
16#include <array>
17#include <cmath>
18#include <cstdint>
19#include <stdexcept>
20#include <string>
21#include <vector>
22
23#include <Kokkos_Core.hpp>
24
25#include "mechanism.h"
26
27namespace chemistry {
28
34
45 std::vector<std::array<double, 5>> viscosity; // per species
46 std::vector<std::array<double, 5>> conductivity; // per species
47 std::vector<std::array<double, 5>> diffusion; // per pair (k, j >= k), k-major
48};
49
54TransportFits fit_transport(const Mechanism & mechanism);
55
64 std::vector<std::array<double, 9>> cstar;
65 std::vector<double> well_depth;
66};
67
73
86template <typename MemorySpace = Kokkos::DefaultExecutionSpace::memory_space>
90 Kokkos::View<double *, MemorySpace> W; // kg/kmol
91 Kokkos::View<double *, MemorySpace> inv_Lewis; // constant Lewis numbers
92 Kokkos::View<double *[5], Kokkos::LayoutRight, MemorySpace> visc; // (k, coefficient)
93 Kokkos::View<double *[5], Kokkos::LayoutRight, MemorySpace> cond;
94 Kokkos::View<double **[5], Kokkos::LayoutRight, MemorySpace> diff; // (k, j, coefficient), symmetric
95 Kokkos::View<double **, Kokkos::LayoutRight, MemorySpace> wilke_w; // (W_j / W_k)^(1/4)
96 Kokkos::View<double **, Kokkos::LayoutRight, MemorySpace> wilke_d; // 1 / sqrt(8 (1 + W_k / W_j))
97 bool thermal_diffusion = false;
98 Kokkos::View<double **[9], Kokkos::LayoutRight, MemorySpace> cstar; // (k, j, coefficient), symmetric
99 Kokkos::View<double **, Kokkos::LayoutRight, MemorySpace> log_eps; // ln(epsilon_kj / k_B), so ln T* = ln T - log_eps
100
101 static constexpr double TINY = 1.0e-20; // smallest mole fraction in the mixing rules, as in Cantera
102
104 static double poly(const double * c, const double L) {
105 return c[0] + L * (c[1] + L * (c[2] + L * (c[3] + L * c[4])));
106 }
107
109 double species_viscosity(const uint32_t k, const double T) const {
110 const double s = Kokkos::sqrt(Kokkos::sqrt(T)) * poly(&visc(k, 0), Kokkos::log(T));
111 return s * s;
112 }
113
115 double species_conductivity(const uint32_t k, const double T) const {
116 return Kokkos::sqrt(T) * poly(&cond(k, 0), Kokkos::log(T));
117 }
118
121 double binary_diffusion(const uint32_t k, const uint32_t j, const double T, const double p) const {
122 return T * Kokkos::sqrt(T) * poly(&diff(k, j, 0), Kokkos::log(T)) / p;
123 }
124
138 template <typename F_Y>
139 KOKKOS_INLINE_FUNCTION void properties(const double T, const double p, const double rho, const double cp,
140 const F_Y & y, double & mu, double & lambda, double * D,
141 double * DT = nullptr) const {
142 const double L = Kokkos::log(T);
143 const double sqrt_T = Kokkos::sqrt(T);
144 const double t14 = Kokkos::sqrt(sqrt_T);
145 // Small negative mass fractions (round-off, or the overshoots of explicit
146 // diffusion) count as zero
147 auto Y = [&](const uint32_t k) { return Kokkos::fmax(0.0, y(k)); };
148 double n = 0.0;
149 for (uint32_t k = 0; k < n_species; k++) n += Y(k) / W(k);
150 const double inv_n = 1.0 / n; // mean molar mass
151 auto X = [&](const uint32_t k) { return Kokkos::fmax(TINY, Y(k) / W(k) * inv_n); };
152 // sqrt(mu_k) in D until the diffusion coefficients
153 for (uint32_t k = 0; k < n_species; k++) D[k] = t14 * poly(&visc(k, 0), L);
154 mu = 0.0;
155 for (uint32_t k = 0; k < n_species; k++) {
156 double sum = 0.0;
157 for (uint32_t j = 0; j < n_species; j++) {
158 const double f = 1.0 + D[k] / D[j] * wilke_w(k, j);
159 sum += f * f * wilke_d(k, j) * X(j);
160 }
161 mu += X(k) * D[k] * D[k] / sum;
162 }
163 if (DT) {
164 // a_k = (15/4) (mu_k / W_k) / (1 + 1.065 sum_(j != k) X_j Phi_kj / X_k), held in DT
165 for (uint32_t k = 0; k < n_species; k++) {
166 if (Y(k) < TINY) {
167 DT[k] = 0.0;
168 continue;
169 }
170 double sum = 0.0;
171 for (uint32_t j = 0; j < n_species; j++) {
172 if (j == k) continue;
173 const double f = 1.0 + D[k] / D[j] * wilke_w(k, j);
174 sum += X(j) * (f * f * wilke_d(k, j));
175 }
176 DT[k] = (15.0 / 4.0) * D[k] * D[k] / W(k) / (1.0 + 1.065 * sum / X(k));
177 }
178 }
179 double sum1 = 0.0, sum2 = 0.0;
180 for (uint32_t k = 0; k < n_species; k++) {
181 const double lambda_k = sqrt_T * poly(&cond(k, 0), L);
182 sum1 += X(k) * lambda_k;
183 sum2 += X(k) / lambda_k;
184 }
185 lambda = 0.5 * (sum1 + 1.0 / sum2);
187 const double alpha = lambda / (rho * cp);
188 for (uint32_t k = 0; k < n_species; k++) D[k] = alpha * inv_Lewis(k);
189 return;
190 }
191 const double T15_p = T * sqrt_T / p;
192 if (n_species == 1) {
193 D[0] = T15_p * poly(&diff(0, 0, 0), L);
194 if (DT) DT[0] = 0.0;
195 return;
196 }
197 if (DT) {
198 // sum_(j != k) (1.2 C*_kj - 1) / (D_kj (W_k + W_j)) (Y_k a_j - Y_j a_k), held in D
199 for (uint32_t k = 0; k < n_species; k++) D[k] = 0.0;
200 for (uint32_t k = 0; k + 1 < n_species; k++) {
201 for (uint32_t j = k + 1; j < n_species; j++) {
202 const double log_ts = L - log_eps(k, j);
203 const double * c = &cstar(k, j, 0);
204 double C = c[8];
205 for (int m = 7; m >= 0; m--) C = C * log_ts + c[m];
206 const double D_kj = T15_p * poly(&diff(k, j, 0), L);
207 const double f = (1.2 * C - 1.0) / D_kj / (W(k) + W(j));
208 const double s = f * (Y(k) * DT[j] - Y(j) * DT[k]);
209 D[k] += s;
210 D[j] -= s;
211 }
212 }
213 }
214 // D_k = (1 - Y_k) / sum_(j != k) X_j / D_kj, with 1 - Y_k summed from the
215 // other species: Cantera's (W - X_k W_k) / (W sum ...) cancels to round-off
216 // noise over a vanishing denominator where species k is nearly pure
217 for (uint32_t k = 0; k < n_species; k++) {
218 double sum = 0.0, others = 0.0;
219 for (uint32_t j = 0; j < n_species; j++) {
220 if (j == k) continue;
221 sum += X(j) / poly(&diff(j, k, 0), L);
222 others += Y(j);
223 }
224 const double D_k = others * T15_p / sum;
225 if (DT) DT[k] = D[k] * D_k * W(k) * inv_n;
226 D[k] = D_k;
227 }
228 if (DT) {
229 double norm = 0.0;
230 for (uint32_t k = 0; k < n_species; k++) norm += DT[k];
231 for (uint32_t k = 0; k < n_species; k++) DT[k] -= Y(k) * norm;
232 }
233 }
234};
235
241template <typename MemorySpace = Kokkos::DefaultExecutionSpace::memory_space>
243 const std::vector<double> & lewis = {},
244 const bool thermal_diffusion = false) {
245 const TransportFits fits = fit_transport(mechanism);
247 const uint32_t n = mechanism.n_species();
248 table.n_species = n;
249 table.model = model;
250 table.W = Kokkos::View<double *, MemorySpace>("transport_W", n);
251 table.inv_Lewis = Kokkos::View<double *, MemorySpace>("transport_inv_Lewis", n);
252 table.visc = Kokkos::View<double *[5], Kokkos::LayoutRight, MemorySpace>("transport_visc", n);
253 table.cond = Kokkos::View<double *[5], Kokkos::LayoutRight, MemorySpace>("transport_cond", n);
254 table.diff = Kokkos::View<double **[5], Kokkos::LayoutRight, MemorySpace>("transport_diff", n, n);
255 table.wilke_w = Kokkos::View<double **, Kokkos::LayoutRight, MemorySpace>("transport_wilke_w", n, n);
256 table.wilke_d = Kokkos::View<double **, Kokkos::LayoutRight, MemorySpace>("transport_wilke_d", n, n);
257 auto h_W = Kokkos::create_mirror_view(table.W);
258 auto h_inv_Le = Kokkos::create_mirror_view(table.inv_Lewis);
259 auto h_visc = Kokkos::create_mirror_view(table.visc);
260 auto h_cond = Kokkos::create_mirror_view(table.cond);
261 auto h_diff = Kokkos::create_mirror_view(table.diff);
262 auto h_ww = Kokkos::create_mirror_view(table.wilke_w);
263 auto h_wd = Kokkos::create_mirror_view(table.wilke_d);
264 size_t pair = 0;
265 for (uint32_t k = 0; k < n; k++) {
266 h_W(k) = mechanism.species[k].molecular_weight;
267 h_inv_Le(k) = (model == TransportModel::CONSTANT_LEWIS && !lewis.empty()) ? 1.0 / lewis[k] : 1.0;
268 for (size_t c = 0; c < 5; c++) {
269 h_visc(k, c) = fits.viscosity[k][c];
270 h_cond(k, c) = fits.conductivity[k][c];
271 }
272 for (uint32_t j = k; j < n; j++, pair++) {
273 for (size_t c = 0; c < 5; c++) {
274 h_diff(k, j, c) = fits.diffusion[pair][c];
275 h_diff(j, k, c) = fits.diffusion[pair][c];
276 }
277 }
278 }
279 for (uint32_t k = 0; k < n; k++) {
280 for (uint32_t j = 0; j < n; j++) {
281 h_ww(k, j) = std::sqrt(std::sqrt(h_W(j) / h_W(k)));
282 h_wd(k, j) = 1.0 / (std::sqrt(8.0) * std::sqrt(1.0 + h_W(k) / h_W(j)));
283 }
284 }
285 Kokkos::deep_copy(table.W, h_W);
286 Kokkos::deep_copy(table.inv_Lewis, h_inv_Le);
287 Kokkos::deep_copy(table.visc, h_visc);
288 Kokkos::deep_copy(table.cond, h_cond);
289 Kokkos::deep_copy(table.diff, h_diff);
290 Kokkos::deep_copy(table.wilke_w, h_ww);
291 Kokkos::deep_copy(table.wilke_d, h_wd);
292 if (thermal_diffusion) {
294 throw std::invalid_argument("Thermal diffusion needs the mixture-averaged transport model.");
295 }
296 const ThermalDiffusionFits td = fit_thermal_diffusion(mechanism);
297 table.thermal_diffusion = true;
298 table.cstar = Kokkos::View<double **[9], Kokkos::LayoutRight, MemorySpace>("transport_cstar", n, n);
299 table.log_eps = Kokkos::View<double **, Kokkos::LayoutRight, MemorySpace>("transport_log_eps", n, n);
300 auto h_cstar = Kokkos::create_mirror_view(table.cstar);
301 auto h_log_eps = Kokkos::create_mirror_view(table.log_eps);
302 size_t p = 0;
303 for (uint32_t k = 0; k < n; k++) {
304 for (uint32_t j = k; j < n; j++, p++) {
305 for (size_t c = 0; c < 9; c++) {
306 h_cstar(k, j, c) = td.cstar[p][c];
307 h_cstar(j, k, c) = td.cstar[p][c];
308 }
309 h_log_eps(k, j) = h_log_eps(j, k) = std::log(td.well_depth[p] / BOLTZMANN);
310 }
311 }
312 Kokkos::deep_copy(table.cstar, h_cstar);
313 Kokkos::deep_copy(table.log_eps, h_log_eps);
314 }
315 return table;
316}
317
318} // namespace chemistry
319
320#endif // CHEMISTRY_TRANSPORT_H
KOKKOS_INLINE_FUNCTION rtype dot(const rtype *a, const rtype *b)
Compute the dot product of two arrays.
Definition common_math.h:32
Gas-phase mechanisms read from Cantera YAML files.
Definition kinetics.h:25
constexpr double BOLTZMANN
Definition mechanism.h:25
TransportFits fit_transport(const Mechanism &mechanism)
Fit the transport properties of every species of a mechanism.
Definition transport.cpp:352
TransportTable< MemorySpace > make_transport_table(const Mechanism &mechanism, const TransportModel model, const std::vector< double > &lewis={}, const bool thermal_diffusion=false)
The transport table of a mechanism for a model.
Definition transport.h:242
TransportModel
Definition transport.h:29
ThermalDiffusionFits fit_thermal_diffusion(const Mechanism &mechanism)
Fit the thermal diffusion data of a mechanism.
Definition transport.cpp:441
One ideal-gas phase of a Cantera YAML file: its elements, species and reactions.
Definition mechanism.h:145
std::vector< Species > species
Definition mechanism.h:149
uint32_t n_species() const
Definition mechanism.h:152
Pair data of Cantera's mixture-averaged thermal diffusion: its fit of the reduced collision integral ...
Definition transport.h:63
std::vector< std::array< double, 9 > > cstar
Definition transport.h:64
std::vector< double > well_depth
Definition transport.h:65
Pure-species transport fits of a mechanism, as Cantera computes them for its mixture-averaged model: ...
Definition transport.h:44
std::vector< std::array< double, 5 > > viscosity
Definition transport.h:45
std::vector< std::array< double, 5 > > conductivity
Definition transport.h:46
std::vector< std::array< double, 5 > > diffusion
Definition transport.h:47
Transport properties of a mechanism's mixtures on the device, in double precision in every build: Wil...
Definition transport.h:87
static KOKKOS_INLINE_FUNCTION double poly(const double *c, const double L)
Definition transport.h:104
KOKKOS_INLINE_FUNCTION double species_conductivity(const uint32_t k, const double T) const
Definition transport.h:115
Kokkos::View< double *, MemorySpace > inv_Lewis
Definition transport.h:91
Kokkos::View< double *, MemorySpace > W
Definition transport.h:90
static constexpr double TINY
Definition transport.h:101
Kokkos::View< double *[5], Kokkos::LayoutRight, MemorySpace > visc
Definition transport.h:92
KOKKOS_INLINE_FUNCTION void properties(const double T, const double p, const double rho, const double cp, const F_Y &y, double &mu, double &lambda, double *D, double *DT=nullptr) const
Mixture viscosity mu [Pa s], conductivity lambda [W/(m K)] and species diffusion coefficients D [m^2/...
Definition transport.h:139
Kokkos::View< double **, Kokkos::LayoutRight, MemorySpace > wilke_d
Definition transport.h:96
Kokkos::View< double *[5], Kokkos::LayoutRight, MemorySpace > cond
Definition transport.h:93
TransportModel model
Definition transport.h:89
uint32_t n_species
Definition transport.h:88
Kokkos::View< double **, Kokkos::LayoutRight, MemorySpace > log_eps
Definition transport.h:99
bool thermal_diffusion
Definition transport.h:97
Kokkos::View< double **, Kokkos::LayoutRight, MemorySpace > wilke_w
Definition transport.h:95
KOKKOS_INLINE_FUNCTION double species_viscosity(const uint32_t k, const double T) const
Definition transport.h:109
KOKKOS_INLINE_FUNCTION double binary_diffusion(const uint32_t k, const uint32_t j, const double T, const double p) const
Binary diffusion coefficient D_kj [m^2/s] at T and p.
Definition transport.h:121
Kokkos::View< double **[5], Kokkos::LayoutRight, MemorySpace > diff
Definition transport.h:94
Kokkos::View< double **[9], Kokkos::LayoutRight, MemorySpace > cstar
Definition transport.h:98
SlotArray< double, Space > X
Definition teno_setup.cpp:478
CellSetup< ExecSpace > c
Definition teno_setup.cpp:1810
@ DT
Definition time_integrator.h:55