13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 388b783a1SJames Wright // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 588b783a1SJames Wright // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 788b783a1SJames Wright 888b783a1SJames Wright /// @file 988b783a1SJames Wright /// Operator for Navier-Stokes example using PETSc 1088b783a1SJames Wright 1188b783a1SJames Wright #ifndef newtonian_h 1288b783a1SJames Wright #define newtonian_h 1388b783a1SJames Wright 1488b783a1SJames Wright #include <ceed.h> 15c9c2c079SJeremy L Thompson #include <math.h> 16738af36cSAdelekeBankole #include <stdlib.h> 172b730f8bSJeremy L Thompson 18c6e8c570SJames Wright #include "newtonian_state.h" 19c9c2c079SJeremy L Thompson #include "newtonian_types.h" 202b89d87eSLeila Ghaffari #include "stabilization.h" 21c9c2c079SJeremy L Thompson #include "utils.h" 2288626eedSJames Wright 2388626eedSJames Wright // ***************************************************************************** 2488b783a1SJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems 2588b783a1SJames Wright // ***************************************************************************** 262b730f8bSJeremy L Thompson CEED_QFUNCTION(ICsNewtonianIG)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2788b783a1SJames Wright // Inputs 2888b783a1SJames Wright const CeedScalar(*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 2988b783a1SJames Wright 3088b783a1SJames Wright // Outputs 3188b783a1SJames Wright CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 3288b783a1SJames Wright 3388626eedSJames Wright // Context 3488626eedSJames Wright const SetupContext context = (SetupContext)ctx; 3588626eedSJames Wright const CeedScalar theta0 = context->theta0; 3688626eedSJames Wright const CeedScalar P0 = context->P0; 3788626eedSJames Wright const CeedScalar cv = context->cv; 3888626eedSJames Wright const CeedScalar cp = context->cp; 3988626eedSJames Wright const CeedScalar *g = context->g; 4088626eedSJames Wright const CeedScalar Rd = cp - cv; 4188626eedSJames Wright 4288b783a1SJames Wright // Quadrature Point Loop 432b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 4488b783a1SJames Wright CeedScalar q[5] = {0.}; 4588b783a1SJames Wright 4688b783a1SJames Wright // Setup 4788b783a1SJames Wright // -- Coordinates 4888626eedSJames Wright const CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]}; 492b89d87eSLeila Ghaffari const CeedScalar e_potential = -Dot3(g, x); 5088b783a1SJames Wright 5188b783a1SJames Wright // -- Density 5288626eedSJames Wright const CeedScalar rho = P0 / (Rd * theta0); 5388b783a1SJames Wright 5488b783a1SJames Wright // Initial Conditions 5588b783a1SJames Wright q[0] = rho; 5688b783a1SJames Wright q[1] = 0.0; 5788b783a1SJames Wright q[2] = 0.0; 5888b783a1SJames Wright q[3] = 0.0; 5988626eedSJames Wright q[4] = rho * (cv * theta0 + e_potential); 6088b783a1SJames Wright 612b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 622b89d87eSLeila Ghaffari 6388b783a1SJames Wright } // End of Quadrature Point Loop 6488b783a1SJames Wright return 0; 6588b783a1SJames Wright } 6688b783a1SJames Wright 6788b783a1SJames Wright // ***************************************************************************** 68*ea61e9acSJeremy L Thompson // This QFunction sets a "still" initial condition for generic Newtonian IG problems in primitive variables 69dc805cc4SLeila Ghaffari // ***************************************************************************** 702b730f8bSJeremy L Thompson CEED_QFUNCTION(ICsNewtonianIG_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 71dc805cc4SLeila Ghaffari // Outputs 72dc805cc4SLeila Ghaffari CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 73dc805cc4SLeila Ghaffari 74dc805cc4SLeila Ghaffari // Context 75dc805cc4SLeila Ghaffari const SetupContext context = (SetupContext)ctx; 76dc805cc4SLeila Ghaffari const CeedScalar theta0 = context->theta0; 77dc805cc4SLeila Ghaffari const CeedScalar P0 = context->P0; 78dc805cc4SLeila Ghaffari 79dc805cc4SLeila Ghaffari // Quadrature Point Loop 802b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 81dc805cc4SLeila Ghaffari CeedScalar q[5] = {0.}; 82dc805cc4SLeila Ghaffari 83dc805cc4SLeila Ghaffari // Initial Conditions 84dc805cc4SLeila Ghaffari q[0] = P0; 85dc805cc4SLeila Ghaffari q[1] = 0.0; 86dc805cc4SLeila Ghaffari q[2] = 0.0; 87dc805cc4SLeila Ghaffari q[3] = 0.0; 88dc805cc4SLeila Ghaffari q[4] = theta0; 89dc805cc4SLeila Ghaffari 902b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 91dc805cc4SLeila Ghaffari 92dc805cc4SLeila Ghaffari } // End of Quadrature Point Loop 93dc805cc4SLeila Ghaffari return 0; 94dc805cc4SLeila Ghaffari } 95dc805cc4SLeila Ghaffari 96dc805cc4SLeila Ghaffari // ***************************************************************************** 97*ea61e9acSJeremy L Thompson // This QFunction implements the following formulation of Navier-Stokes with explicit time stepping method 9888b783a1SJames Wright // 99*ea61e9acSJeremy L Thompson // This is 3D compressible Navier-Stokes in conservation form with state variables of density, momentum density, and total energy density. 10088b783a1SJames Wright // 10188b783a1SJames Wright // State Variables: q = ( rho, U1, U2, U3, E ) 10288b783a1SJames Wright // rho - Mass Density 10388b783a1SJames Wright // Ui - Momentum Density, Ui = rho ui 10488b783a1SJames Wright // E - Total Energy Density, E = rho (cv T + (u u)/2 + g z) 10588b783a1SJames Wright // 10688b783a1SJames Wright // Navier-Stokes Equations: 10788b783a1SJames Wright // drho/dt + div( U ) = 0 10888b783a1SJames Wright // dU/dt + div( rho (u x u) + P I3 ) + rho g khat = div( Fu ) 10988b783a1SJames Wright // dE/dt + div( (E + P) u ) = div( Fe ) 11088b783a1SJames Wright // 11188b783a1SJames Wright // Viscous Stress: 11288b783a1SJames Wright // Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3) 11388b783a1SJames Wright // 11488b783a1SJames Wright // Thermal Stress: 11588b783a1SJames Wright // Fe = u Fu + k grad( T ) 11688626eedSJames Wright // Equation of State 11788b783a1SJames Wright // P = (gamma - 1) (E - rho (u u) / 2 - rho g z) 11888b783a1SJames Wright // 11988b783a1SJames Wright // Stabilization: 12088b783a1SJames Wright // Tau = diag(TauC, TauM, TauM, TauM, TauE) 12188b783a1SJames Wright // f1 = rho sqrt(ui uj gij) 12288b783a1SJames Wright // gij = dXi/dX * dXi/dX 12388b783a1SJames Wright // TauC = Cc f1 / (8 gii) 12488b783a1SJames Wright // TauM = min( 1 , 1 / f1 ) 12588b783a1SJames Wright // TauE = TauM / (Ce cv) 12688b783a1SJames Wright // 12788b783a1SJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 12888b783a1SJames Wright // 12988b783a1SJames Wright // Constants: 13088b783a1SJames Wright // lambda = - 2 / 3, From Stokes hypothesis 13188b783a1SJames Wright // mu , Dynamic viscosity 13288b783a1SJames Wright // k , Thermal conductivity 13388b783a1SJames Wright // cv , Specific heat, constant volume 13488b783a1SJames Wright // cp , Specific heat, constant pressure 13588b783a1SJames Wright // g , Gravity 13688b783a1SJames Wright // gamma = cp / cv, Specific heat ratio 13788b783a1SJames Wright // 138*ea61e9acSJeremy L Thompson // We require the product of the inverse of the Jacobian (dXdx_j,k) and its transpose (dXdx_k,j) to properly compute integrals of the form: int( gradv 139*ea61e9acSJeremy L Thompson // gradu ) 14088b783a1SJames Wright // ***************************************************************************** 1412b730f8bSJeremy L Thompson CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 14288b783a1SJames Wright // Inputs 14346603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 14446603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 14546603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 14646603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 14746603fc5SJames Wright 14888b783a1SJames Wright // Outputs 14946603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 15046603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 15188b783a1SJames Wright 15288b783a1SJames Wright // Context 15388b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 15488626eedSJames Wright const CeedScalar *g = context->g; 15588626eedSJames Wright const CeedScalar dt = context->dt; 15688b783a1SJames Wright 15788b783a1SJames Wright // Quadrature Point Loop 15846603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 1595c677226SJed Brown CeedScalar U[5]; 1605c677226SJed Brown for (int j = 0; j < 5; j++) U[j] = q[j][i]; 1615c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 1625c677226SJed Brown State s = StateFromU(context, U, x_i); 1635c677226SJed Brown 16488b783a1SJames Wright // -- Interp-to-Interp q_data 16588b783a1SJames Wright const CeedScalar wdetJ = q_data[0][i]; 16688b783a1SJames Wright // -- Interp-to-Grad q_data 16788b783a1SJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 1682b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 1692b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 17023d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 17123d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 17288b783a1SJames Wright }; 1735c677226SJed Brown State grad_s[3]; 1743c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) { 1756f00d0e6SJed Brown CeedScalar dx_i[3] = {0}, dU[5]; 1762b730f8bSJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dU[k] = Grad_q[0][k][i] * dXdx[0][j] + Grad_q[1][k][i] * dXdx[1][j] + Grad_q[2][k][i] * dXdx[2][j]; 1775c677226SJed Brown dx_i[j] = 1.; 1786f00d0e6SJed Brown grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i); 1795c677226SJed Brown } 1805c677226SJed Brown 1815c677226SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 1825c677226SJed Brown KMStrainRate(grad_s, strain_rate); 1835c677226SJed Brown NewtonianStress(context, strain_rate, kmstress); 1845c677226SJed Brown KMUnpack(kmstress, stress); 1855c677226SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 1865c677226SJed Brown 1875c677226SJed Brown StateConservative F_inviscid[3]; 1885c677226SJed Brown FluxInviscid(context, s, F_inviscid); 1895c677226SJed Brown 1905c677226SJed Brown // Total flux 1915c677226SJed Brown CeedScalar Flux[5][3]; 1922b89d87eSLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 1935c677226SJed Brown 1942b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 1952b730f8bSJeremy L Thompson for (CeedInt k = 0; k < 5; k++) Grad_v[j][k][i] = wdetJ * (dXdx[j][0] * Flux[k][0] + dXdx[j][1] * Flux[k][1] + dXdx[j][2] * Flux[k][2]); 1962b730f8bSJeremy L Thompson } 1975c677226SJed Brown 1985c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 1992b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * body_force[j]; 20088b783a1SJames Wright 2012b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 2022b89d87eSLeila Ghaffari CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}; 2032b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 2042b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 20588b783a1SJames Wright 2062b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 2072b730f8bSJeremy L Thompson for (CeedInt k = 0; k < 3; k++) Grad_v[k][j][i] -= wdetJ * (stab[j][0] * dXdx[k][0] + stab[j][1] * dXdx[k][1] + stab[j][2] * dXdx[k][2]); 2082b730f8bSJeremy L Thompson } 20988b783a1SJames Wright } // End Quadrature Point Loop 21088b783a1SJames Wright 21188b783a1SJames Wright // Return 21288b783a1SJames Wright return 0; 21388b783a1SJames Wright } 21488b783a1SJames Wright 21588b783a1SJames Wright // ***************************************************************************** 216*ea61e9acSJeremy L Thompson // This QFunction implements the Navier-Stokes equations (mentioned above) with implicit time stepping method 21788b783a1SJames Wright // 21888b783a1SJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 21988b783a1SJames Wright // SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) ) 220*ea61e9acSJeremy L Thompson // (diffusive terms will be added later) 22188b783a1SJames Wright // ***************************************************************************** 2222b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IFunction_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 2232b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 22488b783a1SJames Wright // Inputs 22546603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 22646603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 22746603fc5SJames Wright const CeedScalar(*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 22846603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 22946603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 23046603fc5SJames Wright 23188b783a1SJames Wright // Outputs 23246603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 23346603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 23446603fc5SJames Wright CeedScalar(*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2]; 23546603fc5SJames Wright 23688b783a1SJames Wright // Context 23788b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 23888626eedSJames Wright const CeedScalar *g = context->g; 23988626eedSJames Wright const CeedScalar dt = context->dt; 24088b783a1SJames Wright 24188b783a1SJames Wright // Quadrature Point Loop 24246603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 24346603fc5SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 2445c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 24546603fc5SJames Wright const State s = StateFromQi(context, qi, x_i); 2465c677226SJed Brown 24788b783a1SJames Wright // -- Interp-to-Interp q_data 24888b783a1SJames Wright const CeedScalar wdetJ = q_data[0][i]; 24988b783a1SJames Wright // -- Interp-to-Grad q_data 25088b783a1SJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 2512b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 2522b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 25323d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 25423d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 25588b783a1SJames Wright }; 2565c677226SJed Brown State grad_s[3]; 257ba6664aeSJames Wright for (CeedInt j = 0; j < 3; j++) { 2583d02368aSJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 25946603fc5SJames Wright for (CeedInt k = 0; k < 5; k++) { 26046603fc5SJames Wright dqi[k] = Grad_q[0][k][i] * dXdx[0][j] + Grad_q[1][k][i] * dXdx[1][j] + Grad_q[2][k][i] * dXdx[2][j]; 26146603fc5SJames Wright } 2625c677226SJed Brown dx_i[j] = 1.; 2633d02368aSJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 26488b783a1SJames Wright } 2655c677226SJed Brown 2665c677226SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 2675c677226SJed Brown KMStrainRate(grad_s, strain_rate); 2685c677226SJed Brown NewtonianStress(context, strain_rate, kmstress); 2695c677226SJed Brown KMUnpack(kmstress, stress); 2705c677226SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 2715c677226SJed Brown 2725c677226SJed Brown StateConservative F_inviscid[3]; 2735c677226SJed Brown FluxInviscid(context, s, F_inviscid); 2745c677226SJed Brown 2755c677226SJed Brown // Total flux 2765c677226SJed Brown CeedScalar Flux[5][3]; 2772b89d87eSLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 2785c677226SJed Brown 2792b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 28046603fc5SJames Wright for (CeedInt k = 0; k < 5; k++) { 28146603fc5SJames Wright Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * Flux[k][0] + dXdx[j][1] * Flux[k][1] + dXdx[j][2] * Flux[k][2]); 28246603fc5SJames Wright } 2832b730f8bSJeremy L Thompson } 2845c677226SJed Brown 2855c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 28688b783a1SJames Wright 2872b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 2883d02368aSJames Wright CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}, qi_dot[5], dx0[3] = {0}; 2893d02368aSJames Wright for (int j = 0; j < 5; j++) qi_dot[j] = q_dot[j][i]; 2903d02368aSJames Wright State s_dot = StateFromQi_fwd(context, s, qi_dot, x_i, dx0); 2913d02368aSJames Wright UnpackState_U(s_dot.U, U_dot); 2923d02368aSJames Wright 2932b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) v[j][i] = wdetJ * (U_dot[j] - body_force[j]); 2942b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 2952b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 29688b783a1SJames Wright 2972b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 29846603fc5SJames Wright for (CeedInt k = 0; k < 3; k++) { 29946603fc5SJames Wright Grad_v[k][j][i] += wdetJ * (stab[j][0] * dXdx[k][0] + stab[j][1] * dXdx[k][1] + stab[j][2] * dXdx[k][2]); 30046603fc5SJames Wright } 3012b730f8bSJeremy L Thompson } 3023d02368aSJames Wright for (CeedInt j = 0; j < 5; j++) jac_data[j][i] = qi[j]; 3033c4b7af6SJed Brown for (CeedInt j = 0; j < 6; j++) jac_data[5 + j][i] = kmstress[j]; 3043c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) jac_data[5 + 6 + j][i] = Tau_d[j]; 30588b783a1SJames Wright 30688b783a1SJames Wright } // End Quadrature Point Loop 30788b783a1SJames Wright 30888b783a1SJames Wright // Return 30988b783a1SJames Wright return 0; 31088b783a1SJames Wright } 311e334ad8fSJed Brown 3122b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3133d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 3143d02368aSJames Wright } 3153d02368aSJames Wright 3162b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3173d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 3183d02368aSJames Wright } 3193d02368aSJames Wright 320dc805cc4SLeila Ghaffari // ***************************************************************************** 321*ea61e9acSJeremy L Thompson // This QFunction implements the jacobian of the Navier-Stokes equations for implicit time stepping method. 322dc805cc4SLeila Ghaffari // ***************************************************************************** 3232b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IJacobian_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 3242b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 325e334ad8fSJed Brown // Inputs 32646603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 32746603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 32846603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 32946603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 33046603fc5SJames Wright const CeedScalar(*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 33146603fc5SJames Wright 332e334ad8fSJed Brown // Outputs 33346603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 33446603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 33546603fc5SJames Wright 336e334ad8fSJed Brown // Context 337e334ad8fSJed Brown NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 338e334ad8fSJed Brown const CeedScalar *g = context->g; 339e334ad8fSJed Brown 340e334ad8fSJed Brown // Quadrature Point Loop 34146603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 342e334ad8fSJed Brown // -- Interp-to-Interp q_data 343e334ad8fSJed Brown const CeedScalar wdetJ = q_data[0][i]; 344e334ad8fSJed Brown // -- Interp-to-Grad q_data 345e334ad8fSJed Brown // ---- Inverse of change of coordinate matrix: X_i,j 3462b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 3472b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 34823d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 34923d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 350e334ad8fSJed Brown }; 351e334ad8fSJed Brown 352c98a0616SJames Wright CeedScalar qi[5], kmstress[6], Tau_d[3]; 3533d02368aSJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data[j][i]; 354e334ad8fSJed Brown for (int j = 0; j < 6; j++) kmstress[j] = jac_data[5 + j][i]; 355e334ad8fSJed Brown for (int j = 0; j < 3; j++) Tau_d[j] = jac_data[5 + 6 + j][i]; 356e334ad8fSJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 3573d02368aSJames Wright State s = StateFromQi(context, qi, x_i); 358e334ad8fSJed Brown 3593d02368aSJames Wright CeedScalar dqi[5], dx0[3] = {0}; 3603d02368aSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 3613d02368aSJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx0); 362e334ad8fSJed Brown 363e334ad8fSJed Brown State grad_ds[3]; 364e334ad8fSJed Brown for (int j = 0; j < 3; j++) { 3653d02368aSJames Wright CeedScalar dqi_j[5]; 3662b730f8bSJeremy L Thompson for (int k = 0; k < 5; k++) dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] + Grad_dq[1][k][i] * dXdx[1][j] + Grad_dq[2][k][i] * dXdx[2][j]; 3673d02368aSJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx0); 368e334ad8fSJed Brown } 369e334ad8fSJed Brown 370e334ad8fSJed Brown CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 371e334ad8fSJed Brown KMStrainRate(grad_ds, dstrain_rate); 372e334ad8fSJed Brown NewtonianStress(context, dstrain_rate, dkmstress); 373e334ad8fSJed Brown KMUnpack(dkmstress, dstress); 374e334ad8fSJed Brown KMUnpack(kmstress, stress); 375e334ad8fSJed Brown ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 376e334ad8fSJed Brown 377e334ad8fSJed Brown StateConservative dF_inviscid[3]; 378e334ad8fSJed Brown FluxInviscid_fwd(context, s, ds, dF_inviscid); 379e334ad8fSJed Brown 380e334ad8fSJed Brown // Total flux 381e334ad8fSJed Brown CeedScalar dFlux[5][3]; 3822b89d87eSLeila Ghaffari FluxTotal(dF_inviscid, dstress, dFe, dFlux); 383e334ad8fSJed Brown 3842b730f8bSJeremy L Thompson for (int j = 0; j < 3; j++) { 3852b730f8bSJeremy L Thompson for (int k = 0; k < 5; k++) Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * dFlux[k][0] + dXdx[j][1] * dFlux[k][1] + dXdx[j][2] * dFlux[k][2]); 3862b730f8bSJeremy L Thompson } 387e334ad8fSJed Brown 388e334ad8fSJed Brown const CeedScalar dbody_force[5] = {0, ds.U.density * g[0], ds.U.density * g[1], ds.U.density * g[2], 0}; 3893d02368aSJames Wright CeedScalar dU[5] = {0.}; 3903d02368aSJames Wright UnpackState_U(ds.U, dU); 3912b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]); 392e334ad8fSJed Brown 3932b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 3942b89d87eSLeila Ghaffari CeedScalar dstab[5][3], U_dot[5] = {0}; 3952b89d87eSLeila Ghaffari for (CeedInt j = 0; j < 5; j++) U_dot[j] = context->ijacobian_time_shift * dU[j]; 3962b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_ds, U_dot, dbody_force, x_i, dstab); 3972b89d87eSLeila Ghaffari 3982b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) { 3992b730f8bSJeremy L Thompson for (int k = 0; k < 3; k++) Grad_v[k][j][i] += wdetJ * (dstab[j][0] * dXdx[k][0] + dstab[j][1] * dXdx[k][1] + dstab[j][2] * dXdx[k][2]); 4002b730f8bSJeremy L Thompson } 401e334ad8fSJed Brown } // End Quadrature Point Loop 402e334ad8fSJed Brown return 0; 403e334ad8fSJed Brown } 40465dd5cafSJames Wright 4052b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4063d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 4073d02368aSJames Wright } 4083d02368aSJames Wright 4092b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4103d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 4113d02368aSJames Wright } 4123d02368aSJames Wright 4132b89d87eSLeila Ghaffari // ***************************************************************************** 41465dd5cafSJames Wright // Compute boundary integral (ie. for strongly set inflows) 4152b89d87eSLeila Ghaffari // ***************************************************************************** 4162b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 4172b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 41846603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 41946603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 42046603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 42146603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 42265dd5cafSJames Wright 42346603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 42446603fc5SJames Wright CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 42565dd5cafSJames Wright 4262c4e60d7SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 4272c4e60d7SJames Wright const bool is_implicit = context->is_implicit; 42865dd5cafSJames Wright 4292b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 4302c4e60d7SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 431efe9d856SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 432efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 43365dd5cafSJames Wright 43465dd5cafSJames Wright const CeedScalar wdetJb = (is_implicit ? -1. : 1.) * q_data_sur[0][i]; 4355bce47c7SJames Wright // ---- Normal vector 4362b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 43765dd5cafSJames Wright 4382c4e60d7SJames Wright const CeedScalar dXdx[2][3] = { 4392c4e60d7SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 4402c4e60d7SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 4412c4e60d7SJames Wright }; 44265dd5cafSJames Wright 4432c4e60d7SJames Wright State grad_s[3]; 4442c4e60d7SJames Wright for (CeedInt j = 0; j < 3; j++) { 445efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 4462b730f8bSJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dqi[k] = Grad_q[0][k][i] * dXdx[0][j] + Grad_q[1][k][i] * dXdx[1][j]; 4472c4e60d7SJames Wright dx_i[j] = 1.; 448efe9d856SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 4492c4e60d7SJames Wright } 45065dd5cafSJames Wright 4512c4e60d7SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 4522c4e60d7SJames Wright KMStrainRate(grad_s, strain_rate); 4532c4e60d7SJames Wright NewtonianStress(context, strain_rate, kmstress); 4542c4e60d7SJames Wright KMUnpack(kmstress, stress); 4552c4e60d7SJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 4562c4e60d7SJames Wright 4572c4e60d7SJames Wright StateConservative F_inviscid[3]; 4582c4e60d7SJames Wright FluxInviscid(context, s, F_inviscid); 4592c4e60d7SJames Wright 4605bce47c7SJames Wright CeedScalar Flux[5]; 4615bce47c7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 4622c4e60d7SJames Wright 4635bce47c7SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 46465dd5cafSJames Wright 4655bce47c7SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 466b55ac660SJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 46765dd5cafSJames Wright } 46865dd5cafSJames Wright return 0; 46965dd5cafSJames Wright } 47065dd5cafSJames Wright 4712b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 47220840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromU, StateFromU_fwd); 47320840d50SJames Wright } 47420840d50SJames Wright 4752b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 47620840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromY, StateFromY_fwd); 47720840d50SJames Wright } 47820840d50SJames Wright 4792b89d87eSLeila Ghaffari // ***************************************************************************** 480b55ac660SJames Wright // Jacobian for "set nothing" boundary integral 4812b89d87eSLeila Ghaffari // ***************************************************************************** 4822b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 48320840d50SJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 484b55ac660SJames Wright // Inputs 48546603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 48646603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 48746603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 48846603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 48946603fc5SJames Wright const CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 49046603fc5SJames Wright 491b55ac660SJames Wright // Outputs 492b55ac660SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 493b55ac660SJames Wright 494b55ac660SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 495b55ac660SJames Wright const bool implicit = context->is_implicit; 496b55ac660SJames Wright 497b55ac660SJames Wright // Quadrature Point Loop 49846603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 499b55ac660SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 500b55ac660SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 5012b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 502b55ac660SJames Wright const CeedScalar dXdx[2][3] = { 503b55ac660SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 504b55ac660SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 505b55ac660SJames Wright }; 506b55ac660SJames Wright 507efe9d856SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 508efe9d856SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 509b55ac660SJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 510efe9d856SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 51157e55a1cSJames Wright 512efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 513efe9d856SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 514b55ac660SJames Wright 515b55ac660SJames Wright State grad_ds[3]; 516b55ac660SJames Wright for (CeedInt j = 0; j < 3; j++) { 517efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 5182b730f8bSJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] + Grad_dq[1][k][i] * dXdx[1][j]; 519b55ac660SJames Wright dx_i[j] = 1.; 520efe9d856SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 521b55ac660SJames Wright } 522b55ac660SJames Wright 523b55ac660SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 524b55ac660SJames Wright KMStrainRate(grad_ds, dstrain_rate); 525b55ac660SJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 526b55ac660SJames Wright KMUnpack(dkmstress, dstress); 527b55ac660SJames Wright KMUnpack(kmstress, stress); 528b55ac660SJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 529b55ac660SJames Wright 530b55ac660SJames Wright StateConservative dF_inviscid[3]; 531b55ac660SJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 532b55ac660SJames Wright 5335bce47c7SJames Wright CeedScalar dFlux[5]; 5345bce47c7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 535b55ac660SJames Wright 5365bce47c7SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 537b55ac660SJames Wright } // End Quadrature Point Loop 538b55ac660SJames Wright return 0; 539b55ac660SJames Wright } 540b55ac660SJames Wright 5412b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 54220840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 54320840d50SJames Wright } 54420840d50SJames Wright 5452b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 54620840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 54720840d50SJames Wright } 54820840d50SJames Wright 5492b89d87eSLeila Ghaffari // ***************************************************************************** 55030e9fa81SJames Wright // Outflow boundary condition, weakly setting a constant pressure 5512b89d87eSLeila Ghaffari // ***************************************************************************** 5522b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 5532b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 55430e9fa81SJames Wright // Inputs 55546603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 55646603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 55746603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 55846603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 55946603fc5SJames Wright 56030e9fa81SJames Wright // Outputs 56146603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 56246603fc5SJames Wright CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 56330e9fa81SJames Wright 56430e9fa81SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 56530e9fa81SJames Wright const bool implicit = context->is_implicit; 56630e9fa81SJames Wright const CeedScalar P0 = context->P0; 56730e9fa81SJames Wright 56830e9fa81SJames Wright // Quadrature Point Loop 56946603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 57030e9fa81SJames Wright // Setup 57130e9fa81SJames Wright // -- Interp in 572ce9b5c20SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 573efe9d856SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 574efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 575ce9b5c20SJames Wright s.Y.pressure = P0; 57630e9fa81SJames Wright 57730e9fa81SJames Wright // -- Interp-to-Interp q_data 57830e9fa81SJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 57930e9fa81SJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 58030e9fa81SJames Wright // We can effect this by swapping the sign on this weight 58130e9fa81SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 58230e9fa81SJames Wright 5835bce47c7SJames Wright // ---- Normal vector 58420840d50SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 58530e9fa81SJames Wright 586ce9b5c20SJames Wright const CeedScalar dXdx[2][3] = { 587ce9b5c20SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 588ce9b5c20SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 589ce9b5c20SJames Wright }; 59030e9fa81SJames Wright 591ce9b5c20SJames Wright State grad_s[3]; 592ce9b5c20SJames Wright for (CeedInt j = 0; j < 3; j++) { 593efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 5942b730f8bSJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dqi[k] = Grad_q[0][k][i] * dXdx[0][j] + Grad_q[1][k][i] * dXdx[1][j]; 595ce9b5c20SJames Wright dx_i[j] = 1.; 596efe9d856SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 597ce9b5c20SJames Wright } 598ce9b5c20SJames Wright 599ce9b5c20SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 600ce9b5c20SJames Wright KMStrainRate(grad_s, strain_rate); 601ce9b5c20SJames Wright NewtonianStress(context, strain_rate, kmstress); 602ce9b5c20SJames Wright KMUnpack(kmstress, stress); 603ce9b5c20SJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 604ce9b5c20SJames Wright 605ce9b5c20SJames Wright StateConservative F_inviscid[3]; 606ce9b5c20SJames Wright FluxInviscid(context, s, F_inviscid); 607ce9b5c20SJames Wright 6085bce47c7SJames Wright CeedScalar Flux[5]; 6095bce47c7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 61030e9fa81SJames Wright 6115bce47c7SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 61230e9fa81SJames Wright 61330e9fa81SJames Wright // Save values for Jacobian 6145bce47c7SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 6150ec2498eSJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 61630e9fa81SJames Wright } // End Quadrature Point Loop 61730e9fa81SJames Wright return 0; 61830e9fa81SJames Wright } 61930e9fa81SJames Wright 6202b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 62120840d50SJames Wright return PressureOutflow(ctx, Q, in, out, StateFromU, StateFromU_fwd); 62220840d50SJames Wright } 62320840d50SJames Wright 6242b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 62520840d50SJames Wright return PressureOutflow(ctx, Q, in, out, StateFromY, StateFromY_fwd); 62620840d50SJames Wright } 62720840d50SJames Wright 6282b89d87eSLeila Ghaffari // ***************************************************************************** 62930e9fa81SJames Wright // Jacobian for weak-pressure outflow boundary condition 6302b89d87eSLeila Ghaffari // ***************************************************************************** 6312b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 63220840d50SJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 63330e9fa81SJames Wright // Inputs 63446603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 63546603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 63646603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 63746603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 63846603fc5SJames Wright const CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 63946603fc5SJames Wright 64030e9fa81SJames Wright // Outputs 64130e9fa81SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 64230e9fa81SJames Wright 64330e9fa81SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 64430e9fa81SJames Wright const bool implicit = context->is_implicit; 64530e9fa81SJames Wright 64630e9fa81SJames Wright // Quadrature Point Loop 64746603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 6480ec2498eSJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 64930e9fa81SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 65020840d50SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 6510ec2498eSJames Wright const CeedScalar dXdx[2][3] = { 6520ec2498eSJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 6530ec2498eSJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 6540ec2498eSJames Wright }; 6550ec2498eSJames Wright 656efe9d856SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 657efe9d856SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 6580ec2498eSJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 659efe9d856SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 66057e55a1cSJames Wright 661efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 662efe9d856SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 6630ec2498eSJames Wright s.Y.pressure = context->P0; 6640ec2498eSJames Wright ds.Y.pressure = 0.; 6650ec2498eSJames Wright 6660ec2498eSJames Wright State grad_ds[3]; 6670ec2498eSJames Wright for (CeedInt j = 0; j < 3; j++) { 668efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 6692b730f8bSJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] + Grad_dq[1][k][i] * dXdx[1][j]; 6700ec2498eSJames Wright dx_i[j] = 1.; 671efe9d856SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 6720ec2498eSJames Wright } 6730ec2498eSJames Wright 6740ec2498eSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 6750ec2498eSJames Wright KMStrainRate(grad_ds, dstrain_rate); 6760ec2498eSJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 6770ec2498eSJames Wright KMUnpack(dkmstress, dstress); 6780ec2498eSJames Wright KMUnpack(kmstress, stress); 6790ec2498eSJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 68030e9fa81SJames Wright 681b5d317f8SJames Wright StateConservative dF_inviscid[3]; 682b5d317f8SJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 68330e9fa81SJames Wright 6845bce47c7SJames Wright CeedScalar dFlux[5]; 6855bce47c7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 686b5d317f8SJames Wright 6875bce47c7SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 68830e9fa81SJames Wright } // End Quadrature Point Loop 68930e9fa81SJames Wright return 0; 69030e9fa81SJames Wright } 69130e9fa81SJames Wright 6922b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 69320840d50SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 69420840d50SJames Wright } 69520840d50SJames Wright 6962b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 69720840d50SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 69820840d50SJames Wright } 6992b730f8bSJeremy L Thompson 70088b783a1SJames Wright #endif // newtonian_h 701