1*9ed3d70dSJames Wright // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2*9ed3d70dSJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3*9ed3d70dSJames Wright // 4*9ed3d70dSJames Wright // SPDX-License-Identifier: BSD-2-Clause 5*9ed3d70dSJames Wright // 6*9ed3d70dSJames Wright // This file is part of CEED: http://github.com/ceed 7*9ed3d70dSJames Wright 8*9ed3d70dSJames Wright /// @file 9*9ed3d70dSJames Wright /// QFunctions for the `bc_freestream` and `bc_outflow` boundary conditions 10*9ed3d70dSJames Wright 11*9ed3d70dSJames Wright #include "bc_freestream_type.h" 12*9ed3d70dSJames Wright #include "newtonian_state.h" 13*9ed3d70dSJames Wright #include "newtonian_types.h" 14*9ed3d70dSJames Wright #include "riemann_solver.h" 15*9ed3d70dSJames Wright 16*9ed3d70dSJames Wright // ***************************************************************************** 17*9ed3d70dSJames Wright // Freestream Boundary Condition 18*9ed3d70dSJames Wright // ***************************************************************************** 19*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER int Freestream(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var, 20*9ed3d70dSJames Wright RiemannFluxType flux_type) { 21*9ed3d70dSJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 22*9ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 23*9ed3d70dSJames Wright 24*9ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 25*9ed3d70dSJames Wright CeedScalar(*jac_data_sur) = out[1]; 26*9ed3d70dSJames Wright 27*9ed3d70dSJames Wright const FreestreamContext context = (FreestreamContext)ctx; 28*9ed3d70dSJames Wright const NewtonianIdealGasContext newt_ctx = &context->newtonian_ctx; 29*9ed3d70dSJames Wright const bool is_implicit = newt_ctx->is_implicit; 30*9ed3d70dSJames Wright const CeedScalar zeros[6] = {0.}; 31*9ed3d70dSJames Wright 32*9ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 33*9ed3d70dSJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 34*9ed3d70dSJames Wright State s = StateFromQ(newt_ctx, qi, state_var); 35*9ed3d70dSJames Wright 36*9ed3d70dSJames Wright CeedScalar wdetJb, norm[3]; 37*9ed3d70dSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, norm); 38*9ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 39*9ed3d70dSJames Wright 40*9ed3d70dSJames Wright StateConservative flux; 41*9ed3d70dSJames Wright switch (flux_type) { 42*9ed3d70dSJames Wright case RIEMANN_HLL: 43*9ed3d70dSJames Wright flux = RiemannFlux_HLL(newt_ctx, s, context->S_infty, norm); 44*9ed3d70dSJames Wright break; 45*9ed3d70dSJames Wright case RIEMANN_HLLC: 46*9ed3d70dSJames Wright flux = RiemannFlux_HLLC(newt_ctx, s, context->S_infty, norm); 47*9ed3d70dSJames Wright break; 48*9ed3d70dSJames Wright } 49*9ed3d70dSJames Wright CeedScalar Flux[5]; 50*9ed3d70dSJames Wright UnpackState_U(flux, Flux); 51*9ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 52*9ed3d70dSJames Wright 53*9ed3d70dSJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 54*9ed3d70dSJames Wright StoredValuesPack(Q, i, 5, 6, zeros, jac_data_sur); // Every output value must be set 55*9ed3d70dSJames Wright } 56*9ed3d70dSJames Wright return 0; 57*9ed3d70dSJames Wright } 58*9ed3d70dSJames Wright 59*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Conserv_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 60*9ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLL); 61*9ed3d70dSJames Wright } 62*9ed3d70dSJames Wright 63*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Prim_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 64*9ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLL); 65*9ed3d70dSJames Wright } 66*9ed3d70dSJames Wright 67*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Conserv_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 68*9ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLLC); 69*9ed3d70dSJames Wright } 70*9ed3d70dSJames Wright 71*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Prim_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 72*9ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLLC); 73*9ed3d70dSJames Wright } 74*9ed3d70dSJames Wright 75*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER int Freestream_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var, 76*9ed3d70dSJames Wright RiemannFluxType flux_type) { 77*9ed3d70dSJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 78*9ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 79*9ed3d70dSJames Wright const CeedScalar(*jac_data_sur) = in[4]; 80*9ed3d70dSJames Wright 81*9ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 82*9ed3d70dSJames Wright 83*9ed3d70dSJames Wright const FreestreamContext context = (FreestreamContext)ctx; 84*9ed3d70dSJames Wright const NewtonianIdealGasContext newt_ctx = &context->newtonian_ctx; 85*9ed3d70dSJames Wright const bool is_implicit = newt_ctx->is_implicit; 86*9ed3d70dSJames Wright const State dS_infty = {0}; 87*9ed3d70dSJames Wright 88*9ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 89*9ed3d70dSJames Wright CeedScalar wdetJb, norm[3]; 90*9ed3d70dSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, norm); 91*9ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 92*9ed3d70dSJames Wright 93*9ed3d70dSJames Wright CeedScalar qi[5], dqi[5]; 94*9ed3d70dSJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 95*9ed3d70dSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 96*9ed3d70dSJames Wright State s = StateFromQ(newt_ctx, qi, state_var); 97*9ed3d70dSJames Wright State ds = StateFromQ_fwd(newt_ctx, s, dqi, state_var); 98*9ed3d70dSJames Wright 99*9ed3d70dSJames Wright StateConservative dflux; 100*9ed3d70dSJames Wright switch (flux_type) { 101*9ed3d70dSJames Wright case RIEMANN_HLL: 102*9ed3d70dSJames Wright dflux = RiemannFlux_HLL_fwd(newt_ctx, s, ds, context->S_infty, dS_infty, norm); 103*9ed3d70dSJames Wright break; 104*9ed3d70dSJames Wright case RIEMANN_HLLC: 105*9ed3d70dSJames Wright dflux = RiemannFlux_HLLC_fwd(newt_ctx, s, ds, context->S_infty, dS_infty, norm); 106*9ed3d70dSJames Wright break; 107*9ed3d70dSJames Wright } 108*9ed3d70dSJames Wright CeedScalar dFlux[5]; 109*9ed3d70dSJames Wright UnpackState_U(dflux, dFlux); 110*9ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 111*9ed3d70dSJames Wright } 112*9ed3d70dSJames Wright return 0; 113*9ed3d70dSJames Wright } 114*9ed3d70dSJames Wright 115*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Conserv_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 116*9ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLL); 117*9ed3d70dSJames Wright } 118*9ed3d70dSJames Wright 119*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Prim_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 120*9ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLL); 121*9ed3d70dSJames Wright } 122*9ed3d70dSJames Wright 123*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Conserv_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 124*9ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLLC); 125*9ed3d70dSJames Wright } 126*9ed3d70dSJames Wright 127*9ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Prim_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 128*9ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLLC); 129*9ed3d70dSJames Wright } 130*9ed3d70dSJames Wright 131*9ed3d70dSJames Wright // Note the identity 132*9ed3d70dSJames Wright // 133*9ed3d70dSJames Wright // softplus(x) - x = log(1 + exp(x)) - x 134*9ed3d70dSJames Wright // = log(1 + exp(x)) + log(exp(-x)) 135*9ed3d70dSJames Wright // = log((1 + exp(x)) * exp(-x)) 136*9ed3d70dSJames Wright // = log(exp(-x) + 1) 137*9ed3d70dSJames Wright // = softplus(-x) 138*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus(CeedScalar x, CeedScalar width) { 139*9ed3d70dSJames Wright if (x > 40 * width) return x; 140*9ed3d70dSJames Wright return width * log1p(exp(x / width)); 141*9ed3d70dSJames Wright } 142*9ed3d70dSJames Wright 143*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus_fwd(CeedScalar x, CeedScalar dx, CeedScalar width) { 144*9ed3d70dSJames Wright if (x > 40 * width) return 1; 145*9ed3d70dSJames Wright const CeedScalar t = exp(x / width); 146*9ed3d70dSJames Wright return t / (1 + t); 147*9ed3d70dSJames Wright } 148*9ed3d70dSJames Wright 149*9ed3d70dSJames Wright // Viscous Outflow boundary condition, setting a constant exterior pressure and 150*9ed3d70dSJames Wright // temperature as input for a Riemann solve. This condition is stable even in 151*9ed3d70dSJames Wright // recirculating flow so long as the exterior temperature is sensible. 152*9ed3d70dSJames Wright // 153*9ed3d70dSJames Wright // The velocity in the exterior state has optional softplus regularization to 154*9ed3d70dSJames Wright // keep it outflow. These parameters have been finnicky in practice and provide 155*9ed3d70dSJames Wright // little or no benefit in the tests we've run thus far, thus we recommend 156*9ed3d70dSJames Wright // skipping this feature and just allowing recirculation. 157*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 158*9ed3d70dSJames Wright // Inputs 159*9ed3d70dSJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 160*9ed3d70dSJames Wright const CeedScalar(*Grad_q) = in[1]; 161*9ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 162*9ed3d70dSJames Wright 163*9ed3d70dSJames Wright // Outputs 164*9ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 165*9ed3d70dSJames Wright CeedScalar(*jac_data_sur) = out[1]; 166*9ed3d70dSJames Wright 167*9ed3d70dSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 168*9ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 169*9ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 170*9ed3d70dSJames Wright 171*9ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 172*9ed3d70dSJames Wright CeedScalar wdetJb, dXdx[2][3], norm[3]; 173*9ed3d70dSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, norm); 174*9ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 175*9ed3d70dSJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 176*9ed3d70dSJames Wright State s_int = StateFromQ(gas, qi, state_var); 177*9ed3d70dSJames Wright 178*9ed3d70dSJames Wright StatePrimitive y_ext = s_int.Y; 179*9ed3d70dSJames Wright y_ext.pressure = outflow->pressure; 180*9ed3d70dSJames Wright y_ext.temperature = outflow->temperature; 181*9ed3d70dSJames Wright const CeedScalar u_normal = Dot3(y_ext.velocity, norm); 182*9ed3d70dSJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 183*9ed3d70dSJames Wright for (CeedInt j = 0; j < 3; j++) { 184*9ed3d70dSJames Wright y_ext.velocity[j] += norm[j] * proj; // (I - n n^T) projects into the plane tangent to the normal 185*9ed3d70dSJames Wright } 186*9ed3d70dSJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 187*9ed3d70dSJames Wright 188*9ed3d70dSJames Wright State grad_s[3]; 189*9ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_q, dXdx, grad_s); 190*9ed3d70dSJames Wright 191*9ed3d70dSJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 192*9ed3d70dSJames Wright KMStrainRate_State(grad_s, strain_rate); 193*9ed3d70dSJames Wright NewtonianStress(gas, strain_rate, kmstress); 194*9ed3d70dSJames Wright KMUnpack(kmstress, stress); 195*9ed3d70dSJames Wright ViscousEnergyFlux(gas, s_int.Y, grad_s, stress, Fe); 196*9ed3d70dSJames Wright 197*9ed3d70dSJames Wright StateConservative F_inviscid_normal = RiemannFlux_HLLC(gas, s_int, s_ext, norm); 198*9ed3d70dSJames Wright 199*9ed3d70dSJames Wright CeedScalar Flux[5]; 200*9ed3d70dSJames Wright FluxTotal_RiemannBoundary(F_inviscid_normal, stress, Fe, norm, Flux); 201*9ed3d70dSJames Wright 202*9ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 203*9ed3d70dSJames Wright 204*9ed3d70dSJames Wright // Save values for Jacobian 205*9ed3d70dSJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 206*9ed3d70dSJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 207*9ed3d70dSJames Wright } 208*9ed3d70dSJames Wright return 0; 209*9ed3d70dSJames Wright } 210*9ed3d70dSJames Wright 211*9ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 212*9ed3d70dSJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 213*9ed3d70dSJames Wright } 214*9ed3d70dSJames Wright 215*9ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 216*9ed3d70dSJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 217*9ed3d70dSJames Wright } 218*9ed3d70dSJames Wright 219*9ed3d70dSJames Wright // ***************************************************************************** 220*9ed3d70dSJames Wright // Jacobian for Riemann pressure/temperature outflow boundary condition 221*9ed3d70dSJames Wright // ***************************************************************************** 222*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 223*9ed3d70dSJames Wright StateVariable state_var) { 224*9ed3d70dSJames Wright // Inputs 225*9ed3d70dSJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 226*9ed3d70dSJames Wright const CeedScalar(*Grad_dq) = in[1]; 227*9ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 228*9ed3d70dSJames Wright const CeedScalar(*jac_data_sur) = in[4]; 229*9ed3d70dSJames Wright 230*9ed3d70dSJames Wright // Outputs 231*9ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 232*9ed3d70dSJames Wright 233*9ed3d70dSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 234*9ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 235*9ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 236*9ed3d70dSJames Wright 237*9ed3d70dSJames Wright // Quadrature Point Loop 238*9ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 239*9ed3d70dSJames Wright CeedScalar wdetJb, dXdx[2][3], norm[3]; 240*9ed3d70dSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, norm); 241*9ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 242*9ed3d70dSJames Wright 243*9ed3d70dSJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 244*9ed3d70dSJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 245*9ed3d70dSJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 246*9ed3d70dSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 247*9ed3d70dSJames Wright 248*9ed3d70dSJames Wright State s_int = StateFromQ(gas, qi, state_var); 249*9ed3d70dSJames Wright const State ds_int = StateFromQ_fwd(gas, s_int, dqi, state_var); 250*9ed3d70dSJames Wright StatePrimitive y_ext = s_int.Y, dy_ext = ds_int.Y; 251*9ed3d70dSJames Wright y_ext.pressure = outflow->pressure; 252*9ed3d70dSJames Wright y_ext.temperature = outflow->temperature; 253*9ed3d70dSJames Wright dy_ext.pressure = 0; 254*9ed3d70dSJames Wright dy_ext.temperature = 0; 255*9ed3d70dSJames Wright const CeedScalar u_normal = Dot3(s_int.Y.velocity, norm); 256*9ed3d70dSJames Wright const CeedScalar du_normal = Dot3(ds_int.Y.velocity, norm); 257*9ed3d70dSJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 258*9ed3d70dSJames Wright const CeedScalar dproj = (1 - outflow->recirc) * Softplus_fwd(-u_normal, -du_normal, outflow->softplus_velocity); 259*9ed3d70dSJames Wright for (CeedInt j = 0; j < 3; j++) { 260*9ed3d70dSJames Wright y_ext.velocity[j] += norm[j] * proj; 261*9ed3d70dSJames Wright dy_ext.velocity[j] += norm[j] * dproj; 262*9ed3d70dSJames Wright } 263*9ed3d70dSJames Wright 264*9ed3d70dSJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 265*9ed3d70dSJames Wright State ds_ext = StateFromPrimitive_fwd(gas, s_ext, dy_ext); 266*9ed3d70dSJames Wright 267*9ed3d70dSJames Wright State grad_ds[3]; 268*9ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_dq, dXdx, grad_ds); 269*9ed3d70dSJames Wright 270*9ed3d70dSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 271*9ed3d70dSJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 272*9ed3d70dSJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 273*9ed3d70dSJames Wright KMUnpack(dkmstress, dstress); 274*9ed3d70dSJames Wright KMUnpack(kmstress, stress); 275*9ed3d70dSJames Wright ViscousEnergyFlux_fwd(gas, s_int.Y, ds_int.Y, grad_ds, stress, dstress, dFe); 276*9ed3d70dSJames Wright 277*9ed3d70dSJames Wright StateConservative dF_inviscid_normal = RiemannFlux_HLLC_fwd(gas, s_int, ds_int, s_ext, ds_ext, norm); 278*9ed3d70dSJames Wright 279*9ed3d70dSJames Wright CeedScalar dFlux[5]; 280*9ed3d70dSJames Wright FluxTotal_RiemannBoundary(dF_inviscid_normal, dstress, dFe, norm, dFlux); 281*9ed3d70dSJames Wright 282*9ed3d70dSJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 283*9ed3d70dSJames Wright } // End Quadrature Point Loop 284*9ed3d70dSJames Wright return 0; 285*9ed3d70dSJames Wright } 286*9ed3d70dSJames Wright 287*9ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 288*9ed3d70dSJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 289*9ed3d70dSJames Wright } 290*9ed3d70dSJames Wright 291*9ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 292*9ed3d70dSJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 293*9ed3d70dSJames Wright } 294*9ed3d70dSJames Wright 295*9ed3d70dSJames Wright // ***************************************************************************** 296*9ed3d70dSJames Wright // Outflow boundary condition, weakly setting a constant pressure. This is the 297*9ed3d70dSJames Wright // classic outflow condition used by PHASTA-C and retained largely for 298*9ed3d70dSJames Wright // comparison. In our experiments, it is never better than RiemannOutflow, and 299*9ed3d70dSJames Wright // will crash if outflow ever becomes an inflow, as occurs with strong 300*9ed3d70dSJames Wright // acoustics, vortices, etc. 301*9ed3d70dSJames Wright // ***************************************************************************** 302*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 303*9ed3d70dSJames Wright // Inputs 304*9ed3d70dSJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 305*9ed3d70dSJames Wright const CeedScalar(*Grad_q) = in[1]; 306*9ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 307*9ed3d70dSJames Wright 308*9ed3d70dSJames Wright // Outputs 309*9ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 310*9ed3d70dSJames Wright CeedScalar(*jac_data_sur) = out[1]; 311*9ed3d70dSJames Wright 312*9ed3d70dSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 313*9ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 314*9ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 315*9ed3d70dSJames Wright 316*9ed3d70dSJames Wright // Quadrature Point Loop 317*9ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 318*9ed3d70dSJames Wright // Setup 319*9ed3d70dSJames Wright // -- Interp in 320*9ed3d70dSJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 321*9ed3d70dSJames Wright State s = StateFromQ(gas, qi, state_var); 322*9ed3d70dSJames Wright s.Y.pressure = outflow->pressure; 323*9ed3d70dSJames Wright 324*9ed3d70dSJames Wright CeedScalar wdetJb, dXdx[2][3], norm[3]; 325*9ed3d70dSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, norm); 326*9ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 327*9ed3d70dSJames Wright 328*9ed3d70dSJames Wright State grad_s[3]; 329*9ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_q, dXdx, grad_s); 330*9ed3d70dSJames Wright 331*9ed3d70dSJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 332*9ed3d70dSJames Wright KMStrainRate_State(grad_s, strain_rate); 333*9ed3d70dSJames Wright NewtonianStress(gas, strain_rate, kmstress); 334*9ed3d70dSJames Wright KMUnpack(kmstress, stress); 335*9ed3d70dSJames Wright ViscousEnergyFlux(gas, s.Y, grad_s, stress, Fe); 336*9ed3d70dSJames Wright 337*9ed3d70dSJames Wright StateConservative F_inviscid[3]; 338*9ed3d70dSJames Wright FluxInviscid(gas, s, F_inviscid); 339*9ed3d70dSJames Wright 340*9ed3d70dSJames Wright CeedScalar Flux[5]; 341*9ed3d70dSJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 342*9ed3d70dSJames Wright 343*9ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 344*9ed3d70dSJames Wright 345*9ed3d70dSJames Wright // Save values for Jacobian 346*9ed3d70dSJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 347*9ed3d70dSJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 348*9ed3d70dSJames Wright } // End Quadrature Point Loop 349*9ed3d70dSJames Wright return 0; 350*9ed3d70dSJames Wright } 351*9ed3d70dSJames Wright 352*9ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 353*9ed3d70dSJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 354*9ed3d70dSJames Wright } 355*9ed3d70dSJames Wright 356*9ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 357*9ed3d70dSJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 358*9ed3d70dSJames Wright } 359*9ed3d70dSJames Wright 360*9ed3d70dSJames Wright // ***************************************************************************** 361*9ed3d70dSJames Wright // Jacobian for weak-pressure outflow boundary condition 362*9ed3d70dSJames Wright // ***************************************************************************** 363*9ed3d70dSJames Wright CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 364*9ed3d70dSJames Wright StateVariable state_var) { 365*9ed3d70dSJames Wright // Inputs 366*9ed3d70dSJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 367*9ed3d70dSJames Wright const CeedScalar(*Grad_dq) = in[1]; 368*9ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 369*9ed3d70dSJames Wright const CeedScalar(*jac_data_sur) = in[4]; 370*9ed3d70dSJames Wright 371*9ed3d70dSJames Wright // Outputs 372*9ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 373*9ed3d70dSJames Wright 374*9ed3d70dSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 375*9ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 376*9ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 377*9ed3d70dSJames Wright 378*9ed3d70dSJames Wright // Quadrature Point Loop 379*9ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 380*9ed3d70dSJames Wright CeedScalar wdetJb, dXdx[2][3], norm[3]; 381*9ed3d70dSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, norm); 382*9ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 383*9ed3d70dSJames Wright 384*9ed3d70dSJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 385*9ed3d70dSJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 386*9ed3d70dSJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 387*9ed3d70dSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 388*9ed3d70dSJames Wright 389*9ed3d70dSJames Wright State s = StateFromQ(gas, qi, state_var); 390*9ed3d70dSJames Wright State ds = StateFromQ_fwd(gas, s, dqi, state_var); 391*9ed3d70dSJames Wright s.Y.pressure = outflow->pressure; 392*9ed3d70dSJames Wright ds.Y.pressure = 0.; 393*9ed3d70dSJames Wright 394*9ed3d70dSJames Wright State grad_ds[3]; 395*9ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_dq, dXdx, grad_ds); 396*9ed3d70dSJames Wright 397*9ed3d70dSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 398*9ed3d70dSJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 399*9ed3d70dSJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 400*9ed3d70dSJames Wright KMUnpack(dkmstress, dstress); 401*9ed3d70dSJames Wright KMUnpack(kmstress, stress); 402*9ed3d70dSJames Wright ViscousEnergyFlux_fwd(gas, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 403*9ed3d70dSJames Wright 404*9ed3d70dSJames Wright StateConservative dF_inviscid[3]; 405*9ed3d70dSJames Wright FluxInviscid_fwd(gas, s, ds, dF_inviscid); 406*9ed3d70dSJames Wright 407*9ed3d70dSJames Wright CeedScalar dFlux[5]; 408*9ed3d70dSJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 409*9ed3d70dSJames Wright 410*9ed3d70dSJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 411*9ed3d70dSJames Wright } // End Quadrature Point Loop 412*9ed3d70dSJames Wright return 0; 413*9ed3d70dSJames Wright } 414*9ed3d70dSJames Wright 415*9ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 416*9ed3d70dSJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 417*9ed3d70dSJames Wright } 418*9ed3d70dSJames Wright 419*9ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 420*9ed3d70dSJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 421*9ed3d70dSJames Wright } 422