1*224fc8c8SJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2025, HONEE contributors. 2*224fc8c8SJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause 3*224fc8c8SJames Wright 4*224fc8c8SJames Wright /// @file 5*224fc8c8SJames Wright /// QFunctions for the `bc_freestream` and `bc_outflow` boundary conditions 6*224fc8c8SJames Wright #include "bc_freestream_type.h" 7*224fc8c8SJames Wright #include "newtonian_state.h" 8*224fc8c8SJames Wright #include "newtonian_types.h" 9*224fc8c8SJames Wright #include "riemann_solver.h" 10*224fc8c8SJames Wright 11*224fc8c8SJames Wright // Note the identity 12*224fc8c8SJames Wright // 13*224fc8c8SJames Wright // softplus(x) - x = log(1 + exp(x)) - x 14*224fc8c8SJames Wright // = log(1 + exp(x)) + log(exp(-x)) 15*224fc8c8SJames Wright // = log((1 + exp(x)) * exp(-x)) 16*224fc8c8SJames Wright // = log(exp(-x) + 1) 17*224fc8c8SJames Wright // = softplus(-x) 18*224fc8c8SJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus(CeedScalar x, CeedScalar width) { 19*224fc8c8SJames Wright if (x > 40 * width) return x; 20*224fc8c8SJames Wright return width * log1p(exp(x / width)); 21*224fc8c8SJames Wright } 22*224fc8c8SJames Wright 23*224fc8c8SJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus_fwd(CeedScalar x, CeedScalar dx, CeedScalar width) { 24*224fc8c8SJames Wright if (x > 40 * width) return 1; 25*224fc8c8SJames Wright const CeedScalar t = exp(x / width); 26*224fc8c8SJames Wright return t / (1 + t); 27*224fc8c8SJames Wright } 28*224fc8c8SJames Wright 29*224fc8c8SJames Wright // Viscous Outflow boundary condition, setting a constant exterior pressure and 30*224fc8c8SJames Wright // temperature as input for a Riemann solve. This condition is stable even in 31*224fc8c8SJames Wright // recirculating flow so long as the exterior temperature is sensible. 32*224fc8c8SJames Wright // 33*224fc8c8SJames Wright // The velocity in the exterior state has optional softplus regularization to 34*224fc8c8SJames Wright // keep it outflow. These parameters have been finnicky in practice and provide 35*224fc8c8SJames Wright // little or no benefit in the tests we've run thus far, thus we recommend 36*224fc8c8SJames Wright // skipping this feature and just allowing recirculation. 37*224fc8c8SJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 38*224fc8c8SJames Wright const OutflowContext outflow = (OutflowContext)ctx; 39*224fc8c8SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 40*224fc8c8SJames Wright const CeedScalar(*Grad_q) = in[1]; 41*224fc8c8SJames Wright const CeedScalar(*q_data_sur) = in[2]; 42*224fc8c8SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 43*224fc8c8SJames Wright CeedScalar(*jac_data_sur) = outflow->gas.is_implicit ? out[1] : NULL; 44*224fc8c8SJames Wright 45*224fc8c8SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 46*224fc8c8SJames Wright const bool is_implicit = gas->is_implicit; 47*224fc8c8SJames Wright 48*224fc8c8SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 49*224fc8c8SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 50*224fc8c8SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 51*224fc8c8SJames Wright wdetJb *= is_implicit ? -1. : 1.; 52*224fc8c8SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 53*224fc8c8SJames Wright const State s_int = StateFromQ(gas, qi, state_var); 54*224fc8c8SJames Wright 55*224fc8c8SJames Wright StatePrimitive y_ext = s_int.Y; 56*224fc8c8SJames Wright y_ext.pressure = outflow->pressure; 57*224fc8c8SJames Wright y_ext.temperature = outflow->temperature; 58*224fc8c8SJames Wright const CeedScalar u_normal = Dot3(y_ext.velocity, normal); 59*224fc8c8SJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 60*224fc8c8SJames Wright for (CeedInt j = 0; j < 3; j++) { 61*224fc8c8SJames Wright y_ext.velocity[j] += normal[j] * proj; // (I - n n^T) projects into the plane tangent to the normal 62*224fc8c8SJames Wright } 63*224fc8c8SJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 64*224fc8c8SJames Wright 65*224fc8c8SJames Wright State grad_s[3]; 66*224fc8c8SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_q, dXdx, grad_s); 67*224fc8c8SJames Wright 68*224fc8c8SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 69*224fc8c8SJames Wright KMStrainRate_State(grad_s, strain_rate); 70*224fc8c8SJames Wright NewtonianStress(gas, strain_rate, kmstress); 71*224fc8c8SJames Wright KMUnpack(kmstress, stress); 72*224fc8c8SJames Wright ViscousEnergyFlux(gas, s_int.Y, grad_s, stress, Fe); 73*224fc8c8SJames Wright 74*224fc8c8SJames Wright StateConservative F_inviscid_normal = RiemannFlux_HLLC(gas, s_int, s_ext, normal); 75*224fc8c8SJames Wright 76*224fc8c8SJames Wright CeedScalar Flux[5]; 77*224fc8c8SJames Wright FluxTotal_RiemannBoundary(F_inviscid_normal, stress, Fe, normal, Flux); 78*224fc8c8SJames Wright 79*224fc8c8SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 80*224fc8c8SJames Wright 81*224fc8c8SJames Wright // Save values for Jacobian 82*224fc8c8SJames Wright if (is_implicit) { 83*224fc8c8SJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 84*224fc8c8SJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 85*224fc8c8SJames Wright } 86*224fc8c8SJames Wright } 87*224fc8c8SJames Wright return 0; 88*224fc8c8SJames Wright } 89*224fc8c8SJames Wright 90*224fc8c8SJames Wright CEED_QFUNCTION(RiemannOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 91*224fc8c8SJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 92*224fc8c8SJames Wright } 93*224fc8c8SJames Wright 94*224fc8c8SJames Wright CEED_QFUNCTION(RiemannOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 95*224fc8c8SJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 96*224fc8c8SJames Wright } 97*224fc8c8SJames Wright 98*224fc8c8SJames Wright CEED_QFUNCTION(RiemannOutflow_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 99*224fc8c8SJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_ENTROPY); 100*224fc8c8SJames Wright } 101*224fc8c8SJames Wright 102*224fc8c8SJames Wright // ***************************************************************************** 103*224fc8c8SJames Wright // Jacobian for Riemann pressure/temperature outflow boundary condition 104*224fc8c8SJames Wright // ***************************************************************************** 105*224fc8c8SJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 106*224fc8c8SJames Wright StateVariable state_var) { 107*224fc8c8SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 108*224fc8c8SJames Wright const CeedScalar(*Grad_dq) = in[1]; 109*224fc8c8SJames Wright const CeedScalar(*q_data_sur) = in[2]; 110*224fc8c8SJames Wright const CeedScalar(*jac_data_sur) = in[4]; 111*224fc8c8SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 112*224fc8c8SJames Wright 113*224fc8c8SJames Wright const OutflowContext outflow = (OutflowContext)ctx; 114*224fc8c8SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 115*224fc8c8SJames Wright const bool is_implicit = gas->is_implicit; 116*224fc8c8SJames Wright 117*224fc8c8SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 118*224fc8c8SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 119*224fc8c8SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 120*224fc8c8SJames Wright wdetJb *= is_implicit ? -1. : 1.; 121*224fc8c8SJames Wright 122*224fc8c8SJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 123*224fc8c8SJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 124*224fc8c8SJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 125*224fc8c8SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 126*224fc8c8SJames Wright 127*224fc8c8SJames Wright State s_int = StateFromQ(gas, qi, state_var); 128*224fc8c8SJames Wright const State ds_int = StateFromQ_fwd(gas, s_int, dqi, state_var); 129*224fc8c8SJames Wright StatePrimitive y_ext = s_int.Y, dy_ext = ds_int.Y; 130*224fc8c8SJames Wright y_ext.pressure = outflow->pressure; 131*224fc8c8SJames Wright y_ext.temperature = outflow->temperature; 132*224fc8c8SJames Wright dy_ext.pressure = 0; 133*224fc8c8SJames Wright dy_ext.temperature = 0; 134*224fc8c8SJames Wright const CeedScalar u_normal = Dot3(s_int.Y.velocity, normal); 135*224fc8c8SJames Wright const CeedScalar du_normal = Dot3(ds_int.Y.velocity, normal); 136*224fc8c8SJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 137*224fc8c8SJames Wright const CeedScalar dproj = (1 - outflow->recirc) * Softplus_fwd(-u_normal, -du_normal, outflow->softplus_velocity); 138*224fc8c8SJames Wright for (CeedInt j = 0; j < 3; j++) { 139*224fc8c8SJames Wright y_ext.velocity[j] += normal[j] * proj; 140*224fc8c8SJames Wright dy_ext.velocity[j] += normal[j] * dproj; 141*224fc8c8SJames Wright } 142*224fc8c8SJames Wright 143*224fc8c8SJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 144*224fc8c8SJames Wright State ds_ext = StateFromPrimitive_fwd(gas, s_ext, dy_ext); 145*224fc8c8SJames Wright 146*224fc8c8SJames Wright State grad_ds[3]; 147*224fc8c8SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_dq, dXdx, grad_ds); 148*224fc8c8SJames Wright 149*224fc8c8SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 150*224fc8c8SJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 151*224fc8c8SJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 152*224fc8c8SJames Wright KMUnpack(dkmstress, dstress); 153*224fc8c8SJames Wright KMUnpack(kmstress, stress); 154*224fc8c8SJames Wright ViscousEnergyFlux_fwd(gas, s_int.Y, ds_int.Y, grad_ds, stress, dstress, dFe); 155*224fc8c8SJames Wright 156*224fc8c8SJames Wright StateConservative dF_inviscid_normal = RiemannFlux_HLLC_fwd(gas, s_int, ds_int, s_ext, ds_ext, normal); 157*224fc8c8SJames Wright 158*224fc8c8SJames Wright CeedScalar dFlux[5]; 159*224fc8c8SJames Wright FluxTotal_RiemannBoundary(dF_inviscid_normal, dstress, dFe, normal, dFlux); 160*224fc8c8SJames Wright 161*224fc8c8SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 162*224fc8c8SJames Wright } 163*224fc8c8SJames Wright return 0; 164*224fc8c8SJames Wright } 165*224fc8c8SJames Wright 166*224fc8c8SJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 167*224fc8c8SJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 168*224fc8c8SJames Wright } 169*224fc8c8SJames Wright 170*224fc8c8SJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 171*224fc8c8SJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 172*224fc8c8SJames Wright } 173*224fc8c8SJames Wright 174*224fc8c8SJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 175*224fc8c8SJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY); 176*224fc8c8SJames Wright } 177*224fc8c8SJames Wright 178*224fc8c8SJames Wright // ***************************************************************************** 179*224fc8c8SJames Wright // Outflow boundary condition, weakly setting a constant pressure. This is the 180*224fc8c8SJames Wright // classic outflow condition used by PHASTA-C and retained largely for 181*224fc8c8SJames Wright // comparison. In our experiments, it is never better than RiemannOutflow, and 182*224fc8c8SJames Wright // will crash if outflow ever becomes an inflow, as occurs with strong 183*224fc8c8SJames Wright // acoustics, vortices, etc. 184*224fc8c8SJames Wright // ***************************************************************************** 185*224fc8c8SJames Wright CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 186*224fc8c8SJames Wright const OutflowContext outflow = (OutflowContext)ctx; 187*224fc8c8SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 188*224fc8c8SJames Wright const CeedScalar(*Grad_q) = in[1]; 189*224fc8c8SJames Wright const CeedScalar(*q_data_sur) = in[2]; 190*224fc8c8SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 191*224fc8c8SJames Wright CeedScalar(*jac_data_sur) = outflow->gas.is_implicit ? out[1] : NULL; 192*224fc8c8SJames Wright 193*224fc8c8SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 194*224fc8c8SJames Wright const bool is_implicit = gas->is_implicit; 195*224fc8c8SJames Wright 196*224fc8c8SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 197*224fc8c8SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 198*224fc8c8SJames Wright State s = StateFromQ(gas, qi, state_var); 199*224fc8c8SJames Wright s.Y.pressure = outflow->pressure; 200*224fc8c8SJames Wright 201*224fc8c8SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 202*224fc8c8SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 203*224fc8c8SJames Wright wdetJb *= is_implicit ? -1. : 1.; 204*224fc8c8SJames Wright 205*224fc8c8SJames Wright State grad_s[3]; 206*224fc8c8SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_q, dXdx, grad_s); 207*224fc8c8SJames Wright 208*224fc8c8SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 209*224fc8c8SJames Wright KMStrainRate_State(grad_s, strain_rate); 210*224fc8c8SJames Wright NewtonianStress(gas, strain_rate, kmstress); 211*224fc8c8SJames Wright KMUnpack(kmstress, stress); 212*224fc8c8SJames Wright ViscousEnergyFlux(gas, s.Y, grad_s, stress, Fe); 213*224fc8c8SJames Wright 214*224fc8c8SJames Wright StateConservative F_inviscid[3]; 215*224fc8c8SJames Wright FluxInviscid(gas, s, F_inviscid); 216*224fc8c8SJames Wright 217*224fc8c8SJames Wright CeedScalar Flux[5]; 218*224fc8c8SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, normal, Flux); 219*224fc8c8SJames Wright 220*224fc8c8SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 221*224fc8c8SJames Wright 222*224fc8c8SJames Wright // Save values for Jacobian 223*224fc8c8SJames Wright if (is_implicit) { 224*224fc8c8SJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 225*224fc8c8SJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 226*224fc8c8SJames Wright } 227*224fc8c8SJames Wright } 228*224fc8c8SJames Wright return 0; 229*224fc8c8SJames Wright } 230*224fc8c8SJames Wright 231*224fc8c8SJames Wright CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 232*224fc8c8SJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 233*224fc8c8SJames Wright } 234*224fc8c8SJames Wright 235*224fc8c8SJames Wright CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 236*224fc8c8SJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 237*224fc8c8SJames Wright } 238*224fc8c8SJames Wright 239*224fc8c8SJames Wright CEED_QFUNCTION(PressureOutflow_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 240*224fc8c8SJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_ENTROPY); 241*224fc8c8SJames Wright } 242*224fc8c8SJames Wright 243*224fc8c8SJames Wright // ***************************************************************************** 244*224fc8c8SJames Wright // Jacobian for weak-pressure outflow boundary condition 245*224fc8c8SJames Wright // ***************************************************************************** 246*224fc8c8SJames Wright CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 247*224fc8c8SJames Wright StateVariable state_var) { 248*224fc8c8SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 249*224fc8c8SJames Wright const CeedScalar(*Grad_dq) = in[1]; 250*224fc8c8SJames Wright const CeedScalar(*q_data_sur) = in[2]; 251*224fc8c8SJames Wright const CeedScalar(*jac_data_sur) = in[4]; 252*224fc8c8SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 253*224fc8c8SJames Wright 254*224fc8c8SJames Wright const OutflowContext outflow = (OutflowContext)ctx; 255*224fc8c8SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 256*224fc8c8SJames Wright const bool is_implicit = gas->is_implicit; 257*224fc8c8SJames Wright 258*224fc8c8SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 259*224fc8c8SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 260*224fc8c8SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 261*224fc8c8SJames Wright wdetJb *= is_implicit ? -1. : 1.; 262*224fc8c8SJames Wright 263*224fc8c8SJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 264*224fc8c8SJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 265*224fc8c8SJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 266*224fc8c8SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 267*224fc8c8SJames Wright 268*224fc8c8SJames Wright State s = StateFromQ(gas, qi, state_var); 269*224fc8c8SJames Wright State ds = StateFromQ_fwd(gas, s, dqi, state_var); 270*224fc8c8SJames Wright s.Y.pressure = outflow->pressure; 271*224fc8c8SJames Wright ds.Y.pressure = 0.; 272*224fc8c8SJames Wright 273*224fc8c8SJames Wright State grad_ds[3]; 274*224fc8c8SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_dq, dXdx, grad_ds); 275*224fc8c8SJames Wright 276*224fc8c8SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 277*224fc8c8SJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 278*224fc8c8SJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 279*224fc8c8SJames Wright KMUnpack(dkmstress, dstress); 280*224fc8c8SJames Wright KMUnpack(kmstress, stress); 281*224fc8c8SJames Wright ViscousEnergyFlux_fwd(gas, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 282*224fc8c8SJames Wright 283*224fc8c8SJames Wright StateConservative dF_inviscid[3]; 284*224fc8c8SJames Wright FluxInviscid_fwd(gas, s, ds, dF_inviscid); 285*224fc8c8SJames Wright 286*224fc8c8SJames Wright CeedScalar dFlux[5]; 287*224fc8c8SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, normal, dFlux); 288*224fc8c8SJames Wright 289*224fc8c8SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 290*224fc8c8SJames Wright } 291*224fc8c8SJames Wright return 0; 292*224fc8c8SJames Wright } 293*224fc8c8SJames Wright 294*224fc8c8SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 295*224fc8c8SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 296*224fc8c8SJames Wright } 297*224fc8c8SJames Wright 298*224fc8c8SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 299*224fc8c8SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 300*224fc8c8SJames Wright } 301*224fc8c8SJames Wright 302*224fc8c8SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 303*224fc8c8SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY); 304*224fc8c8SJames Wright } 305