15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors. 29f844368SJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 39f844368SJames Wright // 49f844368SJames Wright // SPDX-License-Identifier: BSD-2-Clause 59f844368SJames Wright // 69f844368SJames Wright // This file is part of CEED: http://github.com/ceed 79f844368SJames Wright 89f844368SJames Wright /// @file 99f844368SJames Wright /// QFunctions for the `bc_freestream` and `bc_outflow` boundary conditions 10*c0b5abf0SJeremy L Thompson #ifndef CEED_RUNNING_JIT_PASS 11*c0b5abf0SJeremy L Thompson #include <stdbool.h> 12*c0b5abf0SJeremy L Thompson #endif 13*c0b5abf0SJeremy L Thompson 149f844368SJames Wright #include "bc_freestream_type.h" 159f844368SJames Wright #include "newtonian_state.h" 169f844368SJames Wright #include "newtonian_types.h" 179f844368SJames Wright #include "riemann_solver.h" 189f844368SJames Wright 199f844368SJames Wright // ***************************************************************************** 209f844368SJames Wright // Freestream Boundary Condition 219f844368SJames Wright // ***************************************************************************** 229f844368SJames Wright CEED_QFUNCTION_HELPER int Freestream(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var, 239f844368SJames Wright RiemannFluxType flux_type) { 24f21e6b1cSJames Wright const FreestreamContext context = (FreestreamContext)ctx; 259f844368SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 269f844368SJames Wright const CeedScalar(*q_data_sur) = in[2]; 279f844368SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 28f21e6b1cSJames Wright CeedScalar(*jac_data_sur) = context->newtonian_ctx.is_implicit ? out[1] : NULL; 299f844368SJames Wright 309f844368SJames Wright const NewtonianIdealGasContext newt_ctx = &context->newtonian_ctx; 319f844368SJames Wright const bool is_implicit = newt_ctx->is_implicit; 329f844368SJames Wright 339f844368SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 349f844368SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 35f21e6b1cSJames Wright const State s = StateFromQ(newt_ctx, qi, state_var); 369f844368SJames Wright 376fa2c4daSJames Wright CeedScalar wdetJb, normal[3]; 386fa2c4daSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, normal); 399f844368SJames Wright wdetJb *= is_implicit ? -1. : 1.; 409f844368SJames Wright 419f844368SJames Wright StateConservative flux; 429f844368SJames Wright switch (flux_type) { 439f844368SJames Wright case RIEMANN_HLL: 446fa2c4daSJames Wright flux = RiemannFlux_HLL(newt_ctx, s, context->S_infty, normal); 459f844368SJames Wright break; 469f844368SJames Wright case RIEMANN_HLLC: 476fa2c4daSJames Wright flux = RiemannFlux_HLLC(newt_ctx, s, context->S_infty, normal); 489f844368SJames Wright break; 499f844368SJames Wright } 509f844368SJames Wright CeedScalar Flux[5]; 519f844368SJames Wright UnpackState_U(flux, Flux); 529f844368SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 539f844368SJames Wright 54f21e6b1cSJames Wright if (is_implicit) { 55f21e6b1cSJames Wright CeedScalar zeros[6] = {0.}; 569f844368SJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 579f844368SJames Wright StoredValuesPack(Q, i, 5, 6, zeros, jac_data_sur); // Every output value must be set 589f844368SJames Wright } 59f21e6b1cSJames Wright } 609f844368SJames Wright return 0; 619f844368SJames Wright } 629f844368SJames Wright 639f844368SJames Wright CEED_QFUNCTION(Freestream_Conserv_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 649f844368SJames Wright return Freestream(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLL); 659f844368SJames Wright } 669f844368SJames Wright 679f844368SJames Wright CEED_QFUNCTION(Freestream_Prim_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 689f844368SJames Wright return Freestream(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLL); 699f844368SJames Wright } 709f844368SJames Wright 71a2d72b6fSJames Wright CEED_QFUNCTION(Freestream_Entropy_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 72a2d72b6fSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLL); 73a2d72b6fSJames Wright } 74a2d72b6fSJames Wright 759f844368SJames Wright CEED_QFUNCTION(Freestream_Conserv_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 769f844368SJames Wright return Freestream(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLLC); 779f844368SJames Wright } 789f844368SJames Wright 799f844368SJames Wright CEED_QFUNCTION(Freestream_Prim_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 809f844368SJames Wright return Freestream(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLLC); 819f844368SJames Wright } 829f844368SJames Wright 83a2d72b6fSJames Wright CEED_QFUNCTION(Freestream_Entropy_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 84a2d72b6fSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLLC); 85a2d72b6fSJames Wright } 86a2d72b6fSJames Wright 879f844368SJames Wright CEED_QFUNCTION_HELPER int Freestream_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var, 889f844368SJames Wright RiemannFluxType flux_type) { 899f844368SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 909f844368SJames Wright const CeedScalar(*q_data_sur) = in[2]; 919f844368SJames Wright const CeedScalar(*jac_data_sur) = in[4]; 929f844368SJames Wright 939f844368SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 949f844368SJames Wright 959f844368SJames Wright const FreestreamContext context = (FreestreamContext)ctx; 969f844368SJames Wright const NewtonianIdealGasContext newt_ctx = &context->newtonian_ctx; 979f844368SJames Wright const bool is_implicit = newt_ctx->is_implicit; 989f844368SJames Wright const State dS_infty = {0}; 999f844368SJames Wright 1009f844368SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 1016fa2c4daSJames Wright CeedScalar wdetJb, normal[3]; 1026fa2c4daSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, normal); 1039f844368SJames Wright wdetJb *= is_implicit ? -1. : 1.; 1049f844368SJames Wright 1059f844368SJames Wright CeedScalar qi[5], dqi[5]; 1069f844368SJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 1079f844368SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 1089f844368SJames Wright State s = StateFromQ(newt_ctx, qi, state_var); 1099f844368SJames Wright State ds = StateFromQ_fwd(newt_ctx, s, dqi, state_var); 1109f844368SJames Wright 1119f844368SJames Wright StateConservative dflux; 1129f844368SJames Wright switch (flux_type) { 1139f844368SJames Wright case RIEMANN_HLL: 1146fa2c4daSJames Wright dflux = RiemannFlux_HLL_fwd(newt_ctx, s, ds, context->S_infty, dS_infty, normal); 1159f844368SJames Wright break; 1169f844368SJames Wright case RIEMANN_HLLC: 1176fa2c4daSJames Wright dflux = RiemannFlux_HLLC_fwd(newt_ctx, s, ds, context->S_infty, dS_infty, normal); 1189f844368SJames Wright break; 1199f844368SJames Wright } 1209f844368SJames Wright CeedScalar dFlux[5]; 1219f844368SJames Wright UnpackState_U(dflux, dFlux); 1229f844368SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 1239f844368SJames Wright } 1249f844368SJames Wright return 0; 1259f844368SJames Wright } 1269f844368SJames Wright 1279f844368SJames Wright CEED_QFUNCTION(Freestream_Jacobian_Conserv_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1289f844368SJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLL); 1299f844368SJames Wright } 1309f844368SJames Wright 1319f844368SJames Wright CEED_QFUNCTION(Freestream_Jacobian_Prim_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1329f844368SJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLL); 1339f844368SJames Wright } 1349f844368SJames Wright 135a2d72b6fSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Entropy_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 136a2d72b6fSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLL); 137a2d72b6fSJames Wright } 138a2d72b6fSJames Wright 1399f844368SJames Wright CEED_QFUNCTION(Freestream_Jacobian_Conserv_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1409f844368SJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLLC); 1419f844368SJames Wright } 1429f844368SJames Wright 1439f844368SJames Wright CEED_QFUNCTION(Freestream_Jacobian_Prim_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1449f844368SJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLLC); 1459f844368SJames Wright } 1469f844368SJames Wright 147a2d72b6fSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Entropy_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 148a2d72b6fSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLLC); 149a2d72b6fSJames Wright } 150a2d72b6fSJames Wright 1519f844368SJames Wright // Note the identity 1529f844368SJames Wright // 1539f844368SJames Wright // softplus(x) - x = log(1 + exp(x)) - x 1549f844368SJames Wright // = log(1 + exp(x)) + log(exp(-x)) 1559f844368SJames Wright // = log((1 + exp(x)) * exp(-x)) 1569f844368SJames Wright // = log(exp(-x) + 1) 1579f844368SJames Wright // = softplus(-x) 1589f844368SJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus(CeedScalar x, CeedScalar width) { 1599f844368SJames Wright if (x > 40 * width) return x; 1609f844368SJames Wright return width * log1p(exp(x / width)); 1619f844368SJames Wright } 1629f844368SJames Wright 1639f844368SJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus_fwd(CeedScalar x, CeedScalar dx, CeedScalar width) { 1649f844368SJames Wright if (x > 40 * width) return 1; 1659f844368SJames Wright const CeedScalar t = exp(x / width); 1669f844368SJames Wright return t / (1 + t); 1679f844368SJames Wright } 1689f844368SJames Wright 1699f844368SJames Wright // Viscous Outflow boundary condition, setting a constant exterior pressure and 1709f844368SJames Wright // temperature as input for a Riemann solve. This condition is stable even in 1719f844368SJames Wright // recirculating flow so long as the exterior temperature is sensible. 1729f844368SJames Wright // 1739f844368SJames Wright // The velocity in the exterior state has optional softplus regularization to 1749f844368SJames Wright // keep it outflow. These parameters have been finnicky in practice and provide 1759f844368SJames Wright // little or no benefit in the tests we've run thus far, thus we recommend 1769f844368SJames Wright // skipping this feature and just allowing recirculation. 1779f844368SJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 178f21e6b1cSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 1799f844368SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 1809f844368SJames Wright const CeedScalar(*Grad_q) = in[1]; 1819f844368SJames Wright const CeedScalar(*q_data_sur) = in[2]; 1829f844368SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 183f21e6b1cSJames Wright CeedScalar(*jac_data_sur) = outflow->gas.is_implicit ? out[1] : NULL; 1849f844368SJames Wright 1859f844368SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 1869f844368SJames Wright const bool is_implicit = gas->is_implicit; 1879f844368SJames Wright 1889f844368SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 1896fa2c4daSJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 1906fa2c4daSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 1919f844368SJames Wright wdetJb *= is_implicit ? -1. : 1.; 1929f844368SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 193f21e6b1cSJames Wright const State s_int = StateFromQ(gas, qi, state_var); 1949f844368SJames Wright 1959f844368SJames Wright StatePrimitive y_ext = s_int.Y; 1969f844368SJames Wright y_ext.pressure = outflow->pressure; 1979f844368SJames Wright y_ext.temperature = outflow->temperature; 1986fa2c4daSJames Wright const CeedScalar u_normal = Dot3(y_ext.velocity, normal); 1999f844368SJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 2009f844368SJames Wright for (CeedInt j = 0; j < 3; j++) { 2016fa2c4daSJames Wright y_ext.velocity[j] += normal[j] * proj; // (I - n n^T) projects into the plane tangent to the normal 2029f844368SJames Wright } 2039f844368SJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 2049f844368SJames Wright 2059f844368SJames Wright State grad_s[3]; 2069f844368SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_q, dXdx, grad_s); 2079f844368SJames Wright 2089f844368SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 2099f844368SJames Wright KMStrainRate_State(grad_s, strain_rate); 2109f844368SJames Wright NewtonianStress(gas, strain_rate, kmstress); 2119f844368SJames Wright KMUnpack(kmstress, stress); 2129f844368SJames Wright ViscousEnergyFlux(gas, s_int.Y, grad_s, stress, Fe); 2139f844368SJames Wright 2146fa2c4daSJames Wright StateConservative F_inviscid_normal = RiemannFlux_HLLC(gas, s_int, s_ext, normal); 2159f844368SJames Wright 2169f844368SJames Wright CeedScalar Flux[5]; 2176fa2c4daSJames Wright FluxTotal_RiemannBoundary(F_inviscid_normal, stress, Fe, normal, Flux); 2189f844368SJames Wright 2199f844368SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 2209f844368SJames Wright 2219f844368SJames Wright // Save values for Jacobian 222f21e6b1cSJames Wright if (is_implicit) { 2239f844368SJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 2249f844368SJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 2259f844368SJames Wright } 226f21e6b1cSJames Wright } 2279f844368SJames Wright return 0; 2289f844368SJames Wright } 2299f844368SJames Wright 2309f844368SJames Wright CEED_QFUNCTION(RiemannOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2319f844368SJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 2329f844368SJames Wright } 2339f844368SJames Wright 2349f844368SJames Wright CEED_QFUNCTION(RiemannOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2359f844368SJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 2369f844368SJames Wright } 2379f844368SJames Wright 238a2d72b6fSJames Wright CEED_QFUNCTION(RiemannOutflow_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 239a2d72b6fSJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_ENTROPY); 240a2d72b6fSJames Wright } 241a2d72b6fSJames Wright 2429f844368SJames Wright // ***************************************************************************** 2439f844368SJames Wright // Jacobian for Riemann pressure/temperature outflow boundary condition 2449f844368SJames Wright // ***************************************************************************** 2459f844368SJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 2469f844368SJames Wright StateVariable state_var) { 2479f844368SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 2489f844368SJames Wright const CeedScalar(*Grad_dq) = in[1]; 2499f844368SJames Wright const CeedScalar(*q_data_sur) = in[2]; 2509f844368SJames Wright const CeedScalar(*jac_data_sur) = in[4]; 2519f844368SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 2529f844368SJames Wright 2539f844368SJames Wright const OutflowContext outflow = (OutflowContext)ctx; 2549f844368SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 2559f844368SJames Wright const bool is_implicit = gas->is_implicit; 2569f844368SJames Wright 2579f844368SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 2586fa2c4daSJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 2596fa2c4daSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 2609f844368SJames Wright wdetJb *= is_implicit ? -1. : 1.; 2619f844368SJames Wright 2629f844368SJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 2639f844368SJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 2649f844368SJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 2659f844368SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 2669f844368SJames Wright 2679f844368SJames Wright State s_int = StateFromQ(gas, qi, state_var); 2689f844368SJames Wright const State ds_int = StateFromQ_fwd(gas, s_int, dqi, state_var); 2699f844368SJames Wright StatePrimitive y_ext = s_int.Y, dy_ext = ds_int.Y; 2709f844368SJames Wright y_ext.pressure = outflow->pressure; 2719f844368SJames Wright y_ext.temperature = outflow->temperature; 2729f844368SJames Wright dy_ext.pressure = 0; 2739f844368SJames Wright dy_ext.temperature = 0; 2746fa2c4daSJames Wright const CeedScalar u_normal = Dot3(s_int.Y.velocity, normal); 2756fa2c4daSJames Wright const CeedScalar du_normal = Dot3(ds_int.Y.velocity, normal); 2769f844368SJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 2779f844368SJames Wright const CeedScalar dproj = (1 - outflow->recirc) * Softplus_fwd(-u_normal, -du_normal, outflow->softplus_velocity); 2789f844368SJames Wright for (CeedInt j = 0; j < 3; j++) { 2796fa2c4daSJames Wright y_ext.velocity[j] += normal[j] * proj; 2806fa2c4daSJames Wright dy_ext.velocity[j] += normal[j] * dproj; 2819f844368SJames Wright } 2829f844368SJames Wright 2839f844368SJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 2849f844368SJames Wright State ds_ext = StateFromPrimitive_fwd(gas, s_ext, dy_ext); 2859f844368SJames Wright 2869f844368SJames Wright State grad_ds[3]; 2879f844368SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_dq, dXdx, grad_ds); 2889f844368SJames Wright 2899f844368SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 2909f844368SJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 2919f844368SJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 2929f844368SJames Wright KMUnpack(dkmstress, dstress); 2939f844368SJames Wright KMUnpack(kmstress, stress); 2949f844368SJames Wright ViscousEnergyFlux_fwd(gas, s_int.Y, ds_int.Y, grad_ds, stress, dstress, dFe); 2959f844368SJames Wright 2966fa2c4daSJames Wright StateConservative dF_inviscid_normal = RiemannFlux_HLLC_fwd(gas, s_int, ds_int, s_ext, ds_ext, normal); 2979f844368SJames Wright 2989f844368SJames Wright CeedScalar dFlux[5]; 2996fa2c4daSJames Wright FluxTotal_RiemannBoundary(dF_inviscid_normal, dstress, dFe, normal, dFlux); 3009f844368SJames Wright 3019f844368SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 302f0b01153SJames Wright } 3039f844368SJames Wright return 0; 3049f844368SJames Wright } 3059f844368SJames Wright 3069f844368SJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3079f844368SJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 3089f844368SJames Wright } 3099f844368SJames Wright 3109f844368SJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3119f844368SJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 3129f844368SJames Wright } 3139f844368SJames Wright 314a2d72b6fSJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 315a2d72b6fSJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY); 316a2d72b6fSJames Wright } 317a2d72b6fSJames Wright 3189f844368SJames Wright // ***************************************************************************** 3199f844368SJames Wright // Outflow boundary condition, weakly setting a constant pressure. This is the 3209f844368SJames Wright // classic outflow condition used by PHASTA-C and retained largely for 3219f844368SJames Wright // comparison. In our experiments, it is never better than RiemannOutflow, and 3229f844368SJames Wright // will crash if outflow ever becomes an inflow, as occurs with strong 3239f844368SJames Wright // acoustics, vortices, etc. 3249f844368SJames Wright // ***************************************************************************** 3259f844368SJames Wright CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 326f21e6b1cSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 3279f844368SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 3289f844368SJames Wright const CeedScalar(*Grad_q) = in[1]; 3299f844368SJames Wright const CeedScalar(*q_data_sur) = in[2]; 3309f844368SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 331f21e6b1cSJames Wright CeedScalar(*jac_data_sur) = outflow->gas.is_implicit ? out[1] : NULL; 3329f844368SJames Wright 3339f844368SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 3349f844368SJames Wright const bool is_implicit = gas->is_implicit; 3359f844368SJames Wright 3369f844368SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 3379f844368SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 3389f844368SJames Wright State s = StateFromQ(gas, qi, state_var); 3399f844368SJames Wright s.Y.pressure = outflow->pressure; 3409f844368SJames Wright 3416fa2c4daSJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 3426fa2c4daSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 3439f844368SJames Wright wdetJb *= is_implicit ? -1. : 1.; 3449f844368SJames Wright 3459f844368SJames Wright State grad_s[3]; 3469f844368SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_q, dXdx, grad_s); 3479f844368SJames Wright 3489f844368SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 3499f844368SJames Wright KMStrainRate_State(grad_s, strain_rate); 3509f844368SJames Wright NewtonianStress(gas, strain_rate, kmstress); 3519f844368SJames Wright KMUnpack(kmstress, stress); 3529f844368SJames Wright ViscousEnergyFlux(gas, s.Y, grad_s, stress, Fe); 3539f844368SJames Wright 3549f844368SJames Wright StateConservative F_inviscid[3]; 3559f844368SJames Wright FluxInviscid(gas, s, F_inviscid); 3569f844368SJames Wright 3579f844368SJames Wright CeedScalar Flux[5]; 3586fa2c4daSJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, normal, Flux); 3599f844368SJames Wright 3609f844368SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 3619f844368SJames Wright 3629f844368SJames Wright // Save values for Jacobian 363f21e6b1cSJames Wright if (is_implicit) { 3649f844368SJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 3659f844368SJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 366f21e6b1cSJames Wright } 367f21e6b1cSJames Wright } 3689f844368SJames Wright return 0; 3699f844368SJames Wright } 3709f844368SJames Wright 3719f844368SJames Wright CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3729f844368SJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 3739f844368SJames Wright } 3749f844368SJames Wright 3759f844368SJames Wright CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3769f844368SJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 3779f844368SJames Wright } 3789f844368SJames Wright 379a2d72b6fSJames Wright CEED_QFUNCTION(PressureOutflow_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 380a2d72b6fSJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_ENTROPY); 381a2d72b6fSJames Wright } 382a2d72b6fSJames Wright 3839f844368SJames Wright // ***************************************************************************** 3849f844368SJames Wright // Jacobian for weak-pressure outflow boundary condition 3859f844368SJames Wright // ***************************************************************************** 3869f844368SJames Wright CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 3879f844368SJames Wright StateVariable state_var) { 3889f844368SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 3899f844368SJames Wright const CeedScalar(*Grad_dq) = in[1]; 3909f844368SJames Wright const CeedScalar(*q_data_sur) = in[2]; 3919f844368SJames Wright const CeedScalar(*jac_data_sur) = in[4]; 3929f844368SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 3939f844368SJames Wright 3949f844368SJames Wright const OutflowContext outflow = (OutflowContext)ctx; 3959f844368SJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 3969f844368SJames Wright const bool is_implicit = gas->is_implicit; 3979f844368SJames Wright 3989f844368SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 3996fa2c4daSJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 4006fa2c4daSJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 4019f844368SJames Wright wdetJb *= is_implicit ? -1. : 1.; 4029f844368SJames Wright 4039f844368SJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 4049f844368SJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 4059f844368SJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 4069f844368SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 4079f844368SJames Wright 4089f844368SJames Wright State s = StateFromQ(gas, qi, state_var); 4099f844368SJames Wright State ds = StateFromQ_fwd(gas, s, dqi, state_var); 4109f844368SJames Wright s.Y.pressure = outflow->pressure; 4119f844368SJames Wright ds.Y.pressure = 0.; 4129f844368SJames Wright 4139f844368SJames Wright State grad_ds[3]; 4149f844368SJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_dq, dXdx, grad_ds); 4159f844368SJames Wright 4169f844368SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 4179f844368SJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 4189f844368SJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 4199f844368SJames Wright KMUnpack(dkmstress, dstress); 4209f844368SJames Wright KMUnpack(kmstress, stress); 4219f844368SJames Wright ViscousEnergyFlux_fwd(gas, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 4229f844368SJames Wright 4239f844368SJames Wright StateConservative dF_inviscid[3]; 4249f844368SJames Wright FluxInviscid_fwd(gas, s, ds, dF_inviscid); 4259f844368SJames Wright 4269f844368SJames Wright CeedScalar dFlux[5]; 4276fa2c4daSJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, normal, dFlux); 4289f844368SJames Wright 4299f844368SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 430f0b01153SJames Wright } 4319f844368SJames Wright return 0; 4329f844368SJames Wright } 4339f844368SJames Wright 4349f844368SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4359f844368SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 4369f844368SJames Wright } 4379f844368SJames Wright 4389f844368SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4399f844368SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 4409f844368SJames Wright } 441a2d72b6fSJames Wright 442a2d72b6fSJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 443a2d72b6fSJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY); 444a2d72b6fSJames Wright } 445