Theseus
Compressible flow solver
Loading...
Searching...
No Matches
ChandrashekarFlux.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 "mfem.hpp"
10#include "theseus_kernels.hpp"
11
12namespace Theseus
13{
14
15 namespace ChandrashekarFlux
16 {
17 // This is Riemann solver that computes the numerical flux for 2 point states
18 // Will be ctx.iflux.ComputeVolumeFlux
19 template<typename GasModelT>
20 MFEM_HOST_DEVICE
21 inline static void ComputeVolumeFluxKernel(const GasModelT &gasModel,
22 const mfem::real_t* q1,
23 const mfem::real_t* q2,
24 const mfem::real_t* met1,
25 const mfem::real_t* met2,
26 mfem::real_t* F_tilde)
27 {
28 const int dim = gasModel.dim();
29 const int neq = gasModel.num_equations();
30
31 // mean metric row
32 mfem::real_t met[3] = {0,0,0};
33 Kernels::ComputeMeanVec(met1, met2, met, dim);
36
37 const mfem::real_t rho1 = gasModel.density(S1);
38 const mfem::real_t rho2 = gasModel.density(S2);
39 const mfem::real_t rho_ln = Kernels::ComputeLogMean(rho1, rho2, 1e-4);
40
41 mfem::real_t mom_hat[3] = {0,0,0};
42 mfem::real_t h_hat = 0;
43 mfem::real_t vn = 0;
44
45 for (int d=0; d<dim; ++d)
46 {
47 const mfem::real_t v1 = gasModel.velocity(S1, d);
48 const mfem::real_t v2 = gasModel.velocity(S2, d);
49 const mfem::real_t vbar = mfem::real_t(0.5)*(v1+v2);
50
51 vn += vbar * met[d];
52
53 mom_hat[d] = rho_ln * vbar;
54
55 h_hat += -mfem::real_t(0.25)*(v1*v1 + v2*v2) + vbar*vbar;
56 }
57
58
59 const mfem::real_t p1 = gasModel.pressure(S1);
60 const mfem::real_t p2 = gasModel.pressure(S2);
61
62 // Single-component ideal-gas-specific KEPEC bits
63 // TODO: Update/Craft KPEC fluxes for mixtures (and passive scalar components)
64 const mfem::real_t beta1 = mfem::real_t(0.5) * rho1 / p1;
65 const mfem::real_t beta2 = mfem::real_t(0.5) * rho2 / p2;
66 const mfem::real_t beta_ln = Kernels::ComputeLogMean(beta1, beta2, 1e-4);
67
68 const mfem::real_t p_hat = mfem::real_t(0.5) * (rho1 + rho2) / (beta1 + beta2);
69
70 const mfem::real_t gm11 = gasModel.gamma(S1);
71 const mfem::real_t gm12 = gasModel.gamma(S2);
72 const mfem::real_t gm1_av_inv = mfem::real_t(2.0) / (gm11 + gm12 - mfem::real_t(2.0));
73
74 h_hat += mfem::real_t(0.5) / beta_ln * gm1_av_inv + p_hat / rho_ln;
75
76 // F_tilde layout: [rho, rhoV, rhoE]
77 // NOTE: Caller *must* zero(or own) F_tilde (size: neq)
78 // NOTE: HRM! Why ZERO? It appears that F_tilde is overwritten below
79 const int mass_eq = gasModel.L.eq_mass;
80 const int mom0_eq = gasModel.L.eq_mom0;
81 const int ener_eq = gasModel.L.eq_energy;
82 F_tilde[mass_eq] = rho_ln * vn;
83 for (int d=0; d<dim; ++d)
84 {
85 F_tilde[mom0_eq + d] = vn * mom_hat[d] + p_hat * met[d];
86 }
87 F_tilde[ener_eq] = rho_ln * vn * h_hat;
88
89 // TODO: Updte for scalars, sigh
90 // for (s=0; s<num_scalars; ++s) F_tilde[XXXX]= XXX
91
92 }
93
94 template<typename GasModelT>
95 MFEM_HOST_DEVICE inline static void ComputeFaceFluxKernel(const GasModelT &gasModel,const mfem::real_t *state1,
96 const mfem::real_t *state2, const mfem::real_t *nor,
97 mfem::real_t *flux)
98 {
99 const int dim = gasModel.dim();
100 const int neq = gasModel.num_equations();
101
102 Theseus::PointStateView S1{state1};
103 Theseus::PointStateView S2{state2};
104
105 const mfem::real_t rho1 = gasModel.density(S1);
106 const mfem::real_t rho2 = gasModel.density(S2);
107 const mfem::real_t rho_mean = 0.5 * (rho1 + rho2);
108 const mfem::real_t rho_ln = Kernels::ComputeLogMean(rho1, rho2, 1e-4);
109 const mfem::real_t drho = rho2 - rho1;
110 mfem::real_t mom[3] = {0.0, 0.0, 0.0};
111 mfem::real_t mom1[3] = {0.0, 0.0, 0.0};
112 mfem::real_t mom2[3] = {0.0, 0.0, 0.0};
113 mfem::real_t hhat = 0.0;
114 mfem::real_t diss = 0.0;
115 mfem::real_t vn = 0.0;
116 mfem::real_t vn1 = 0.0;
117 mfem::real_t vn2 = 0.0;
118 mfem::real_t nor_norm_squared = 0.0;
119
120 for(int idim = 0;idim < dim;idim++){
121 mom1[idim] = gasModel.momentum(S1, idim);
122 mom2[idim] = gasModel.momentum(S2, idim);
123 const mfem::real_t v1 = mom1[idim]/rho1;
124 const mfem::real_t v2 = mom2[idim]/rho2;
125 const mfem::real_t vbar = 0.5 * (v1 + v2);
126 const mfem::real_t dv = v2 - v1;
127 vn += vbar * nor[idim];
128 vn1 += v1 * nor[idim];
129 vn2 += v2 * nor[idim];
130 nor_norm_squared += nor[idim] * nor[idim];
131 mom[idim] = rho_ln * vbar;
132 hhat += -0.25 * (v1*v1 + v2*v2) + vbar * vbar;
133 diss += 0.5 * drho * v1*v2 + rho_mean * dv * vbar;
134 }
135 const mfem::real_t p1 = gasModel.pressure(S1);
136 const mfem::real_t p2 = gasModel.pressure(S2);
137
138 const mfem::real_t nor_norm = Kernels::rsqrt(nor_norm_squared);
139 const mfem::real_t lambda_max = Kernels::rmax(
140 Kernels::rabs(vn1) + gasModel.sound_speed(S1) * nor_norm,
141 Kernels::rabs(vn2) + gasModel.sound_speed(S2) * nor_norm);
142
143 const mfem::real_t beta1 = 0.5 * rho1 / p1;
144 const mfem::real_t beta2 = 0.5 * rho2 / p2;
145 const mfem::real_t beta_ln = Kernels::ComputeLogMean(beta1, beta2, 1e-4);
146
147 const mfem::real_t p_hat = 0.5 * (rho1 + rho2) / (beta1 + beta2);
148
149 // Use the average gamma for now
150 // TODO: Craft KEPEC fluxes for LTE/NLTE
151 const mfem::real_t gm11 = gasModel.gamma(S1);
152 const mfem::real_t gm12 = gasModel.gamma(S2);
153 const mfem::real_t gm1_av_inv = 2.0/(gm11 + gm12 - 2.0);
154
155 hhat += 0.5 / beta_ln * gm1_av_inv + p_hat / rho_ln;
156 diss += 0.5 * drho * gm1_av_inv / beta_ln + 0.5 * rho_mean * gm1_av_inv * (1.0 / beta2 - 1.0 / beta1);
157 const int mass_eq = gasModel.L.eq_mass;
158 const int mom0_eq = gasModel.L.eq_mom0;
159 const int ener_eq = gasModel.L.eq_energy;
160
161 flux[mass_eq] = rho_ln * vn - 0.5 * lambda_max * (rho2 - rho1);
162 for (int d = 0; d < dim; d++)
163 {
164 flux[mom0_eq + d] = vn * mom[d] + p_hat * nor[d]
165 - 0.5 * lambda_max * (mom2[d]-mom1[d]);
166 }
167 flux[ener_eq] = rho_ln * vn * hhat - 0.5 * lambda_max * diss;
168
169 }
171
172 template<typename GasModelT>
173 MFEM_HOST_DEVICE inline void ComputeVolumeFlux(const GasModelT &gasModel,
174 const mfem::real_t *q1, const mfem::real_t *q2,
175 const mfem::real_t *met1, const mfem::real_t *met2,
176 mfem::real_t *F_tilde) const{
177 ComputeVolumeFluxKernel(gasModel, q1, q2, met1, met2, F_tilde);
178 }
179
180 template<typename GasModelT>
181 MFEM_HOST_DEVICE inline void ComputeFaceFlux(const GasModelT &gasModel,const mfem::real_t *qminus,
182 const mfem::real_t *qplus, const mfem::real_t *nor,
183 mfem::real_t *flux) const {
184 ComputeFaceFluxKernel(gasModel, qminus, qplus, nor, flux);
185 }
186 };
187 };
188}
MFEM_HOST_DEVICE void ComputeMeanVec(const mfem::real_t *a, const mfem::real_t *b, mfem::real_t *out, int n)
Definition theseus_kernels.hpp:101
MFEM_HOST_DEVICE mfem::real_t rsqrt(mfem::real_t x)
Definition theseus_kernels.hpp:19
MFEM_HOST_DEVICE mfem::real_t ComputeLogMean(mfem::real_t x, mfem::real_t y, mfem::real_t eps)
Definition theseus_kernels.hpp:107
MFEM_HOST_DEVICE mfem::real_t rmax(mfem::real_t a, mfem::real_t b)
Definition theseus_kernels.hpp:17
MFEM_HOST_DEVICE mfem::real_t rabs(mfem::real_t x)
Definition theseus_kernels.hpp:22
Definition AxisymmetricGeometry.hpp:15
Definition ChandrashekarFlux.hpp:170
MFEM_HOST_DEVICE void ComputeFaceFlux(const GasModelT &gasModel, const mfem::real_t *qminus, const mfem::real_t *qplus, const mfem::real_t *nor, mfem::real_t *flux) const
Definition ChandrashekarFlux.hpp:181
MFEM_HOST_DEVICE void ComputeVolumeFlux(const GasModelT &gasModel, const mfem::real_t *q1, const mfem::real_t *q2, const mfem::real_t *met1, const mfem::real_t *met2, mfem::real_t *F_tilde) const
Definition ChandrashekarFlux.hpp:173
Definition GasState.hpp:127