xref: /honee/qfunctions/newtonian.h (revision 8fd7270942c84117f8b6855dfa7afdd538199702)
1ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2ae2b091fSJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
33a8779fbSJames Wright 
43a8779fbSJames Wright /// @file
5ea615d4cSJames Wright /// Newtonian fluids operator for HONEE
63e17a7a1SJames Wright #include <ceed/types.h>
72b916ea7SJeremy L Thompson 
8475b2820SJames Wright #include "newtonian_state.h"
9d0cce58aSJeremy L Thompson #include "newtonian_types.h"
10d1b9ef12SLeila Ghaffari #include "stabilization.h"
11d0cce58aSJeremy L Thompson #include "utils.h"
12bb8a0c61SJames Wright 
13bb8a0c61SJames Wright // *****************************************************************************
143a8779fbSJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems
153a8779fbSJames Wright // *****************************************************************************
168fff8293SJames Wright CEED_QFUNCTION_HELPER int ICsNewtonianIG(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) {
173a8779fbSJames Wright   CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
183a8779fbSJames Wright 
19bb8a0c61SJames Wright   const SetupContext context = (SetupContext)ctx;
20bb8a0c61SJames Wright 
212b916ea7SJeremy L Thompson   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
22a541e550SJames Wright     CeedScalar q[5];
23edcfef1bSKenneth E. Jansen     State      s = StateFromPrimitive(&context->gas, context->reference);
248fff8293SJames Wright     StateToQ(&context->gas, s, q, state_var);
252b916ea7SJeremy L Thompson     for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j];
26b193fadcSJames Wright   }
273a8779fbSJames Wright   return 0;
283a8779fbSJames Wright }
293a8779fbSJames Wright 
309b103f75SJames Wright CEED_QFUNCTION(ICsNewtonianIG_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
319b103f75SJames Wright   return ICsNewtonianIG(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
329b103f75SJames Wright }
339b103f75SJames Wright 
342b916ea7SJeremy L Thompson CEED_QFUNCTION(ICsNewtonianIG_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
358fff8293SJames Wright   return ICsNewtonianIG(ctx, Q, in, out, STATEVAR_PRIMITIVE);
36b8fb7609SAdeleke O. Bankole }
379b103f75SJames Wright 
389b103f75SJames Wright CEED_QFUNCTION(ICsNewtonianIG_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
399b103f75SJames Wright   return ICsNewtonianIG(ctx, Q, in, out, STATEVAR_ENTROPY);
40cbe60e31SLeila Ghaffari }
41cbe60e31SLeila Ghaffari 
4297cfd714SJames Wright CEED_QFUNCTION_HELPER int MassFunction_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) {
4365dee3d2SJames Wright   const CeedScalar(*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
4465dee3d2SJames Wright   const CeedScalar(*q)[CEED_Q_VLA]     = (const CeedScalar(*)[CEED_Q_VLA])in[1];
4565dee3d2SJames Wright   const CeedScalar(*q_data)            = in[2];
4665dee3d2SJames Wright   CeedScalar(*v)[CEED_Q_VLA]           = (CeedScalar(*)[CEED_Q_VLA])out[0];
4765dee3d2SJames Wright   CeedScalar(*Grad_v)[5][CEED_Q_VLA]   = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
4865dee3d2SJames Wright 
4965dee3d2SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
5065dee3d2SJames Wright 
5165dee3d2SJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
5265dee3d2SJames Wright     const CeedScalar qi[5]     = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
5365dee3d2SJames Wright     const CeedScalar qi_dot[5] = {q_dot[0][i], q_dot[1][i], q_dot[2][i], q_dot[3][i], q_dot[4][i]};
5465dee3d2SJames Wright     const State      s         = StateFromQ(context, qi, state_var);
5565dee3d2SJames Wright     const State      s_dot     = StateFromQ(context, qi_dot, state_var);
5665dee3d2SJames Wright     CeedScalar       wdetJ, dXdx[3][3];
5765dee3d2SJames Wright     QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx);
5865dee3d2SJames Wright 
5965dee3d2SJames Wright     // Standard mass matrix term
6065dee3d2SJames Wright     for (CeedInt f = 0; f < 5; f++) {
6165dee3d2SJames Wright       v[f][i] = wdetJ * qi_dot[f];
6265dee3d2SJames Wright     }
6365dee3d2SJames Wright 
6465dee3d2SJames Wright     // Stabilization method: none (Galerkin), SU, or SUPG
6565dee3d2SJames Wright     State      grad_s[3] = {{{0.}}};
668c85b835SJames Wright     CeedScalar Tau_d[3], stab[5][3], body_force[5] = {0.}, divFdiff[5] = {0.}, U_dot[5];
6765dee3d2SJames Wright     UnpackState_U(s_dot.U, U_dot);
6865dee3d2SJames Wright     Tau_diagPrim(context, s, dXdx, context->dt, Tau_d);
698c85b835SJames Wright     Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, divFdiff, stab);
7065dee3d2SJames Wright 
7165dee3d2SJames Wright     // Stabilized mass term
7265dee3d2SJames Wright     for (CeedInt j = 0; j < 5; j++) {
7365dee3d2SJames Wright       for (CeedInt k = 0; k < 3; k++) {
7465dee3d2SJames Wright         Grad_v[k][j][i] = wdetJ * (stab[j][0] * dXdx[k][0] + stab[j][1] * dXdx[k][1] + stab[j][2] * dXdx[k][2]);
7565dee3d2SJames Wright       }
7665dee3d2SJames Wright     }
7765dee3d2SJames Wright   }
7897cfd714SJames Wright   return 0;
7965dee3d2SJames Wright }
8065dee3d2SJames Wright 
8165dee3d2SJames Wright CEED_QFUNCTION(MassFunction_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
8297cfd714SJames Wright   return MassFunction_Newtonian(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
8365dee3d2SJames Wright }
8465dee3d2SJames Wright 
85e57b52dbSJames Wright // @brief Computes the residual created by IDL
8630b5892fSJames Wright CEED_QFUNCTION_HELPER void InternalDampingLayer_Residual(const NewtonianIdealGasContext context, const State s, const CeedScalar sigma,
8730b5892fSJames Wright                                                          CeedScalar damp_Y[5], CeedScalar damp_residual[5]) {
8830b5892fSJames Wright   ScaleN(damp_Y, sigma, 5);
8930b5892fSJames Wright   State damp_s = StateFromY_fwd(context, s, damp_Y);
9030b5892fSJames Wright 
9130b5892fSJames Wright   CeedScalar U[5];
9230b5892fSJames Wright   UnpackState_U(damp_s.U, U);
9330b5892fSJames Wright   for (int i = 0; i < 5; i++) damp_residual[i] += U[i];
9430b5892fSJames Wright }
9530b5892fSJames Wright 
96e57b52dbSJames Wright /**
97e57b52dbSJames Wright   @brief IFunction integrand for Internal Damping Layer
98e57b52dbSJames Wright 
99e57b52dbSJames Wright   `location` refers to whatever scalar distance is desired for IDL to ramp from.
100e57b52dbSJames Wright   See `LinearRampCoefficient()` for details on the `amplitude`, `length`, `start`, and `location` arguments.
101e57b52dbSJames Wright 
102e57b52dbSJames Wright   @param[in]    s         Solution `State`
103e57b52dbSJames Wright   @param[in]    context   Newtonian context
104e57b52dbSJames Wright   @param[in]    amplitude Amplitude of the IDL ramp
105e57b52dbSJames Wright   @param[in]    length    Length of the IDL ramp
106e57b52dbSJames Wright   @param[in]    start     Start of the IDL ramp
107e57b52dbSJames Wright   @param[in]    location  Quadrature point location (relative to IDL ramp specification)
108e57b52dbSJames Wright   @param[in]    pressure  Pressure used to damp to
109e57b52dbSJames Wright   @param[inout] v_i       Output to be multiplied by weight function, summed into
110e57b52dbSJames Wright   @param[out]   sigma     IDL ramp coefficient
111e57b52dbSJames Wright **/
11230b5892fSJames Wright CEED_QFUNCTION_HELPER void InternalDampingLayer_IFunction_Integrand(const State s, const NewtonianIdealGasContext context, CeedScalar amplitude,
11330b5892fSJames Wright                                                                     CeedScalar length, CeedScalar start, CeedScalar location, CeedScalar pressure,
11430b5892fSJames Wright                                                                     CeedScalar v_i[5], CeedScalar *sigma) {
11530b5892fSJames Wright   const CeedScalar sigma_        = LinearRampCoefficient(amplitude, length, start, location);
11630b5892fSJames Wright   CeedScalar       damp_state[5] = {s.Y.pressure - pressure, 0, 0, 0, 0}, idl_residual[5] = {0.};
11730b5892fSJames Wright   InternalDampingLayer_Residual(context, s, sigma_, damp_state, idl_residual);
11830b5892fSJames Wright   AXPY(1, idl_residual, v_i, 5);
11930b5892fSJames Wright   *sigma = sigma_;
12030b5892fSJames Wright }
12130b5892fSJames Wright 
122*8fd72709SJames Wright /**
123*8fd72709SJames Wright   @brief IJacobian integrand for Internal Damping Layer
124*8fd72709SJames Wright 
125*8fd72709SJames Wright   @note This uses a Picard-type linearization of the damping and could be replaced by an `InternalDampingLayer_fwd` that uses s and ds.
126*8fd72709SJames Wright 
127*8fd72709SJames Wright   @param[in]    s         Solution `State`
128*8fd72709SJames Wright   @param[in]    ds        Change in `State` of solution
129*8fd72709SJames Wright   @param[in]    context   Newtonian context
130*8fd72709SJames Wright   @param[in]    sigma     IDL ramp coefficient
131*8fd72709SJames Wright   @param[inout] v_i       Output to be multiplied by weight function, summed into
132*8fd72709SJames Wright **/
133*8fd72709SJames Wright CEED_QFUNCTION_HELPER void InternalDampingLayer_IJacobian_Integrand(const State s, const State ds, const NewtonianIdealGasContext context,
134*8fd72709SJames Wright                                                                     CeedScalar sigma, CeedScalar v_i[5]) {
135*8fd72709SJames Wright   CeedScalar damp_state[5] = {ds.Y.pressure, 0, 0, 0, 0}, idl_residual[5] = {0.};
136*8fd72709SJames Wright   InternalDampingLayer_Residual(context, s, sigma, damp_state, idl_residual);
137*8fd72709SJames Wright   AXPY(1, idl_residual, v_i, 5);
138*8fd72709SJames Wright }
139*8fd72709SJames Wright 
140cbe60e31SLeila Ghaffari // *****************************************************************************
14104e40bb6SJeremy L Thompson // This QFunction implements the following formulation of Navier-Stokes with explicit time stepping method
1423a8779fbSJames Wright //
14304e40bb6SJeremy L Thompson // This is 3D compressible Navier-Stokes in conservation form with state variables of density, momentum density, and total energy density.
1443a8779fbSJames Wright //
1453a8779fbSJames Wright // State Variables: q = ( rho, U1, U2, U3, E )
1463a8779fbSJames Wright //   rho - Mass Density
1473a8779fbSJames Wright //   Ui  - Momentum Density,      Ui = rho ui
1483a8779fbSJames Wright //   E   - Total Energy Density,  E  = rho (cv T + (u u)/2 + g z)
1493a8779fbSJames Wright //
1503a8779fbSJames Wright // Navier-Stokes Equations:
1513a8779fbSJames Wright //   drho/dt + div( U )                               = 0
1523a8779fbSJames Wright //   dU/dt   + div( rho (u x u) + P I3 ) + rho g khat = div( Fu )
1533a8779fbSJames Wright //   dE/dt   + div( (E + P) u )                       = div( Fe )
1543a8779fbSJames Wright //
1553a8779fbSJames Wright // Viscous Stress:
1563a8779fbSJames Wright //   Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3)
1573a8779fbSJames Wright //
1583a8779fbSJames Wright // Thermal Stress:
1593a8779fbSJames Wright //   Fe = u Fu + k grad( T )
160bb8a0c61SJames Wright // Equation of State
1613a8779fbSJames Wright //   P = (gamma - 1) (E - rho (u u) / 2 - rho g z)
1623a8779fbSJames Wright //
1633a8779fbSJames Wright // Stabilization:
1643a8779fbSJames Wright //   Tau = diag(TauC, TauM, TauM, TauM, TauE)
1653a8779fbSJames Wright //     f1 = rho  sqrt(ui uj gij)
1663a8779fbSJames Wright //     gij = dXi/dX * dXi/dX
1673a8779fbSJames Wright //     TauC = Cc f1 / (8 gii)
1683a8779fbSJames Wright //     TauM = min( 1 , 1 / f1 )
1693a8779fbSJames Wright //     TauE = TauM / (Ce cv)
1703a8779fbSJames Wright //
1713a8779fbSJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
1723a8779fbSJames Wright //
1733a8779fbSJames Wright // Constants:
1743a8779fbSJames Wright //   lambda = - 2 / 3,  From Stokes hypothesis
1753a8779fbSJames Wright //   mu              ,  Dynamic viscosity
1763a8779fbSJames Wright //   k               ,  Thermal conductivity
1773a8779fbSJames Wright //   cv              ,  Specific heat, constant volume
1783a8779fbSJames Wright //   cp              ,  Specific heat, constant pressure
1793a8779fbSJames Wright //   g               ,  Gravity
1803a8779fbSJames Wright //   gamma  = cp / cv,  Specific heat ratio
1813a8779fbSJames Wright //
18204e40bb6SJeremy L Thompson // We require the product of the inverse of the Jacobian (dXdx_j,k) and its transpose (dXdx_k,j) to properly compute integrals of the form: int( gradv
18304e40bb6SJeremy L Thompson // gradu )
1843a8779fbSJames Wright // *****************************************************************************
1852b916ea7SJeremy L Thompson CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
186b3b24828SJames Wright   NewtonianIdealGasContext context      = (NewtonianIdealGasContext)ctx;
187b3b24828SJames Wright   const bool               use_divFdiff = context->divFdiff_method != DIV_DIFF_FLUX_PROJ_NONE;
188b3b24828SJames Wright 
1893d65b166SJames Wright   const CeedScalar(*q)[CEED_Q_VLA]        = (const CeedScalar(*)[CEED_Q_VLA])in[0];
19087bd45e7SJames Wright   const CeedScalar(*Grad_q)               = in[1];
191ade49511SJames Wright   const CeedScalar(*q_data)               = in[2];
1920a32a5aaSJames Wright   const CeedScalar(*x)[CEED_Q_VLA]        = (const CeedScalar(*)[CEED_Q_VLA])in[3];
193b3b24828SJames Wright   const CeedScalar(*divFdiff)[CEED_Q_VLA] = use_divFdiff ? (const CeedScalar(*)[CEED_Q_VLA])in[4] : NULL;
1943d65b166SJames Wright   CeedScalar(*v)[CEED_Q_VLA]              = (CeedScalar(*)[CEED_Q_VLA])out[0];
1953d65b166SJames Wright   CeedScalar(*Grad_v)[5][CEED_Q_VLA]      = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
1963a8779fbSJames Wright 
197bb8a0c61SJames Wright   const CeedScalar *g            = context->g;
198bb8a0c61SJames Wright   const CeedScalar  dt           = context->dt;
199b3b24828SJames Wright   const CeedScalar  idl_pressure = context->idl_pressure;
2003a8779fbSJames Wright 
2013d65b166SJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
202ade49511SJames Wright     CeedScalar       U[5], wdetJ, dXdx[3][3];
2030a32a5aaSJames Wright     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
204c1a52365SJed Brown     for (int j = 0; j < 5; j++) U[j] = q[j][i];
2051be49596SJames Wright     QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx);
206edcfef1bSKenneth E. Jansen     State s = StateFromU(context, U);
207c1a52365SJed Brown 
208c1a52365SJed Brown     State grad_s[3];
209edcfef1bSKenneth E. Jansen     StatePhysicalGradientFromReference(Q, i, context, s, STATEVAR_CONSERVATIVE, Grad_q, dXdx, grad_s);
210c1a52365SJed Brown 
211c1a52365SJed Brown     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
21240a33f2dSJames Wright     KMStrainRate_State(grad_s, strain_rate);
213c1a52365SJed Brown     NewtonianStress(context, strain_rate, kmstress);
214c1a52365SJed Brown     KMUnpack(kmstress, stress);
215c1a52365SJed Brown     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
216c1a52365SJed Brown 
217c1a52365SJed Brown     StateConservative F_inviscid[3];
218c1a52365SJed Brown     FluxInviscid(context, s, F_inviscid);
219c1a52365SJed Brown 
220c1a52365SJed Brown     // Total flux
221c1a52365SJed Brown     CeedScalar Flux[5][3];
222d1b9ef12SLeila Ghaffari     FluxTotal(F_inviscid, stress, Fe, Flux);
223c1a52365SJed Brown 
2247523f6aaSJames Wright     for (CeedInt j = 0; j < 5; j++) {
2257523f6aaSJames Wright       for (CeedInt k = 0; k < 3; k++) Grad_v[k][j][i] = wdetJ * (dXdx[k][0] * Flux[j][0] + dXdx[k][1] * Flux[j][1] + dXdx[k][2] * Flux[j][2]);
2262b916ea7SJeremy L Thompson     }
227c1a52365SJed Brown 
22860dbb574SKenneth E. Jansen     const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], Dot3(s.U.momentum, g)};
2292b916ea7SJeremy L Thompson     for (int j = 0; j < 5; j++) v[j][i] = wdetJ * body_force[j];
2303a8779fbSJames Wright 
2310a32a5aaSJames Wright     if (context->idl_enable) {
2320a32a5aaSJames Wright       const CeedScalar sigma         = LinearRampCoefficient(context->idl_amplitude, context->idl_length, context->idl_start, x_i[0]);
233b3b24828SJames Wright       CeedScalar       damp_state[5] = {s.Y.pressure - idl_pressure, 0, 0, 0, 0}, idl_residual[5] = {0.};
23430b5892fSJames Wright       InternalDampingLayer_Residual(context, s, sigma, damp_state, idl_residual);
2350a32a5aaSJames Wright       for (int j = 0; j < 5; j++) v[j][i] -= wdetJ * idl_residual[j];
2360a32a5aaSJames Wright     }
2370a32a5aaSJames Wright 
238b3b24828SJames Wright     CeedScalar divFdiff_i[5] = {0.};
239b3b24828SJames Wright     if (use_divFdiff)
240b3b24828SJames Wright       for (int j = 1; j < 5; j++) divFdiff_i[j] = divFdiff[j - 1][i];
241b3b24828SJames Wright 
242d1b9ef12SLeila Ghaffari     // -- Stabilization method: none (Galerkin), SU, or SUPG
243b3b24828SJames Wright     CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0};
244d1b9ef12SLeila Ghaffari     Tau_diagPrim(context, s, dXdx, dt, Tau_d);
245b3b24828SJames Wright     Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, divFdiff_i, stab);
2463a8779fbSJames Wright 
2472b916ea7SJeremy L Thompson     for (CeedInt j = 0; j < 5; j++) {
2482b916ea7SJeremy L Thompson       for (CeedInt k = 0; k < 3; k++) Grad_v[k][j][i] -= wdetJ * (stab[j][0] * dXdx[k][0] + stab[j][1] * dXdx[k][1] + stab[j][2] * dXdx[k][2]);
2492b916ea7SJeremy L Thompson     }
250b193fadcSJames Wright   }
2513a8779fbSJames Wright   return 0;
2523a8779fbSJames Wright }
2533a8779fbSJames Wright 
254e57b52dbSJames Wright /**
255e57b52dbSJames Wright   @brief IFunction integrand of Navier-Stokes for Newtonian ideal gas
256e57b52dbSJames Wright 
257e57b52dbSJames Wright   This is used in the quadrature point loop within a larger QFunction.
258e57b52dbSJames Wright   `v_i` and `dv_i` are summed into (meaning they must be some initialized value).
259e57b52dbSJames Wright   `kmstress` and `Tau_d` are given to be included as Jacobian data.
260e57b52dbSJames Wright 
261e57b52dbSJames Wright   @param[in]    s          `State` of solution
262e57b52dbSJames Wright   @param[in]    grad_s     Physical gradient of solution
263e57b52dbSJames Wright   @param[in]    s_dot      Time derivative of solution
264e57b52dbSJames Wright   @param[in]    divFdiff_i Divergence of diffusive flux
265e57b52dbSJames Wright   @param[in]    x_i        Coordinate location of quadrature point
266e57b52dbSJames Wright   @param[in]    context    Newtonian context
267e57b52dbSJames Wright   @param[in]    dXdx       Inverse of element mapping Jacobian (d\xi / dx)
268e57b52dbSJames Wright   @param[inout] v_i        Output to be multiplied by weight function, summed into
269e57b52dbSJames Wright   @param[inout] grad_v_i   Output to be multiplied by gradient of weight function, summed into
270e57b52dbSJames Wright   @param[out]   kmstress   Viscous stress, in Kelvin-Mandel ordering
271e57b52dbSJames Wright   @param[out]   Tau_d      Diagonal Tau coefficients
272e57b52dbSJames Wright **/
27330b5892fSJames Wright CEED_QFUNCTION_HELPER void IFunction_Newtonian_Integrand(const State s, const State grad_s[3], const State s_dot, const CeedScalar divFdiff_i[5],
27430b5892fSJames Wright                                                          const CeedScalar x_i[3], const NewtonianIdealGasContext context, const CeedScalar dXdx[3][3],
275e57b52dbSJames Wright                                                          CeedScalar v_i[5], CeedScalar grad_v_i[5][3], CeedScalar kmstress[6], CeedScalar Tau_d[3]) {
276e57b52dbSJames Wright   CeedScalar        strain_rate[6], stress[3][3], F_visc_energy[3], F_total[5][3];
277e57b52dbSJames Wright   StateConservative F_inviscid[3];
278e57b52dbSJames Wright   const CeedScalar *g = context->g, dt = context->dt;
27930b5892fSJames Wright 
280e57b52dbSJames Wright   // Advective and viscous fluxes
28130b5892fSJames Wright   KMStrainRate_State(grad_s, strain_rate);
28230b5892fSJames Wright   NewtonianStress(context, strain_rate, kmstress);
28330b5892fSJames Wright   KMUnpack(kmstress, stress);
284e57b52dbSJames Wright   ViscousEnergyFlux(context, s.Y, grad_s, stress, F_visc_energy);
28530b5892fSJames Wright   FluxInviscid(context, s, F_inviscid);
286e57b52dbSJames Wright   FluxTotal(F_inviscid, stress, F_visc_energy, F_total);
287e57b52dbSJames Wright   AXPY(-1, (CeedScalar *)F_total, (CeedScalar *)grad_v_i, 15);
28830b5892fSJames Wright 
289e57b52dbSJames Wright   // Body force and time derivative
29030b5892fSJames Wright   const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], Dot3(s.U.momentum, g)};
291e57b52dbSJames Wright   CeedScalar       U_dot[5];
29230b5892fSJames Wright   UnpackState_U(s_dot.U, U_dot);
29330b5892fSJames Wright   for (CeedInt j = 0; j < 5; j++) v_i[j] += U_dot[j] - body_force[j];
294e57b52dbSJames Wright 
295e57b52dbSJames Wright   // Stabilization
296e57b52dbSJames Wright   CeedScalar stab[5][3];
29730b5892fSJames Wright   Tau_diagPrim(context, s, dXdx, dt, Tau_d);
29830b5892fSJames Wright   Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, divFdiff_i, stab);
299e57b52dbSJames Wright   AXPY(1, (CeedScalar *)stab, (CeedScalar *)grad_v_i, 15);
30030b5892fSJames Wright }
30130b5892fSJames Wright 
302e57b52dbSJames Wright // @brief State-independent IFunction of Navier-Stokes for Newtonian ideal gas
3038fff8293SJames Wright CEED_QFUNCTION_HELPER int IFunction_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) {
3048c85b835SJames Wright   NewtonianIdealGasContext context      = (NewtonianIdealGasContext)ctx;
305ff684e42SJames Wright   const bool               use_divFdiff = context->divFdiff_method != DIV_DIFF_FLUX_PROJ_NONE;
3068c85b835SJames Wright 
3073d65b166SJames Wright   const CeedScalar(*q)[CEED_Q_VLA]        = (const CeedScalar(*)[CEED_Q_VLA])in[0];
308e57b52dbSJames Wright   const CeedScalar(*grad_q)               = in[1];
3093d65b166SJames Wright   const CeedScalar(*q_dot)[CEED_Q_VLA]    = (const CeedScalar(*)[CEED_Q_VLA])in[2];
310ade49511SJames Wright   const CeedScalar(*q_data)               = in[3];
3113d65b166SJames Wright   const CeedScalar(*x)[CEED_Q_VLA]        = (const CeedScalar(*)[CEED_Q_VLA])in[4];
312ff684e42SJames Wright   const CeedScalar(*divFdiff)[CEED_Q_VLA] = use_divFdiff ? (const CeedScalar(*)[CEED_Q_VLA])in[5] : NULL;
3133d65b166SJames Wright   CeedScalar(*v)[CEED_Q_VLA]              = (CeedScalar(*)[CEED_Q_VLA])out[0];
314e57b52dbSJames Wright   CeedScalar(*grad_v)[5][CEED_Q_VLA]      = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
315ade49511SJames Wright   CeedScalar(*jac_data)                   = out[2];
3163d65b166SJames Wright 
3173d65b166SJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
318e57b52dbSJames Wright     const CeedScalar q_i[5]     = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
319e57b52dbSJames Wright     const CeedScalar q_i_dot[5] = {q_dot[0][i], q_dot[1][i], q_dot[2][i], q_dot[3][i], q_dot[4][i]};
320c1a52365SJed Brown     const CeedScalar x_i[3]     = {x[0][i], x[1][i], x[2][i]};
321e57b52dbSJames Wright     const State      s          = StateFromQ(context, q_i, state_var);
322e57b52dbSJames Wright     const State      s_dot      = StateFromQ_fwd(context, s, q_i_dot, state_var);
323c1a52365SJed Brown 
324ade49511SJames Wright     CeedScalar wdetJ, dXdx[3][3];
325ade49511SJames Wright     QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx);
326c1a52365SJed Brown     State grad_s[3];
327e57b52dbSJames Wright     StatePhysicalGradientFromReference(Q, i, context, s, state_var, grad_q, dXdx, grad_s);
3288c85b835SJames Wright     CeedScalar divFdiff_i[5] = {0.};
32930b5892fSJames Wright     if (use_divFdiff)
3308c85b835SJames Wright       for (int j = 1; j < 5; j++) divFdiff_i[j] = divFdiff[j - 1][i];
3313a8779fbSJames Wright 
332e57b52dbSJames Wright     CeedScalar v_i[5] = {0.}, grad_v_i[5][3] = {{0.}}, kmstress[6], Tau_d[3], sigma;
333e57b52dbSJames Wright     IFunction_Newtonian_Integrand(s, grad_s, s_dot, divFdiff_i, x_i, context, dXdx, v_i, grad_v_i, kmstress, Tau_d);
33430b5892fSJames Wright     if (context->idl_enable)
33530b5892fSJames Wright       InternalDampingLayer_IFunction_Integrand(s, context, context->idl_amplitude, context->idl_length, context->idl_start, x_i[0],
33630b5892fSJames Wright                                                context->idl_pressure, v_i, &sigma);
33730b5892fSJames Wright 
33830b5892fSJames Wright     for (CeedInt j = 0; j < 5; j++) v[j][i] = wdetJ * v_i[j];
3392b916ea7SJeremy L Thompson     for (CeedInt j = 0; j < 5; j++) {
340*8fd72709SJames Wright       for (CeedInt k = 0; k < 3; k++)
341e57b52dbSJames Wright         grad_v[k][j][i] = wdetJ * (grad_v_i[j][0] * dXdx[k][0] + grad_v_i[j][1] * dXdx[k][1] + grad_v_i[j][2] * dXdx[k][2]);
3423d65b166SJames Wright     }
34330b5892fSJames Wright 
344e57b52dbSJames Wright     StoredValuesPack(Q, i, 0, 5, q_i, jac_data);
345ade49511SJames Wright     StoredValuesPack(Q, i, 5, 6, kmstress, jac_data);
346ade49511SJames Wright     StoredValuesPack(Q, i, 11, 3, Tau_d, jac_data);
34730b5892fSJames Wright     if (context->idl_enable) StoredValuesPack(Q, i, 14, 1, &sigma, jac_data);
348b193fadcSJames Wright   }
3493a8779fbSJames Wright   return 0;
3503a8779fbSJames Wright }
351f0b65372SJed Brown 
3522b916ea7SJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
3538fff8293SJames Wright   return IFunction_Newtonian(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
35476555becSJames Wright }
35576555becSJames Wright 
3562b916ea7SJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
3578fff8293SJames Wright   return IFunction_Newtonian(ctx, Q, in, out, STATEVAR_PRIMITIVE);
35876555becSJames Wright }
35976555becSJames Wright 
3609b103f75SJames Wright CEED_QFUNCTION(IFunction_Newtonian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
3619b103f75SJames Wright   return IFunction_Newtonian(ctx, Q, in, out, STATEVAR_ENTROPY);
3629b103f75SJames Wright }
3639b103f75SJames Wright 
364*8fd72709SJames Wright /**
365*8fd72709SJames Wright   @brief IJacobian integrand of Navier-Stokes for Newtonian ideal gas
3663d65b166SJames Wright 
367*8fd72709SJames Wright   This is used in the quadrature point loop within a larger QFunction.
368*8fd72709SJames Wright   `v_i` and `dv_i` are summed into (meaning they must be some initialized value).
369*8fd72709SJames Wright   `kmstress` and `Tau_d` are (generally) calculated and stored by the IFunction.
370*8fd72709SJames Wright 
371*8fd72709SJames Wright   @param[in]    s          `State` of solution
372*8fd72709SJames Wright   @param[in]    ds         Change in `State` of solution
373*8fd72709SJames Wright   @param[in]    grad_ds     Physical gradient of change in `State` of solution
374*8fd72709SJames Wright   @param[in]    context    Newtonian context
375*8fd72709SJames Wright   @param[in]    kmstress   Viscous stress, in Kelvin-Mandel ordering
376*8fd72709SJames Wright   @param[in]    Tau_d      Diagonal Tau coefficients
377*8fd72709SJames Wright   @param[inout] v_i        Output to be multiplied by weight function, summed into
378*8fd72709SJames Wright   @param[inout] grad_v_i   Output to be multiplied by gradient of weight function, summed into
379*8fd72709SJames Wright **/
380*8fd72709SJames Wright CEED_QFUNCTION_HELPER void IJacobian_Newtonian_Integrand(const State s, const State ds, const State grad_ds[3],
381*8fd72709SJames Wright                                                          const NewtonianIdealGasContext context, const CeedScalar kmstress[6],
382*8fd72709SJames Wright                                                          const CeedScalar Tau_d[3], CeedScalar v_i[5], CeedScalar grad_v_i[5][3]) {
383f0b65372SJed Brown   const CeedScalar *g = context->g;
384*8fd72709SJames Wright   CeedScalar        dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dF_visc_energy[3], dF_total[5][3];
385*8fd72709SJames Wright   StateConservative dF_inviscid[3];
386f0b65372SJed Brown 
387*8fd72709SJames Wright   // Advective and viscous fluxes
38840a33f2dSJames Wright   KMStrainRate_State(grad_ds, dstrain_rate);
389f0b65372SJed Brown   NewtonianStress(context, dstrain_rate, dkmstress);
390f0b65372SJed Brown   KMUnpack(dkmstress, dstress);
391f0b65372SJed Brown   KMUnpack(kmstress, stress);
392*8fd72709SJames Wright   ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dF_visc_energy);
393f0b65372SJed Brown   FluxInviscid_fwd(context, s, ds, dF_inviscid);
394*8fd72709SJames Wright   FluxTotal(dF_inviscid, dstress, dF_visc_energy, dF_total);
395*8fd72709SJames Wright   AXPY(-1, (CeedScalar *)dF_total, (CeedScalar *)grad_v_i, 15);
396f0b65372SJed Brown 
397*8fd72709SJames Wright   // Body force and time derivative
39860dbb574SKenneth E. Jansen   const CeedScalar dbody_force[5] = {0, ds.U.density * g[0], ds.U.density * g[1], ds.U.density * g[2], Dot3(ds.U.momentum, g)};
399*8fd72709SJames Wright   CeedScalar       dU[5], dU_dot[5];
40076555becSJames Wright   UnpackState_U(ds.U, dU);
401*8fd72709SJames Wright   for (CeedInt j = 0; j < 5; j++) {
402*8fd72709SJames Wright     dU_dot[j] = context->ijacobian_time_shift * dU[j];
403*8fd72709SJames Wright     v_i[j]    = dU_dot[j] - dbody_force[j];
404e7754af5SKenneth E. Jansen   }
405e7754af5SKenneth E. Jansen 
406*8fd72709SJames Wright   // Stabilization
407*8fd72709SJames Wright   CeedScalar       dstab[5][3];
4088c85b835SJames Wright   const CeedScalar zeroFlux[5] = {0.};
409*8fd72709SJames Wright   Stabilization(context, s, Tau_d, grad_ds, dU_dot, dbody_force, zeroFlux, dstab);
410*8fd72709SJames Wright   AXPY(1, (CeedScalar *)dstab, (CeedScalar *)grad_v_i, 15);
411*8fd72709SJames Wright }
412d1b9ef12SLeila Ghaffari 
413*8fd72709SJames Wright // @brief State-independent IJacobian of Navier-Stokes for Newtonian ideal gas
414*8fd72709SJames Wright CEED_QFUNCTION_HELPER int IJacobian_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) {
415*8fd72709SJames Wright   const CeedScalar(*dq)[CEED_Q_VLA]  = (const CeedScalar(*)[CEED_Q_VLA])in[0];
416*8fd72709SJames Wright   const CeedScalar(*grad_dq)         = in[1];
417*8fd72709SJames Wright   const CeedScalar(*q_data)          = in[2];
418*8fd72709SJames Wright   const CeedScalar(*jac_data)        = in[3];
419*8fd72709SJames Wright   CeedScalar(*v)[CEED_Q_VLA]         = (CeedScalar(*)[CEED_Q_VLA])out[0];
420*8fd72709SJames Wright   CeedScalar(*grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
421*8fd72709SJames Wright 
422*8fd72709SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
423*8fd72709SJames Wright 
424*8fd72709SJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
425*8fd72709SJames Wright     const CeedScalar dq_i[5] = {dq[0][i], dq[1][i], dq[2][i], dq[3][i], dq[4][i]};
426*8fd72709SJames Wright     CeedScalar       qi[5], kmstress[6], Tau_d[3];
427*8fd72709SJames Wright     StoredValuesUnpack(Q, i, 0, 5, jac_data, qi);
428*8fd72709SJames Wright     StoredValuesUnpack(Q, i, 5, 6, jac_data, kmstress);
429*8fd72709SJames Wright     StoredValuesUnpack(Q, i, 11, 3, jac_data, Tau_d);
430*8fd72709SJames Wright     const State s  = StateFromQ(context, qi, state_var);
431*8fd72709SJames Wright     const State ds = StateFromQ_fwd(context, s, dq_i, state_var);
432*8fd72709SJames Wright 
433*8fd72709SJames Wright     CeedScalar wdetJ, dXdx[3][3];
434*8fd72709SJames Wright     QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx);
435*8fd72709SJames Wright     State grad_ds[3];
436*8fd72709SJames Wright     StatePhysicalGradientFromReference(Q, i, context, s, state_var, grad_dq, dXdx, grad_ds);
437*8fd72709SJames Wright 
438*8fd72709SJames Wright     CeedScalar v_i[5] = {0.}, grad_v_i[5][3] = {{0.}};
439*8fd72709SJames Wright     IJacobian_Newtonian_Integrand(s, ds, grad_ds, context, kmstress, Tau_d, v_i, grad_v_i);
440*8fd72709SJames Wright     if (context->idl_enable) {
441*8fd72709SJames Wright       CeedScalar sigma;
442*8fd72709SJames Wright       StoredValuesUnpack(Q, i, 14, 1, jac_data, &sigma);
443*8fd72709SJames Wright       InternalDampingLayer_IJacobian_Integrand(s, ds, context, sigma, v_i);
444*8fd72709SJames Wright       for (int j = 0; j < 5; j++) v[j][i] += wdetJ * v_i[j];
445*8fd72709SJames Wright     }
446*8fd72709SJames Wright 
447*8fd72709SJames Wright     for (CeedInt j = 0; j < 5; j++) v[j][i] = wdetJ * v_i[j];
4482b916ea7SJeremy L Thompson     for (int j = 0; j < 5; j++) {
449*8fd72709SJames Wright       for (int k = 0; k < 3; k++) grad_v[k][j][i] = wdetJ * (grad_v_i[j][0] * dXdx[k][0] + grad_v_i[j][1] * dXdx[k][1] + grad_v_i[j][2] * dXdx[k][2]);
4502b916ea7SJeremy L Thompson     }
451b193fadcSJames Wright   }
452f0b65372SJed Brown   return 0;
453f0b65372SJed Brown }
4548085925cSJames Wright 
4552b916ea7SJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
4568fff8293SJames Wright   return IJacobian_Newtonian(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
45776555becSJames Wright }
45876555becSJames Wright 
4592b916ea7SJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
4608fff8293SJames Wright   return IJacobian_Newtonian(ctx, Q, in, out, STATEVAR_PRIMITIVE);
46176555becSJames Wright }
46276555becSJames Wright 
4639b103f75SJames Wright CEED_QFUNCTION(IJacobian_Newtonian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
4649b103f75SJames Wright   return IJacobian_Newtonian(ctx, Q, in, out, STATEVAR_ENTROPY);
4659b103f75SJames Wright }
4669b103f75SJames Wright 
467d1b9ef12SLeila Ghaffari // *****************************************************************************
4688085925cSJames Wright // Compute boundary integral (ie. for strongly set inflows)
469d1b9ef12SLeila Ghaffari // *****************************************************************************
4708fff8293SJames Wright CEED_QFUNCTION_HELPER int BoundaryIntegral(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) {
4714b96a86bSJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
4723d65b166SJames Wright   const CeedScalar(*q)[CEED_Q_VLA]       = (const CeedScalar(*)[CEED_Q_VLA])in[0];
47387bd45e7SJames Wright   const CeedScalar(*Grad_q)              = in[1];
474ade49511SJames Wright   const CeedScalar(*q_data_sur)          = in[2];
4753d65b166SJames Wright   CeedScalar(*v)[CEED_Q_VLA]             = (CeedScalar(*)[CEED_Q_VLA])out[0];
4764b96a86bSJames Wright   CeedScalar(*jac_data_sur)              = context->is_implicit ? out[1] : NULL;
4778085925cSJames Wright 
478d3b25f3aSJames Wright   const bool is_implicit = context->is_implicit;
4798085925cSJames Wright 
4802b916ea7SJeremy L Thompson   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
48141e73928SJames Wright     const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
482edcfef1bSKenneth E. Jansen     State            s     = StateFromQ(context, qi, state_var);
4838085925cSJames Wright 
48478e8b7daSJames Wright     CeedScalar wdetJb, dXdx[2][3], normal[3];
48578e8b7daSJames Wright     QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal);
486ade49511SJames Wright     wdetJb *= is_implicit ? -1. : 1.;
4878085925cSJames Wright 
488d3b25f3aSJames Wright     State grad_s[3];
489edcfef1bSKenneth E. Jansen     StatePhysicalGradientFromReference_Boundary(Q, i, context, s, state_var, Grad_q, dXdx, grad_s);
4908085925cSJames Wright 
491d3b25f3aSJames Wright     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
49240a33f2dSJames Wright     KMStrainRate_State(grad_s, strain_rate);
493d3b25f3aSJames Wright     NewtonianStress(context, strain_rate, kmstress);
494d3b25f3aSJames Wright     KMUnpack(kmstress, stress);
495d3b25f3aSJames Wright     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
496d3b25f3aSJames Wright 
497d3b25f3aSJames Wright     StateConservative F_inviscid[3];
498d3b25f3aSJames Wright     FluxInviscid(context, s, F_inviscid);
499d3b25f3aSJames Wright 
500c5740391SJames Wright     CeedScalar Flux[5];
50178e8b7daSJames Wright     FluxTotal_Boundary(F_inviscid, stress, Fe, normal, Flux);
502d3b25f3aSJames Wright 
503c5740391SJames Wright     for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j];
5048085925cSJames Wright 
5054b96a86bSJames Wright     if (is_implicit) {
506ade49511SJames Wright       StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur);
507ade49511SJames Wright       StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur);
5088085925cSJames Wright     }
5094b96a86bSJames Wright   }
5108085925cSJames Wright   return 0;
5118085925cSJames Wright }
5128085925cSJames Wright 
5132b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
5148fff8293SJames Wright   return BoundaryIntegral(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
515d4559bbeSJames Wright }
516d4559bbeSJames Wright 
5172b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
5188fff8293SJames Wright   return BoundaryIntegral(ctx, Q, in, out, STATEVAR_PRIMITIVE);
519d4559bbeSJames Wright }
520d4559bbeSJames Wright 
5219b103f75SJames Wright CEED_QFUNCTION(BoundaryIntegral_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
5229b103f75SJames Wright   return BoundaryIntegral(ctx, Q, in, out, STATEVAR_ENTROPY);
5239b103f75SJames Wright }
5249b103f75SJames Wright 
525d1b9ef12SLeila Ghaffari // *****************************************************************************
52668ae065aSJames Wright // Jacobian for "set nothing" boundary integral
527d1b9ef12SLeila Ghaffari // *****************************************************************************
5282b916ea7SJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out,
5298fff8293SJames Wright                                                     StateVariable state_var) {
5303d65b166SJames Wright   const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
53187bd45e7SJames Wright   const CeedScalar(*Grad_dq)        = in[1];
532ade49511SJames Wright   const CeedScalar(*q_data_sur)     = in[2];
533c1484fadSKenneth E. Jansen   const CeedScalar(*jac_data_sur)   = in[4];
53468ae065aSJames Wright   CeedScalar(*v)[CEED_Q_VLA]        = (CeedScalar(*)[CEED_Q_VLA])out[0];
53568ae065aSJames Wright 
53668ae065aSJames Wright   const NewtonianIdealGasContext context     = (NewtonianIdealGasContext)ctx;
537ade49511SJames Wright   const bool                     is_implicit = context->is_implicit;
53868ae065aSJames Wright 
5393d65b166SJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
54078e8b7daSJames Wright     CeedScalar wdetJb, dXdx[2][3], normal[3];
54178e8b7daSJames Wright     QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal);
542ade49511SJames Wright     wdetJb *= is_implicit ? -1. : 1.;
54368ae065aSJames Wright 
544edcfef1bSKenneth E. Jansen     CeedScalar qi[5], kmstress[6], dqi[5];
545ade49511SJames Wright     StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi);
546ade49511SJames Wright     StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress);
54741e73928SJames Wright     for (int j = 0; j < 5; j++) dqi[j] = dq[j][i];
5483934e2b1SJames Wright 
549edcfef1bSKenneth E. Jansen     State s  = StateFromQ(context, qi, state_var);
550edcfef1bSKenneth E. Jansen     State ds = StateFromQ_fwd(context, s, dqi, state_var);
55168ae065aSJames Wright 
55268ae065aSJames Wright     State grad_ds[3];
553edcfef1bSKenneth E. Jansen     StatePhysicalGradientFromReference_Boundary(Q, i, context, s, state_var, Grad_dq, dXdx, grad_ds);
55468ae065aSJames Wright 
55568ae065aSJames Wright     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
55640a33f2dSJames Wright     KMStrainRate_State(grad_ds, dstrain_rate);
55768ae065aSJames Wright     NewtonianStress(context, dstrain_rate, dkmstress);
55868ae065aSJames Wright     KMUnpack(dkmstress, dstress);
55968ae065aSJames Wright     KMUnpack(kmstress, stress);
56068ae065aSJames Wright     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
56168ae065aSJames Wright 
56268ae065aSJames Wright     StateConservative dF_inviscid[3];
56368ae065aSJames Wright     FluxInviscid_fwd(context, s, ds, dF_inviscid);
56468ae065aSJames Wright 
565c5740391SJames Wright     CeedScalar dFlux[5];
56678e8b7daSJames Wright     FluxTotal_Boundary(dF_inviscid, dstress, dFe, normal, dFlux);
56768ae065aSJames Wright 
568c5740391SJames Wright     for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j];
569512c8ec7SJames Wright   }
57068ae065aSJames Wright   return 0;
57168ae065aSJames Wright }
57268ae065aSJames Wright 
5732b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
5748fff8293SJames Wright   return BoundaryIntegral_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
575d4559bbeSJames Wright }
576d4559bbeSJames Wright 
5772b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
5788fff8293SJames Wright   return BoundaryIntegral_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE);
579d4559bbeSJames Wright }
5809b103f75SJames Wright 
5819b103f75SJames Wright CEED_QFUNCTION(BoundaryIntegral_Jacobian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
5829b103f75SJames Wright   return BoundaryIntegral_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY);
5839b103f75SJames Wright }
58436038bbcSJames Wright 
5858561fee2SJames Wright // @brief Volume integral for RHS of divergence of diffusive flux direct projection
58636038bbcSJames Wright CEED_QFUNCTION_HELPER int DivDiffusiveFluxVolumeRHS_NS(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out,
58736038bbcSJames Wright                                                        StateVariable state_var) {
58836038bbcSJames Wright   const CeedScalar(*q)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[0];
58936038bbcSJames Wright   const CeedScalar(*Grad_q)          = in[1];
59036038bbcSJames Wright   const CeedScalar(*q_data)          = in[2];
59136038bbcSJames Wright   CeedScalar(*Grad_v)[4][CEED_Q_VLA] = (CeedScalar(*)[4][CEED_Q_VLA])out[0];
59236038bbcSJames Wright 
59336038bbcSJames Wright   const NewtonianIdealGasContext context               = (NewtonianIdealGasContext)ctx;
59436038bbcSJames Wright   const StateConservative        ZeroInviscidFluxes[3] = {{0}};
59536038bbcSJames Wright 
59636038bbcSJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
59736038bbcSJames Wright     const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
59836038bbcSJames Wright     const State      s     = StateFromQ(context, qi, state_var);
59936038bbcSJames Wright     CeedScalar       wdetJ, dXdx[3][3];
60036038bbcSJames Wright     CeedScalar       stress[3][3], Fe[3], Fdiff[5][3];
60136038bbcSJames Wright 
60236038bbcSJames Wright     QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx);
60336038bbcSJames Wright     {  // Get stress and Fe
60436038bbcSJames Wright       State      grad_s[3];
60536038bbcSJames Wright       CeedScalar strain_rate[6], kmstress[6];
60636038bbcSJames Wright 
60736038bbcSJames Wright       StatePhysicalGradientFromReference(Q, i, context, s, state_var, Grad_q, dXdx, grad_s);
60836038bbcSJames Wright       KMStrainRate_State(grad_s, strain_rate);
60936038bbcSJames Wright       NewtonianStress(context, strain_rate, kmstress);
61036038bbcSJames Wright       KMUnpack(kmstress, stress);
61136038bbcSJames Wright       ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
61236038bbcSJames Wright     }
61336038bbcSJames Wright 
61436038bbcSJames Wright     FluxTotal(ZeroInviscidFluxes, stress, Fe, Fdiff);
61536038bbcSJames Wright 
61636038bbcSJames Wright     for (CeedInt j = 1; j < 5; j++) {  // Continuity has no diffusive flux, therefore skip
61736038bbcSJames Wright       for (CeedInt k = 0; k < 3; k++) {
61836038bbcSJames Wright         Grad_v[k][j - 1][i] = -wdetJ * Dot3(dXdx[k], Fdiff[j]);
61936038bbcSJames Wright       }
62036038bbcSJames Wright     }
62136038bbcSJames Wright   }
62236038bbcSJames Wright   return 0;
62336038bbcSJames Wright }
62436038bbcSJames Wright 
62536038bbcSJames Wright CEED_QFUNCTION(DivDiffusiveFluxVolumeRHS_NS_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
62636038bbcSJames Wright   return DivDiffusiveFluxVolumeRHS_NS(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
62736038bbcSJames Wright }
62836038bbcSJames Wright 
62936038bbcSJames Wright CEED_QFUNCTION(DivDiffusiveFluxVolumeRHS_NS_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
63036038bbcSJames Wright   return DivDiffusiveFluxVolumeRHS_NS(ctx, Q, in, out, STATEVAR_PRIMITIVE);
63136038bbcSJames Wright }
63236038bbcSJames Wright 
63336038bbcSJames Wright CEED_QFUNCTION(DivDiffusiveFluxVolumeRHS_NS_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
63436038bbcSJames Wright   return DivDiffusiveFluxVolumeRHS_NS(ctx, Q, in, out, STATEVAR_ENTROPY);
63536038bbcSJames Wright }
63636038bbcSJames Wright 
6378561fee2SJames Wright // @brief Boundary integral for RHS of divergence of diffusive flux direct projection
63836038bbcSJames Wright CEED_QFUNCTION_HELPER int DivDiffusiveFluxBoundaryRHS_NS(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out,
63936038bbcSJames Wright                                                          StateVariable state_var) {
64036038bbcSJames Wright   const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
64136038bbcSJames Wright   const CeedScalar(*Grad_q)        = in[1];
64236038bbcSJames Wright   const CeedScalar(*q_data)        = in[2];
64336038bbcSJames Wright   CeedScalar(*v)[CEED_Q_VLA]       = (CeedScalar(*)[CEED_Q_VLA])out[0];
64436038bbcSJames Wright 
64536038bbcSJames Wright   const NewtonianIdealGasContext context               = (NewtonianIdealGasContext)ctx;
64636038bbcSJames Wright   const StateConservative        ZeroInviscidFluxes[3] = {{0}};
64736038bbcSJames Wright 
64836038bbcSJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
64936038bbcSJames Wright     const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
65036038bbcSJames Wright     const State      s     = StateFromQ(context, qi, state_var);
65136038bbcSJames Wright     CeedScalar       wdetJ, dXdx[3][3], normal[3];
65236038bbcSJames Wright     CeedScalar       stress[3][3], Fe[3], Fdiff[5];
65336038bbcSJames Wright 
65436038bbcSJames Wright     QdataBoundaryGradientUnpack_3D(Q, i, q_data, &wdetJ, dXdx, normal);
65536038bbcSJames Wright     {  // Get stress and Fe
65636038bbcSJames Wright       State      grad_s[3];
65736038bbcSJames Wright       CeedScalar strain_rate[6], kmstress[6];
65836038bbcSJames Wright 
65936038bbcSJames Wright       StatePhysicalGradientFromReference(Q, i, context, s, state_var, Grad_q, dXdx, grad_s);
66036038bbcSJames Wright       KMStrainRate_State(grad_s, strain_rate);
66136038bbcSJames Wright       NewtonianStress(context, strain_rate, kmstress);
66236038bbcSJames Wright       KMUnpack(kmstress, stress);
66336038bbcSJames Wright       ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
66436038bbcSJames Wright     }
66536038bbcSJames Wright 
66636038bbcSJames Wright     FluxTotal_Boundary(ZeroInviscidFluxes, stress, Fe, normal, Fdiff);
66736038bbcSJames Wright 
66836038bbcSJames Wright     // Continuity has no diffusive flux, therefore skip
66936038bbcSJames Wright     for (CeedInt j = 1; j < 5; j++) v[j - 1][i] = wdetJ * Fdiff[j];
67036038bbcSJames Wright   }
67136038bbcSJames Wright   return 0;
67236038bbcSJames Wright }
67336038bbcSJames Wright 
67436038bbcSJames Wright CEED_QFUNCTION(DivDiffusiveFluxBoundaryRHS_NS_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
67536038bbcSJames Wright   return DivDiffusiveFluxBoundaryRHS_NS(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
67636038bbcSJames Wright }
67736038bbcSJames Wright 
67836038bbcSJames Wright CEED_QFUNCTION(DivDiffusiveFluxBoundaryRHS_NS_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
67936038bbcSJames Wright   return DivDiffusiveFluxBoundaryRHS_NS(ctx, Q, in, out, STATEVAR_PRIMITIVE);
68036038bbcSJames Wright }
68136038bbcSJames Wright 
68236038bbcSJames Wright CEED_QFUNCTION(DivDiffusiveFluxBoundaryRHS_NS_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
68336038bbcSJames Wright   return DivDiffusiveFluxBoundaryRHS_NS(ctx, Q, in, out, STATEVAR_ENTROPY);
68436038bbcSJames Wright }
68536038bbcSJames Wright 
6868561fee2SJames Wright // @brief Integral for RHS of diffusive flux indirect projection
68736038bbcSJames Wright CEED_QFUNCTION_HELPER int DiffusiveFluxRHS_NS(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) {
68836038bbcSJames Wright   const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
68936038bbcSJames Wright   const CeedScalar(*Grad_q)        = in[1];
69036038bbcSJames Wright   const CeedScalar(*q_data)        = in[2];
69136038bbcSJames Wright   CeedScalar(*v)[CEED_Q_VLA]       = (CeedScalar(*)[CEED_Q_VLA])out[0];
69236038bbcSJames Wright 
69336038bbcSJames Wright   const NewtonianIdealGasContext context               = (NewtonianIdealGasContext)ctx;
69436038bbcSJames Wright   const StateConservative        ZeroInviscidFluxes[3] = {{0}};
69536038bbcSJames Wright 
69636038bbcSJames Wright   CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
69736038bbcSJames Wright     const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
69836038bbcSJames Wright     const State      s     = StateFromQ(context, qi, state_var);
69936038bbcSJames Wright     CeedScalar       wdetJ, dXdx[3][3];
70036038bbcSJames Wright     CeedScalar       stress[3][3], Fe[3], Fdiff[5][3];
70136038bbcSJames Wright 
70236038bbcSJames Wright     QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx);
70336038bbcSJames Wright     {  // Get stress and Fe
70436038bbcSJames Wright       State      grad_s[3];
70536038bbcSJames Wright       CeedScalar strain_rate[6], kmstress[6];
70636038bbcSJames Wright 
70736038bbcSJames Wright       StatePhysicalGradientFromReference(Q, i, context, s, state_var, Grad_q, dXdx, grad_s);
70836038bbcSJames Wright       KMStrainRate_State(grad_s, strain_rate);
70936038bbcSJames Wright       NewtonianStress(context, strain_rate, kmstress);
71036038bbcSJames Wright       KMUnpack(kmstress, stress);
71136038bbcSJames Wright       ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
71236038bbcSJames Wright     }
71336038bbcSJames Wright 
71436038bbcSJames Wright     FluxTotal(ZeroInviscidFluxes, stress, Fe, Fdiff);
71536038bbcSJames Wright 
71636038bbcSJames Wright     for (CeedInt j = 1; j < 5; j++) {  // Continuity has no diffusive flux, therefore skip
71736038bbcSJames Wright       for (CeedInt k = 0; k < 3; k++) {
71836038bbcSJames Wright         v[(j - 1) * 3 + k][i] = wdetJ * Fdiff[j][k];
71936038bbcSJames Wright       }
72036038bbcSJames Wright     }
72136038bbcSJames Wright   }
72236038bbcSJames Wright   return 0;
72336038bbcSJames Wright }
72436038bbcSJames Wright 
72536038bbcSJames Wright CEED_QFUNCTION(DiffusiveFluxRHS_NS_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
72636038bbcSJames Wright   return DiffusiveFluxRHS_NS(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
72736038bbcSJames Wright }
72836038bbcSJames Wright 
72936038bbcSJames Wright CEED_QFUNCTION(DiffusiveFluxRHS_NS_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
73036038bbcSJames Wright   return DiffusiveFluxRHS_NS(ctx, Q, in, out, STATEVAR_PRIMITIVE);
73136038bbcSJames Wright }
73236038bbcSJames Wright 
73336038bbcSJames Wright CEED_QFUNCTION(DiffusiveFluxRHS_NS_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
73436038bbcSJames Wright   return DiffusiveFluxRHS_NS(ctx, Q, in, out, STATEVAR_ENTROPY);
73536038bbcSJames Wright }
736