Theseus
Compressible flow solver
Loading...
Searching...
No Matches
LTETable.hpp
Go to the documentation of this file.
1// Copyright (c) 2025-2026 Board of Trustees of the University of Illinois
2//
3// This file is part of Theseus.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6#pragma once
7
8#include "Physics.hpp"
9#include "GasState.hpp"
10#include "theseus_kernels.hpp"
11#ifdef USE_PLATO
12#include "plato_Cpp_library_interface.h"
13#include "TheseusConfig.hpp"
14#include <filesystem>
15#endif
16
17namespace Theseus
18{
19 namespace LTETable {
20
21 struct Layout
22 {
23 // LTE table specific quantities
24 int nx, ny; // dimensions of LTE table
25 int num_properties = 9; // CL NOTE : change the num_properties if more are being stored
26
27 // Property indices in the LTE table
28 int P_idx = 0; // pressure
29 int e_idx = 1; // internal energy
30 int cv_idx = 2; // specific heat at constant volume
31 int cp_idx = 3; // specific heat at constant pressure
32 int R_eq_idx = 4; // Mixture gas constant
33 int gamma_eq_idx = 5; // gamma-eq
34 int c_idx = 6; // equilibrium sound-speed
35 int mu_idx = 7; // shear viscosity
36 int lambda_idx = 8; // thermal conductivity
37
38 void setup(int nx_, int ny_)
39 {
40 nx = nx_;
41 ny = ny_;
42 }
43
44 // Flat index of properties in the flattened 3D LTE Table
45 MFEM_HOST_DEVICE inline int property_index(int property, int ind_x, int ind_y) const
46 {
47 int index;
48 // TODO: I don't think assert is allowed in device code
49 assert(property < num_properties);
50 index = property*ny*nx + ind_y*nx + ind_x;
51 return index;
52 }
53
54 };
55
56 struct Data
57 {
58 mfem::Vector lte_table;
59 mfem::Vector inv_table;
60 mfem::Vector rho_grid;
61 mfem::Vector T_grid;
62 mfem::Vector e_grid;
63 };
64
65 struct View
66 {
67 const mfem::real_t *lte_table;
68 const mfem::real_t *inv_table;
69 const mfem::real_t *rho_grid;
70 const mfem::real_t *T_grid;
71 const mfem::real_t *e_grid;
72 };
73
74
75 struct LTETables {
76 MFEM_HOST_DEVICE LTETables() = default;
77
78 LTETables(int nx_, int ny_ = 0)
79 { L.setup(nx_, ny_); }
80
83 };
84
85 inline void uniform_grid(int N, mfem::real_t min, mfem::real_t max, mfem::Vector &grid)
86 {
87 grid.SetSize(N);
88 double step = (max - min) / (N - 1);
89 for (int i = 0; i < N; ++i)
90 {
91 grid[i] = min + i * step;
92 }
93 }
94
95 inline void log_grid(int N, mfem::real_t min, mfem::real_t max, mfem::Vector &grid)
96 {
97 grid.SetSize(N);
98 double step = std::log10(max/min) / (N-1);
99 for (int i = 0;i < N; ++i)
100 {
101 grid[i] = min * std::pow(10, i * step);
102 }
103 }
104
105 inline void fill_table(const LTETable::Layout &L, const mfem::real_t* rho_grid, const mfem::real_t* T_grid,
106 mfem::real_t* lte_table, mfem::real_t &e_min, mfem::real_t &e_max)
107 {
108
109#ifdef USE_PLATO
110 mfem::real_t UKB = 1.380649e-23;
111 int nb_comp = plato_get_nb_comp();
112 int nb_spec = plato_get_nb_species();
113 int nb_temp = plato_get_nb_temp();
114 double X_tol = 1e-12;
115
116 mfem::Vector yc(nb_comp), Xc(nb_comp);
117 mfem::Vector Xi(nb_spec), Xitol(nb_spec), Xip(nb_spec), Xim(nb_spec), yi(nb_spec),
118 Ri(nb_spec), ei(nb_spec), hi(nb_spec), Ji(nb_spec),
119 Di(nb_spec),Dij(nb_spec*(nb_spec + 1)/2), di(nb_spec);
120 mfem::Vector temp(nb_temp), lambda_int(nb_temp);
121
122 mfem::real_t R, P, nb, e, betaT, alpha, cv, gam, cp, c,
123 mu, sigma, lambda_trh, lambda_tre, lambda_reactive;
124
125 plato_get_Ri(Ri.GetData());
126
127 int flag = 0;
128 for(int i=0; i < L.nx; i++)
129 {
130 const mfem::real_t rho = rho_grid[i];
131 for(int j=0; j < L.ny; j++)
132 {
133 yc = 1.0;
134 Xc = 1.0;
135
136 const mfem::real_t T = T_grid[j];
137 temp = T;
138
139 // Computing LTE composition
140 plato_get_eq_composition_mass(&rho, &T, yc.GetData(), yi.GetData(), &flag);
141 plato_mass_to_mole_fractions(yi.GetData(), Xi.GetData());
142
143 // Number density and pressure
144 R = Theseus::Kernels::Dot(nb_spec, Ri.GetData(), yi.GetData());
145 P = rho * R * T;
146 nb = P / (UKB*T);
147
148 // Energies and enthalpy per unit-mass
149 plato_get_species_energy(temp.GetData(), ei.GetData());
150 for(int sp=0; sp < nb_spec; sp++) hi[sp] = ei[sp] + Ri[sp]*T;
151 e = Theseus::Kernels::Dot(nb_spec, yi.GetData(), ei.GetData());
152
153 // Derived thermodynamic properties
154 // isothermal compressibility, coeff of thermal expansion, cv, cp, gamma, sound_speed at equilibrium
155 betaT = plato_get_eq_isoth_comp(&P, &T, Xi.GetData());
156 alpha = plato_get_eq_coeff_th_exp(&P, &T, Xi.GetData());
157 cv = plato_get_eq_cv(&rho, &T, yi.GetData());
158 gam = 1.0 + alpha*alpha*T/(rho*betaT*cv);
159 cp = gam*cv;
160 c = std::sqrt(gam*P/rho);
161
162 // Transport properties
163 // dynamic viscosity, thermal conductivity, components of thermal conductivity
164 plato_get_transp_coeff_comp(&nb, Xi.GetData(), temp.GetData(), &mu, &sigma,
165 &lambda_trh, &lambda_tre, lambda_int.GetData(), Di.GetData());
166
167 double eps = 1e-5;
168 double Tepsp1 = T*(1.0 + eps);
169 double Tepsm1 = T*(1.0 - eps);
170 // reactive thermal conductivity
171 // (NOTE: pass mole fractions with tolerance to procedure solving Stefan-Maxwell's equations)
172 plato_get_eq_composition_mole(&P, &Tepsp1, Xc.GetData(), Xip.GetData(), &flag);
173 plato_get_eq_composition_mole(&P, &Tepsm1, Xc.GetData(), Xim.GetData(), &flag);
174 plato_get_bin_diff_coeff(&nb, &T, &T, Xi.GetData(), Dij.GetData());
175 for(int sp=0; sp < nb_spec; sp++) di[sp] = -0.5 * (Xip[sp] - Xim[sp])/(eps*T);
176
177 double sum_Xitol = 0.0, X;
178 for(int sp=0; sp < nb_spec; sp++)
179 {
180 X = Xi[sp] + X_tol;
181 Xitol[sp] = X;
182 sum_Xitol += X;
183 }
184
185 sum_Xitol = 1.0/sum_Xitol;
186 for(int sp=0; sp < nb_spec; sp++) Xitol[sp] *= sum_Xitol;
187
188 plato_get_species_diff_flux(&T, &T, &nb, Xitol.GetData(), Dij.GetData(), di.GetData(), Ji.GetData());
189 lambda_reactive = Theseus::Kernels::Dot(nb_spec, Ji.GetData(), hi.GetData());
190
191 lte_table[L.property_index(L.P_idx, i, j)] = P;
192 lte_table[L.property_index(L.e_idx, i, j)] = e;
193 lte_table[L.property_index(L.cv_idx, i, j)] = cv;
194 lte_table[L.property_index(L.cp_idx, i, j)] = cp;
195 lte_table[L.property_index(L.R_eq_idx, i, j)] = R;
196 lte_table[L.property_index(L.gamma_eq_idx, i, j)] = gam;
197 lte_table[L.property_index(L.c_idx, i, j)] = c;
198 lte_table[L.property_index(L.mu_idx, i, j)] = mu;
199 lte_table[L.property_index(L.lambda_idx, i, j)] = lambda_trh + lambda_tre + lambda_int[0] + lambda_reactive;
200
201 if(i+j == 0)
202 {
203 e_min = e;
204 e_max = e;
205 }
206 else
207 {
208 e_min = std::min(e_min, e);
209 e_max = std::max(e_max, e);
210 }
211 }
212 }
213#endif
214 }
215
216 inline void fill_inv_table(const LTETable::Layout &L, const mfem::real_t* rho_grid, const mfem::real_t* e_grid,
217 const mfem::real_t* T_grid, mfem::real_t* inv_table)
218 {
219#ifdef USE_PLATO
220 int nb_comp = plato_get_nb_comp();
221 int nb_spec = plato_get_nb_species();
222
223 mfem::Vector yc(nb_comp);
224 mfem::Vector yi(nb_spec), ei(nb_spec);
225 mfem::Vector temp(1);
226
227 mfem::real_t rho, e0, e, res, cv;
228 mfem::real_t tol = 1e-8;
229
230 int flag = 0;
231 mfem::real_t T = T_grid[0];
232 for(int i = 0; i < L.nx; i++)
233 {
234 rho = rho_grid[i];
235 T = T_grid[0];
236 for(int j = 0; j < L.ny; j++)
237 {
238 e0 = e_grid[j];
239 res = 1.0;
240 yc = 1.0;
241 int it = 0;
242 // Newton iteration to find T such that internal energy at (rho, T) matches e0
243 while(res > tol)
244 {
245 temp = T;
246 plato_get_eq_composition_mass(&rho, &T, yc.GetData(), yi.GetData(), &flag);
247 plato_get_species_energy(temp.GetData(), ei.GetData());
248 e = Theseus::Kernels::Dot(nb_spec, yi.GetData(), ei.GetData());
249 cv = plato_get_eq_cv(&rho, &T, yi.GetData());
250
251 res = -(e - e0)/cv;
252 T += res;
253 it++;
254 res = std::abs(res)/T;
255
256 if(it > 100)
257 {
258 MFEM_ABORT("Maximum number of iterations reached in fill_inv_table");
259 }
260 if(T<0.0)
261 {
262 MFEM_ABORT("Negative temperature encountered in fill_inv_table");
263 }
264 }
265 inv_table[L.property_index(0 , i, j)] = T;
266 }
267 }
268#endif
269 }
270
271 MFEM_HOST_DEVICE inline
272 int hunt(const mfem::real_t *arr, int n, mfem::real_t x, int ind_lo)
273 {
274 int ind_hi, ind_mid;
275 int incr = 1;
276 bool ascend = (arr[n-1] >= arr[0]);
277
278 if (ind_lo < 0 || ind_lo >= n)
279 {
280 ind_lo = -1;
281 ind_hi = n;
282 }
283 else
284 {
285 // Right or Left Hunt
286 if ( (x >= arr[ind_lo]) == ascend)
287 {
288 // Hunt right
289 if (ind_lo == n-1) return ind_lo;
290 ind_hi = ind_lo + incr;
291
292 while (ind_hi < n && ((x >= arr[ind_hi]) == ascend))
293 {
294 ind_lo = ind_hi;
295 incr *= 2;
296 ind_hi = ind_lo + incr;
297 if (ind_hi > n-1)
298 {
299 ind_hi = n;
300 break;
301 }
302 }
303 }
304 // Hunt left
305 else
306 {
307 if (ind_lo == 0)
308 {
309 ind_lo = -1;
310 return ind_lo;
311 }
312 ind_hi = ind_lo;
313 ind_lo = ind_lo-1;
314 while (ind_lo >= 0 && ((x < arr[ind_lo]) == ascend))
315 {
316 ind_hi = ind_lo;
317 incr *= 2;
318 if (incr >= ind_hi)
319 {
320 ind_lo = -1;
321 break;
322 }
323 else ind_lo = ind_hi - incr;
324 }
325 }
326 }
327
328 // Binary Search in the estimated bracket
329 while(ind_hi - ind_lo != 1)
330 {
331 ind_mid = ind_lo + (ind_hi - ind_lo)/2;
332 if( (x >= arr[ind_mid]) == ascend)
333 {
334 ind_lo = ind_mid;
335 }
336 else
337 {
338 ind_hi = ind_mid;
339 }
340 }
341
342 if(x == arr[n-1]) ind_lo = n-2;
343 if(x == arr[0]) ind_lo = 0;
344 return ind_lo;
345 }
346
347#ifdef USE_PLATO
348 inline int check_plato_database_path(const std::string &path)
349 {
350 std::filesystem::path thermo_db_path(path);
351
352 if (!std::filesystem::exists(thermo_db_path))
353 {
354 std::cerr << "Plato database path does not exist: " << path << std::endl;
355 return 1;
356 }
357
358 if (!std::filesystem::is_directory(thermo_db_path))
359 {
360 std::cerr << "Plato database path is not a directory: " << path << std::endl;
361 return 1;
362 }
363 std::filesystem::path mix_path(path+"/mixture");
364 std::filesystem::path thermo_path(path+"/thermo");
365 if(!std::filesystem::is_directory(mix_path) || !std::filesystem::is_directory(thermo_path))
366 {
367 std::cerr << "Plato database missing mixture or thermo database." << std::endl;
368 return 1;
369 }
370
371 return 0;
372 }
373#endif
374 }
375}
MFEM_HOST_DEVICE mfem::real_t Dot(const int dim, const mfem::real_t *vec1, const mfem::real_t *vec2)
Definition theseus_kernels.hpp:82
void log_grid(int N, mfem::real_t min, mfem::real_t max, mfem::Vector &grid)
Definition LTETable.hpp:95
void uniform_grid(int N, mfem::real_t min, mfem::real_t max, mfem::Vector &grid)
Definition LTETable.hpp:85
void fill_table(const LTETable::Layout &L, const mfem::real_t *rho_grid, const mfem::real_t *T_grid, mfem::real_t *lte_table, mfem::real_t &e_min, mfem::real_t &e_max)
Definition LTETable.hpp:105
MFEM_HOST_DEVICE int hunt(const mfem::real_t *arr, int n, mfem::real_t x, int ind_lo)
Definition LTETable.hpp:272
void fill_inv_table(const LTETable::Layout &L, const mfem::real_t *rho_grid, const mfem::real_t *e_grid, const mfem::real_t *T_grid, mfem::real_t *inv_table)
Definition LTETable.hpp:216
Definition AxisymmetricGeometry.hpp:15
Definition LTETable.hpp:57
mfem::Vector inv_table
Definition LTETable.hpp:59
mfem::Vector e_grid
Definition LTETable.hpp:62
mfem::Vector lte_table
Definition LTETable.hpp:58
mfem::Vector T_grid
Definition LTETable.hpp:61
mfem::Vector rho_grid
Definition LTETable.hpp:60
Definition LTETable.hpp:75
MFEM_HOST_DEVICE LTETables()=default
LTETables(int nx_, int ny_=0)
Definition LTETable.hpp:78
LTETable::View tables
Definition LTETable.hpp:82
LTETable::Layout L
Definition LTETable.hpp:81
Definition LTETable.hpp:22
int cv_idx
Definition LTETable.hpp:30
int lambda_idx
Definition LTETable.hpp:36
int ny
Definition LTETable.hpp:24
int num_properties
Definition LTETable.hpp:25
int R_eq_idx
Definition LTETable.hpp:32
int cp_idx
Definition LTETable.hpp:31
int e_idx
Definition LTETable.hpp:29
void setup(int nx_, int ny_)
Definition LTETable.hpp:38
int nx
Definition LTETable.hpp:24
MFEM_HOST_DEVICE int property_index(int property, int ind_x, int ind_y) const
Definition LTETable.hpp:45
int P_idx
Definition LTETable.hpp:28
int c_idx
Definition LTETable.hpp:34
int gamma_eq_idx
Definition LTETable.hpp:33
int mu_idx
Definition LTETable.hpp:35
Definition LTETable.hpp:66
const mfem::real_t * T_grid
Definition LTETable.hpp:70
const mfem::real_t * inv_table
Definition LTETable.hpp:68
const mfem::real_t * rho_grid
Definition LTETable.hpp:69
const mfem::real_t * e_grid
Definition LTETable.hpp:71
const mfem::real_t * lte_table
Definition LTETable.hpp:67