1*9ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, 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
10c0b5abf0SJeremy L Thompson #ifndef CEED_RUNNING_JIT_PASS
11c0b5abf0SJeremy L Thompson #include <stdbool.h>
12c0b5abf0SJeremy L Thompson #endif
13c0b5abf0SJeremy 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 // *****************************************************************************
Freestream(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,StateVariable state_var,RiemannFluxType flux_type)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
Freestream_Conserv_HLL(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Prim_HLL(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Entropy_HLL(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Conserv_HLLC(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Prim_HLLC(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Entropy_HLLC(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Jacobian(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,StateVariable state_var,RiemannFluxType flux_type)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
Freestream_Jacobian_Conserv_HLL(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Jacobian_Prim_HLL(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Jacobian_Entropy_HLL(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Jacobian_Conserv_HLLC(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Jacobian_Prim_HLLC(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
Freestream_Jacobian_Entropy_HLLC(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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)
Softplus(CeedScalar x,CeedScalar width)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
Softplus_fwd(CeedScalar x,CeedScalar dx,CeedScalar width)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.
RiemannOutflow(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,StateVariable state_var)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
RiemannOutflow_Conserv(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
RiemannOutflow_Prim(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
RiemannOutflow_Entropy(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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 // *****************************************************************************
RiemannOutflow_Jacobian(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,StateVariable state_var)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
RiemannOutflow_Jacobian_Conserv(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
RiemannOutflow_Jacobian_Prim(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
RiemannOutflow_Jacobian_Entropy(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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 // *****************************************************************************
PressureOutflow(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,StateVariable state_var)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
PressureOutflow_Conserv(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
PressureOutflow_Prim(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
PressureOutflow_Entropy(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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 // *****************************************************************************
PressureOutflow_Jacobian(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,StateVariable state_var)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
PressureOutflow_Jacobian_Conserv(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
PressureOutflow_Jacobian_Prim(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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
PressureOutflow_Jacobian_Entropy(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)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