1dc936754SJeremy L Thompson // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors. 29ed3d70dSJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 39ed3d70dSJames Wright // 49ed3d70dSJames Wright // SPDX-License-Identifier: BSD-2-Clause 59ed3d70dSJames Wright // 69ed3d70dSJames Wright // This file is part of CEED: http://github.com/ceed 79ed3d70dSJames Wright 89ed3d70dSJames Wright /// @file 99ed3d70dSJames Wright /// QFunctions for the `bc_freestream` and `bc_outflow` boundary conditions 109ed3d70dSJames Wright #include "bc_freestream_type.h" 119ed3d70dSJames Wright #include "newtonian_state.h" 129ed3d70dSJames Wright #include "newtonian_types.h" 139ed3d70dSJames Wright #include "riemann_solver.h" 149ed3d70dSJames Wright 159ed3d70dSJames Wright // ***************************************************************************** 169ed3d70dSJames Wright // Freestream Boundary Condition 179ed3d70dSJames Wright // ***************************************************************************** 189ed3d70dSJames Wright CEED_QFUNCTION_HELPER int Freestream(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var, 199ed3d70dSJames Wright RiemannFluxType flux_type) { 204b96a86bSJames Wright const FreestreamContext context = (FreestreamContext)ctx; 219ed3d70dSJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 229ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 239ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 244b96a86bSJames Wright CeedScalar(*jac_data_sur) = context->newtonian_ctx.is_implicit ? out[1] : NULL; 259ed3d70dSJames Wright 269ed3d70dSJames Wright const NewtonianIdealGasContext newt_ctx = &context->newtonian_ctx; 279ed3d70dSJames Wright const bool is_implicit = newt_ctx->is_implicit; 289ed3d70dSJames Wright 299ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 309ed3d70dSJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 314b96a86bSJames Wright const State s = StateFromQ(newt_ctx, qi, state_var); 329ed3d70dSJames Wright 33*feb491a7SJames Wright CeedScalar wdetJb, normal[3]; 34*feb491a7SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, normal); 359ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 369ed3d70dSJames Wright 379ed3d70dSJames Wright StateConservative flux; 389ed3d70dSJames Wright switch (flux_type) { 399ed3d70dSJames Wright case RIEMANN_HLL: 40*feb491a7SJames Wright flux = RiemannFlux_HLL(newt_ctx, s, context->S_infty, normal); 419ed3d70dSJames Wright break; 429ed3d70dSJames Wright case RIEMANN_HLLC: 43*feb491a7SJames Wright flux = RiemannFlux_HLLC(newt_ctx, s, context->S_infty, normal); 449ed3d70dSJames Wright break; 459ed3d70dSJames Wright } 469ed3d70dSJames Wright CeedScalar Flux[5]; 479ed3d70dSJames Wright UnpackState_U(flux, Flux); 489ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 499ed3d70dSJames Wright 504b96a86bSJames Wright if (is_implicit) { 514b96a86bSJames Wright CeedScalar zeros[6] = {0.}; 529ed3d70dSJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 539ed3d70dSJames Wright StoredValuesPack(Q, i, 5, 6, zeros, jac_data_sur); // Every output value must be set 549ed3d70dSJames Wright } 554b96a86bSJames Wright } 569ed3d70dSJames Wright return 0; 579ed3d70dSJames Wright } 589ed3d70dSJames Wright 599ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Conserv_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 609ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLL); 619ed3d70dSJames Wright } 629ed3d70dSJames Wright 639ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Prim_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 649ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLL); 659ed3d70dSJames Wright } 669ed3d70dSJames Wright 679b103f75SJames Wright CEED_QFUNCTION(Freestream_Entropy_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 689b103f75SJames Wright return Freestream(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLL); 699b103f75SJames Wright } 709b103f75SJames Wright 719ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Conserv_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 729ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLLC); 739ed3d70dSJames Wright } 749ed3d70dSJames Wright 759ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Prim_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 769ed3d70dSJames Wright return Freestream(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLLC); 779ed3d70dSJames Wright } 789ed3d70dSJames Wright 799b103f75SJames Wright CEED_QFUNCTION(Freestream_Entropy_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 809b103f75SJames Wright return Freestream(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLLC); 819b103f75SJames Wright } 829b103f75SJames Wright 839ed3d70dSJames Wright CEED_QFUNCTION_HELPER int Freestream_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var, 849ed3d70dSJames Wright RiemannFluxType flux_type) { 859ed3d70dSJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 869ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 879ed3d70dSJames Wright const CeedScalar(*jac_data_sur) = in[4]; 889ed3d70dSJames Wright 899ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 909ed3d70dSJames Wright 919ed3d70dSJames Wright const FreestreamContext context = (FreestreamContext)ctx; 929ed3d70dSJames Wright const NewtonianIdealGasContext newt_ctx = &context->newtonian_ctx; 939ed3d70dSJames Wright const bool is_implicit = newt_ctx->is_implicit; 949ed3d70dSJames Wright const State dS_infty = {0}; 959ed3d70dSJames Wright 969ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 97*feb491a7SJames Wright CeedScalar wdetJb, normal[3]; 98*feb491a7SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, normal); 999ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 1009ed3d70dSJames Wright 1019ed3d70dSJames Wright CeedScalar qi[5], dqi[5]; 1029ed3d70dSJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 1039ed3d70dSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 1049ed3d70dSJames Wright State s = StateFromQ(newt_ctx, qi, state_var); 1059ed3d70dSJames Wright State ds = StateFromQ_fwd(newt_ctx, s, dqi, state_var); 1069ed3d70dSJames Wright 1079ed3d70dSJames Wright StateConservative dflux; 1089ed3d70dSJames Wright switch (flux_type) { 1099ed3d70dSJames Wright case RIEMANN_HLL: 110*feb491a7SJames Wright dflux = RiemannFlux_HLL_fwd(newt_ctx, s, ds, context->S_infty, dS_infty, normal); 1119ed3d70dSJames Wright break; 1129ed3d70dSJames Wright case RIEMANN_HLLC: 113*feb491a7SJames Wright dflux = RiemannFlux_HLLC_fwd(newt_ctx, s, ds, context->S_infty, dS_infty, normal); 1149ed3d70dSJames Wright break; 1159ed3d70dSJames Wright } 1169ed3d70dSJames Wright CeedScalar dFlux[5]; 1179ed3d70dSJames Wright UnpackState_U(dflux, dFlux); 1189ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 1199ed3d70dSJames Wright } 1209ed3d70dSJames Wright return 0; 1219ed3d70dSJames Wright } 1229ed3d70dSJames Wright 1239ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Conserv_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1249ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLL); 1259ed3d70dSJames Wright } 1269ed3d70dSJames Wright 1279ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Prim_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1289ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLL); 1299ed3d70dSJames Wright } 1309ed3d70dSJames Wright 1319b103f75SJames Wright CEED_QFUNCTION(Freestream_Jacobian_Entropy_HLL)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1329b103f75SJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLL); 1339b103f75SJames Wright } 1349b103f75SJames Wright 1359ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Conserv_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1369ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE, RIEMANN_HLLC); 1379ed3d70dSJames Wright } 1389ed3d70dSJames Wright 1399ed3d70dSJames Wright CEED_QFUNCTION(Freestream_Jacobian_Prim_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1409ed3d70dSJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE, RIEMANN_HLLC); 1419ed3d70dSJames Wright } 1429ed3d70dSJames Wright 1439b103f75SJames Wright CEED_QFUNCTION(Freestream_Jacobian_Entropy_HLLC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1449b103f75SJames Wright return Freestream_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY, RIEMANN_HLLC); 1459b103f75SJames Wright } 1469b103f75SJames Wright 1479ed3d70dSJames Wright // Note the identity 1489ed3d70dSJames Wright // 1499ed3d70dSJames Wright // softplus(x) - x = log(1 + exp(x)) - x 1509ed3d70dSJames Wright // = log(1 + exp(x)) + log(exp(-x)) 1519ed3d70dSJames Wright // = log((1 + exp(x)) * exp(-x)) 1529ed3d70dSJames Wright // = log(exp(-x) + 1) 1539ed3d70dSJames Wright // = softplus(-x) 1549ed3d70dSJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus(CeedScalar x, CeedScalar width) { 1559ed3d70dSJames Wright if (x > 40 * width) return x; 1569ed3d70dSJames Wright return width * log1p(exp(x / width)); 1579ed3d70dSJames Wright } 1589ed3d70dSJames Wright 1599ed3d70dSJames Wright CEED_QFUNCTION_HELPER CeedScalar Softplus_fwd(CeedScalar x, CeedScalar dx, CeedScalar width) { 1609ed3d70dSJames Wright if (x > 40 * width) return 1; 1619ed3d70dSJames Wright const CeedScalar t = exp(x / width); 1629ed3d70dSJames Wright return t / (1 + t); 1639ed3d70dSJames Wright } 1649ed3d70dSJames Wright 1659ed3d70dSJames Wright // Viscous Outflow boundary condition, setting a constant exterior pressure and 1669ed3d70dSJames Wright // temperature as input for a Riemann solve. This condition is stable even in 1679ed3d70dSJames Wright // recirculating flow so long as the exterior temperature is sensible. 1689ed3d70dSJames Wright // 1699ed3d70dSJames Wright // The velocity in the exterior state has optional softplus regularization to 1709ed3d70dSJames Wright // keep it outflow. These parameters have been finnicky in practice and provide 1719ed3d70dSJames Wright // little or no benefit in the tests we've run thus far, thus we recommend 1729ed3d70dSJames Wright // skipping this feature and just allowing recirculation. 1739ed3d70dSJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 1744b96a86bSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 1759ed3d70dSJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 1769ed3d70dSJames Wright const CeedScalar(*Grad_q) = in[1]; 1779ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 1789ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 1794b96a86bSJames Wright CeedScalar(*jac_data_sur) = outflow->gas.is_implicit ? out[1] : NULL; 1809ed3d70dSJames Wright 1819ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 1829ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 1839ed3d70dSJames Wright 1849ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 185*feb491a7SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 186*feb491a7SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 1879ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 1889ed3d70dSJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 1894b96a86bSJames Wright const State s_int = StateFromQ(gas, qi, state_var); 1909ed3d70dSJames Wright 1919ed3d70dSJames Wright StatePrimitive y_ext = s_int.Y; 1929ed3d70dSJames Wright y_ext.pressure = outflow->pressure; 1939ed3d70dSJames Wright y_ext.temperature = outflow->temperature; 194*feb491a7SJames Wright const CeedScalar u_normal = Dot3(y_ext.velocity, normal); 1959ed3d70dSJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 1969ed3d70dSJames Wright for (CeedInt j = 0; j < 3; j++) { 197*feb491a7SJames Wright y_ext.velocity[j] += normal[j] * proj; // (I - n n^T) projects into the plane tangent to the normal 1989ed3d70dSJames Wright } 1999ed3d70dSJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 2009ed3d70dSJames Wright 2019ed3d70dSJames Wright State grad_s[3]; 2029ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_q, dXdx, grad_s); 2039ed3d70dSJames Wright 2049ed3d70dSJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 2059ed3d70dSJames Wright KMStrainRate_State(grad_s, strain_rate); 2069ed3d70dSJames Wright NewtonianStress(gas, strain_rate, kmstress); 2079ed3d70dSJames Wright KMUnpack(kmstress, stress); 2089ed3d70dSJames Wright ViscousEnergyFlux(gas, s_int.Y, grad_s, stress, Fe); 2099ed3d70dSJames Wright 210*feb491a7SJames Wright StateConservative F_inviscid_normal = RiemannFlux_HLLC(gas, s_int, s_ext, normal); 2119ed3d70dSJames Wright 2129ed3d70dSJames Wright CeedScalar Flux[5]; 213*feb491a7SJames Wright FluxTotal_RiemannBoundary(F_inviscid_normal, stress, Fe, normal, Flux); 2149ed3d70dSJames Wright 2159ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 2169ed3d70dSJames Wright 2179ed3d70dSJames Wright // Save values for Jacobian 2184b96a86bSJames Wright if (is_implicit) { 2199ed3d70dSJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 2209ed3d70dSJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 2219ed3d70dSJames Wright } 2224b96a86bSJames Wright } 2239ed3d70dSJames Wright return 0; 2249ed3d70dSJames Wright } 2259ed3d70dSJames Wright 2269ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2279ed3d70dSJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 2289ed3d70dSJames Wright } 2299ed3d70dSJames Wright 2309ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2319ed3d70dSJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 2329ed3d70dSJames Wright } 2339ed3d70dSJames Wright 2349b103f75SJames Wright CEED_QFUNCTION(RiemannOutflow_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2359b103f75SJames Wright return RiemannOutflow(ctx, Q, in, out, STATEVAR_ENTROPY); 2369b103f75SJames Wright } 2379b103f75SJames Wright 2389ed3d70dSJames Wright // ***************************************************************************** 2399ed3d70dSJames Wright // Jacobian for Riemann pressure/temperature outflow boundary condition 2409ed3d70dSJames Wright // ***************************************************************************** 2419ed3d70dSJames Wright CEED_QFUNCTION_HELPER int RiemannOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 2429ed3d70dSJames Wright StateVariable state_var) { 2439ed3d70dSJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 2449ed3d70dSJames Wright const CeedScalar(*Grad_dq) = in[1]; 2459ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 2469ed3d70dSJames Wright const CeedScalar(*jac_data_sur) = in[4]; 2479ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 2489ed3d70dSJames Wright 2499ed3d70dSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 2509ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 2519ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 2529ed3d70dSJames Wright 2539ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 254*feb491a7SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 255*feb491a7SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 2569ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 2579ed3d70dSJames Wright 2589ed3d70dSJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 2599ed3d70dSJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 2609ed3d70dSJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 2619ed3d70dSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 2629ed3d70dSJames Wright 2639ed3d70dSJames Wright State s_int = StateFromQ(gas, qi, state_var); 2649ed3d70dSJames Wright const State ds_int = StateFromQ_fwd(gas, s_int, dqi, state_var); 2659ed3d70dSJames Wright StatePrimitive y_ext = s_int.Y, dy_ext = ds_int.Y; 2669ed3d70dSJames Wright y_ext.pressure = outflow->pressure; 2679ed3d70dSJames Wright y_ext.temperature = outflow->temperature; 2689ed3d70dSJames Wright dy_ext.pressure = 0; 2699ed3d70dSJames Wright dy_ext.temperature = 0; 270*feb491a7SJames Wright const CeedScalar u_normal = Dot3(s_int.Y.velocity, normal); 271*feb491a7SJames Wright const CeedScalar du_normal = Dot3(ds_int.Y.velocity, normal); 2729ed3d70dSJames Wright const CeedScalar proj = (1 - outflow->recirc) * Softplus(-u_normal, outflow->softplus_velocity); 2739ed3d70dSJames Wright const CeedScalar dproj = (1 - outflow->recirc) * Softplus_fwd(-u_normal, -du_normal, outflow->softplus_velocity); 2749ed3d70dSJames Wright for (CeedInt j = 0; j < 3; j++) { 275*feb491a7SJames Wright y_ext.velocity[j] += normal[j] * proj; 276*feb491a7SJames Wright dy_ext.velocity[j] += normal[j] * dproj; 2779ed3d70dSJames Wright } 2789ed3d70dSJames Wright 2799ed3d70dSJames Wright State s_ext = StateFromPrimitive(gas, y_ext); 2809ed3d70dSJames Wright State ds_ext = StateFromPrimitive_fwd(gas, s_ext, dy_ext); 2819ed3d70dSJames Wright 2829ed3d70dSJames Wright State grad_ds[3]; 2839ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s_int, state_var, Grad_dq, dXdx, grad_ds); 2849ed3d70dSJames Wright 2859ed3d70dSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 2869ed3d70dSJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 2879ed3d70dSJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 2889ed3d70dSJames Wright KMUnpack(dkmstress, dstress); 2899ed3d70dSJames Wright KMUnpack(kmstress, stress); 2909ed3d70dSJames Wright ViscousEnergyFlux_fwd(gas, s_int.Y, ds_int.Y, grad_ds, stress, dstress, dFe); 2919ed3d70dSJames Wright 292*feb491a7SJames Wright StateConservative dF_inviscid_normal = RiemannFlux_HLLC_fwd(gas, s_int, ds_int, s_ext, ds_ext, normal); 2939ed3d70dSJames Wright 2949ed3d70dSJames Wright CeedScalar dFlux[5]; 295*feb491a7SJames Wright FluxTotal_RiemannBoundary(dF_inviscid_normal, dstress, dFe, normal, dFlux); 2969ed3d70dSJames Wright 2979ed3d70dSJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 298b193fadcSJames Wright } 2999ed3d70dSJames Wright return 0; 3009ed3d70dSJames Wright } 3019ed3d70dSJames Wright 3029ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3039ed3d70dSJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 3049ed3d70dSJames Wright } 3059ed3d70dSJames Wright 3069ed3d70dSJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3079ed3d70dSJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 3089ed3d70dSJames Wright } 3099ed3d70dSJames Wright 3109b103f75SJames Wright CEED_QFUNCTION(RiemannOutflow_Jacobian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3119b103f75SJames Wright return RiemannOutflow_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY); 3129b103f75SJames Wright } 3139b103f75SJames Wright 3149ed3d70dSJames Wright // ***************************************************************************** 3159ed3d70dSJames Wright // Outflow boundary condition, weakly setting a constant pressure. This is the 3169ed3d70dSJames Wright // classic outflow condition used by PHASTA-C and retained largely for 3179ed3d70dSJames Wright // comparison. In our experiments, it is never better than RiemannOutflow, and 3189ed3d70dSJames Wright // will crash if outflow ever becomes an inflow, as occurs with strong 3199ed3d70dSJames Wright // acoustics, vortices, etc. 3209ed3d70dSJames Wright // ***************************************************************************** 3219ed3d70dSJames Wright CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 3224b96a86bSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 3239ed3d70dSJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 3249ed3d70dSJames Wright const CeedScalar(*Grad_q) = in[1]; 3259ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 3269ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 3274b96a86bSJames Wright CeedScalar(*jac_data_sur) = outflow->gas.is_implicit ? out[1] : NULL; 3289ed3d70dSJames Wright 3299ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 3309ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 3319ed3d70dSJames Wright 3329ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 3339ed3d70dSJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 3349ed3d70dSJames Wright State s = StateFromQ(gas, qi, state_var); 3359ed3d70dSJames Wright s.Y.pressure = outflow->pressure; 3369ed3d70dSJames Wright 337*feb491a7SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 338*feb491a7SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 3399ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 3409ed3d70dSJames Wright 3419ed3d70dSJames Wright State grad_s[3]; 3429ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_q, dXdx, grad_s); 3439ed3d70dSJames Wright 3449ed3d70dSJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 3459ed3d70dSJames Wright KMStrainRate_State(grad_s, strain_rate); 3469ed3d70dSJames Wright NewtonianStress(gas, strain_rate, kmstress); 3479ed3d70dSJames Wright KMUnpack(kmstress, stress); 3489ed3d70dSJames Wright ViscousEnergyFlux(gas, s.Y, grad_s, stress, Fe); 3499ed3d70dSJames Wright 3509ed3d70dSJames Wright StateConservative F_inviscid[3]; 3519ed3d70dSJames Wright FluxInviscid(gas, s, F_inviscid); 3529ed3d70dSJames Wright 3539ed3d70dSJames Wright CeedScalar Flux[5]; 354*feb491a7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, normal, Flux); 3559ed3d70dSJames Wright 3569ed3d70dSJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 3579ed3d70dSJames Wright 3589ed3d70dSJames Wright // Save values for Jacobian 3594b96a86bSJames Wright if (is_implicit) { 3609ed3d70dSJames Wright StoredValuesPack(Q, i, 0, 5, qi, jac_data_sur); 3619ed3d70dSJames Wright StoredValuesPack(Q, i, 5, 6, kmstress, jac_data_sur); 3624b96a86bSJames Wright } 3634b96a86bSJames Wright } 3649ed3d70dSJames Wright return 0; 3659ed3d70dSJames Wright } 3669ed3d70dSJames Wright 3679ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3689ed3d70dSJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 3699ed3d70dSJames Wright } 3709ed3d70dSJames Wright 3719ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3729ed3d70dSJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_PRIMITIVE); 3739ed3d70dSJames Wright } 3749ed3d70dSJames Wright 3759b103f75SJames Wright CEED_QFUNCTION(PressureOutflow_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3769b103f75SJames Wright return PressureOutflow(ctx, Q, in, out, STATEVAR_ENTROPY); 3779b103f75SJames Wright } 3789b103f75SJames Wright 3799ed3d70dSJames Wright // ***************************************************************************** 3809ed3d70dSJames Wright // Jacobian for weak-pressure outflow boundary condition 3819ed3d70dSJames Wright // ***************************************************************************** 3829ed3d70dSJames Wright CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 3839ed3d70dSJames Wright StateVariable state_var) { 3849ed3d70dSJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 3859ed3d70dSJames Wright const CeedScalar(*Grad_dq) = in[1]; 3869ed3d70dSJames Wright const CeedScalar(*q_data_sur) = in[2]; 3879ed3d70dSJames Wright const CeedScalar(*jac_data_sur) = in[4]; 3889ed3d70dSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 3899ed3d70dSJames Wright 3909ed3d70dSJames Wright const OutflowContext outflow = (OutflowContext)ctx; 3919ed3d70dSJames Wright const NewtonianIdealGasContext gas = &outflow->gas; 3929ed3d70dSJames Wright const bool is_implicit = gas->is_implicit; 3939ed3d70dSJames Wright 3949ed3d70dSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 395*feb491a7SJames Wright CeedScalar wdetJb, dXdx[2][3], normal[3]; 396*feb491a7SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, dXdx, normal); 3979ed3d70dSJames Wright wdetJb *= is_implicit ? -1. : 1.; 3989ed3d70dSJames Wright 3999ed3d70dSJames Wright CeedScalar qi[5], kmstress[6], dqi[5]; 4009ed3d70dSJames Wright StoredValuesUnpack(Q, i, 0, 5, jac_data_sur, qi); 4019ed3d70dSJames Wright StoredValuesUnpack(Q, i, 5, 6, jac_data_sur, kmstress); 4029ed3d70dSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 4039ed3d70dSJames Wright 4049ed3d70dSJames Wright State s = StateFromQ(gas, qi, state_var); 4059ed3d70dSJames Wright State ds = StateFromQ_fwd(gas, s, dqi, state_var); 4069ed3d70dSJames Wright s.Y.pressure = outflow->pressure; 4079ed3d70dSJames Wright ds.Y.pressure = 0.; 4089ed3d70dSJames Wright 4099ed3d70dSJames Wright State grad_ds[3]; 4109ed3d70dSJames Wright StatePhysicalGradientFromReference_Boundary(Q, i, gas, s, state_var, Grad_dq, dXdx, grad_ds); 4119ed3d70dSJames Wright 4129ed3d70dSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 4139ed3d70dSJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 4149ed3d70dSJames Wright NewtonianStress(gas, dstrain_rate, dkmstress); 4159ed3d70dSJames Wright KMUnpack(dkmstress, dstress); 4169ed3d70dSJames Wright KMUnpack(kmstress, stress); 4179ed3d70dSJames Wright ViscousEnergyFlux_fwd(gas, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 4189ed3d70dSJames Wright 4199ed3d70dSJames Wright StateConservative dF_inviscid[3]; 4209ed3d70dSJames Wright FluxInviscid_fwd(gas, s, ds, dF_inviscid); 4219ed3d70dSJames Wright 4229ed3d70dSJames Wright CeedScalar dFlux[5]; 423*feb491a7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, normal, dFlux); 4249ed3d70dSJames Wright 4259ed3d70dSJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 426b193fadcSJames Wright } 4279ed3d70dSJames Wright return 0; 4289ed3d70dSJames Wright } 4299ed3d70dSJames Wright 4309ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4319ed3d70dSJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 4329ed3d70dSJames Wright } 4339ed3d70dSJames Wright 4349ed3d70dSJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4359ed3d70dSJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_PRIMITIVE); 4369ed3d70dSJames Wright } 4379b103f75SJames Wright 4389b103f75SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4399b103f75SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, STATEVAR_ENTROPY); 4409b103f75SJames Wright } 441