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> 17*2b730f8bSJeremy 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 // ***************************************************************************** 26*2b730f8bSJeremy 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 43*2b730f8bSJeremy 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 61*2b730f8bSJeremy 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 // ***************************************************************************** 68dc805cc4SLeila Ghaffari // This QFunction sets a "still" initial condition for generic Newtonian IG 69dc805cc4SLeila Ghaffari // problems in primitive variables 70dc805cc4SLeila Ghaffari // ***************************************************************************** 71*2b730f8bSJeremy L Thompson CEED_QFUNCTION(ICsNewtonianIG_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 72dc805cc4SLeila Ghaffari // Outputs 73dc805cc4SLeila Ghaffari CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 74dc805cc4SLeila Ghaffari 75dc805cc4SLeila Ghaffari // Context 76dc805cc4SLeila Ghaffari const SetupContext context = (SetupContext)ctx; 77dc805cc4SLeila Ghaffari const CeedScalar theta0 = context->theta0; 78dc805cc4SLeila Ghaffari const CeedScalar P0 = context->P0; 79dc805cc4SLeila Ghaffari 80dc805cc4SLeila Ghaffari // Quadrature Point Loop 81*2b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 82dc805cc4SLeila Ghaffari CeedScalar q[5] = {0.}; 83dc805cc4SLeila Ghaffari 84dc805cc4SLeila Ghaffari // Initial Conditions 85dc805cc4SLeila Ghaffari q[0] = P0; 86dc805cc4SLeila Ghaffari q[1] = 0.0; 87dc805cc4SLeila Ghaffari q[2] = 0.0; 88dc805cc4SLeila Ghaffari q[3] = 0.0; 89dc805cc4SLeila Ghaffari q[4] = theta0; 90dc805cc4SLeila Ghaffari 91*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 92dc805cc4SLeila Ghaffari 93dc805cc4SLeila Ghaffari } // End of Quadrature Point Loop 94dc805cc4SLeila Ghaffari return 0; 95dc805cc4SLeila Ghaffari } 96dc805cc4SLeila Ghaffari 97dc805cc4SLeila Ghaffari // ***************************************************************************** 9888b783a1SJames Wright // This QFunction implements the following formulation of Navier-Stokes with 9988b783a1SJames Wright // explicit time stepping method 10088b783a1SJames Wright // 10188b783a1SJames Wright // This is 3D compressible Navier-Stokes in conservation form with state 10288b783a1SJames Wright // variables of density, momentum density, and total energy density. 10388b783a1SJames Wright // 10488b783a1SJames Wright // State Variables: q = ( rho, U1, U2, U3, E ) 10588b783a1SJames Wright // rho - Mass Density 10688b783a1SJames Wright // Ui - Momentum Density, Ui = rho ui 10788b783a1SJames Wright // E - Total Energy Density, E = rho (cv T + (u u)/2 + g z) 10888b783a1SJames Wright // 10988b783a1SJames Wright // Navier-Stokes Equations: 11088b783a1SJames Wright // drho/dt + div( U ) = 0 11188b783a1SJames Wright // dU/dt + div( rho (u x u) + P I3 ) + rho g khat = div( Fu ) 11288b783a1SJames Wright // dE/dt + div( (E + P) u ) = div( Fe ) 11388b783a1SJames Wright // 11488b783a1SJames Wright // Viscous Stress: 11588b783a1SJames Wright // Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3) 11688b783a1SJames Wright // 11788b783a1SJames Wright // Thermal Stress: 11888b783a1SJames Wright // Fe = u Fu + k grad( T ) 11988626eedSJames Wright // Equation of State 12088b783a1SJames Wright // P = (gamma - 1) (E - rho (u u) / 2 - rho g z) 12188b783a1SJames Wright // 12288b783a1SJames Wright // Stabilization: 12388b783a1SJames Wright // Tau = diag(TauC, TauM, TauM, TauM, TauE) 12488b783a1SJames Wright // f1 = rho sqrt(ui uj gij) 12588b783a1SJames Wright // gij = dXi/dX * dXi/dX 12688b783a1SJames Wright // TauC = Cc f1 / (8 gii) 12788b783a1SJames Wright // TauM = min( 1 , 1 / f1 ) 12888b783a1SJames Wright // TauE = TauM / (Ce cv) 12988b783a1SJames Wright // 13088b783a1SJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 13188b783a1SJames Wright // 13288b783a1SJames Wright // Constants: 13388b783a1SJames Wright // lambda = - 2 / 3, From Stokes hypothesis 13488b783a1SJames Wright // mu , Dynamic viscosity 13588b783a1SJames Wright // k , Thermal conductivity 13688b783a1SJames Wright // cv , Specific heat, constant volume 13788b783a1SJames Wright // cp , Specific heat, constant pressure 13888b783a1SJames Wright // g , Gravity 13988b783a1SJames Wright // gamma = cp / cv, Specific heat ratio 14088b783a1SJames Wright // 14188b783a1SJames Wright // We require the product of the inverse of the Jacobian (dXdx_j,k) and 14288b783a1SJames Wright // its transpose (dXdx_k,j) to properly compute integrals of the form: 14388b783a1SJames Wright // int( gradv gradu ) 14488b783a1SJames Wright // 14588b783a1SJames Wright // ***************************************************************************** 146*2b730f8bSJeremy L Thompson CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 14788b783a1SJames Wright // *INDENT-OFF* 14888b783a1SJames Wright // Inputs 149*2b730f8bSJeremy L Thompson const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1], 150*2b730f8bSJeremy L Thompson (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 15188b783a1SJames Wright // Outputs 152*2b730f8bSJeremy L Thompson CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0], (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 15388b783a1SJames Wright // *INDENT-ON* 15488b783a1SJames Wright 15588b783a1SJames Wright // Context 15688b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 15788626eedSJames Wright const CeedScalar *g = context->g; 15888626eedSJames Wright const CeedScalar dt = context->dt; 15988b783a1SJames Wright 16088b783a1SJames Wright CeedPragmaSIMD 16188b783a1SJames Wright // Quadrature Point Loop 16288b783a1SJames Wright for (CeedInt i = 0; i < Q; i++) { 1635c677226SJed Brown CeedScalar U[5]; 1645c677226SJed Brown for (int j = 0; j < 5; j++) U[j] = q[j][i]; 1655c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 1665c677226SJed Brown State s = StateFromU(context, U, x_i); 1675c677226SJed Brown 16888b783a1SJames Wright // -- Interp-to-Interp q_data 16988b783a1SJames Wright const CeedScalar wdetJ = q_data[0][i]; 17088b783a1SJames Wright // -- Interp-to-Grad q_data 17188b783a1SJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 17288b783a1SJames Wright // *INDENT-OFF* 173*2b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 174*2b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 17523d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 17623d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 17788b783a1SJames Wright }; 17888b783a1SJames Wright // *INDENT-ON* 1795c677226SJed Brown State grad_s[3]; 1803c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) { 1816f00d0e6SJed Brown CeedScalar dx_i[3] = {0}, dU[5]; 182*2b730f8bSJeremy 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]; 1835c677226SJed Brown dx_i[j] = 1.; 1846f00d0e6SJed Brown grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i); 1855c677226SJed Brown } 1865c677226SJed Brown 1875c677226SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 1885c677226SJed Brown KMStrainRate(grad_s, strain_rate); 1895c677226SJed Brown NewtonianStress(context, strain_rate, kmstress); 1905c677226SJed Brown KMUnpack(kmstress, stress); 1915c677226SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 1925c677226SJed Brown 1935c677226SJed Brown StateConservative F_inviscid[3]; 1945c677226SJed Brown FluxInviscid(context, s, F_inviscid); 1955c677226SJed Brown 1965c677226SJed Brown // Total flux 1975c677226SJed Brown CeedScalar Flux[5][3]; 1982b89d87eSLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 1995c677226SJed Brown 200*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 201*2b730f8bSJeremy 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]); 202*2b730f8bSJeremy L Thompson } 2035c677226SJed Brown 2045c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 205*2b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * body_force[j]; 20688b783a1SJames Wright 2072b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 2082b89d87eSLeila Ghaffari CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}; 2092b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 2102b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 21188b783a1SJames Wright 212*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 213*2b730f8bSJeremy 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]); 214*2b730f8bSJeremy L Thompson } 21588b783a1SJames Wright } // End Quadrature Point Loop 21688b783a1SJames Wright 21788b783a1SJames Wright // Return 21888b783a1SJames Wright return 0; 21988b783a1SJames Wright } 22088b783a1SJames Wright 22188b783a1SJames Wright // ***************************************************************************** 22288b783a1SJames Wright // This QFunction implements the Navier-Stokes equations (mentioned above) with 22388b783a1SJames Wright // implicit time stepping method 22488b783a1SJames Wright // 22588b783a1SJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 22688b783a1SJames Wright // SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) ) 22788b783a1SJames Wright // (diffussive terms will be added later) 22888b783a1SJames Wright // 22988b783a1SJames Wright // ***************************************************************************** 230*2b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IFunction_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 231*2b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 23288b783a1SJames Wright // *INDENT-OFF* 23388b783a1SJames Wright // Inputs 234*2b730f8bSJeremy L Thompson const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1], 235*2b730f8bSJeremy L Thompson (*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3], 23688b783a1SJames Wright (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 23788b783a1SJames Wright // Outputs 238*2b730f8bSJeremy L Thompson CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0], (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1], 239a3ae0734SJed Brown (*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2]; 24088b783a1SJames Wright // *INDENT-ON* 24188b783a1SJames Wright // Context 24288b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 24388626eedSJames Wright const CeedScalar *g = context->g; 24488626eedSJames Wright const CeedScalar dt = context->dt; 24588b783a1SJames Wright 24688b783a1SJames Wright CeedPragmaSIMD 24788b783a1SJames Wright // Quadrature Point Loop 24888b783a1SJames Wright for (CeedInt i = 0; i < Q; i++) { 2493d02368aSJames Wright CeedScalar qi[5]; 2503d02368aSJames Wright for (CeedInt j = 0; j < 5; j++) qi[j] = q[j][i]; 2515c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 2523d02368aSJames Wright State s = StateFromQi(context, qi, x_i); 2535c677226SJed Brown 25488b783a1SJames Wright // -- Interp-to-Interp q_data 25588b783a1SJames Wright const CeedScalar wdetJ = q_data[0][i]; 25688b783a1SJames Wright // -- Interp-to-Grad q_data 25788b783a1SJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 25888b783a1SJames Wright // *INDENT-OFF* 259*2b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 260*2b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 26123d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 26223d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 26388b783a1SJames Wright }; 26488b783a1SJames Wright // *INDENT-ON* 2655c677226SJed Brown State grad_s[3]; 266ba6664aeSJames Wright for (CeedInt j = 0; j < 3; j++) { 2673d02368aSJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 268*2b730f8bSJeremy 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] + Grad_q[2][k][i] * dXdx[2][j]; 2695c677226SJed Brown dx_i[j] = 1.; 2703d02368aSJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 27188b783a1SJames Wright } 2725c677226SJed Brown 2735c677226SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 2745c677226SJed Brown KMStrainRate(grad_s, strain_rate); 2755c677226SJed Brown NewtonianStress(context, strain_rate, kmstress); 2765c677226SJed Brown KMUnpack(kmstress, stress); 2775c677226SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 2785c677226SJed Brown 2795c677226SJed Brown StateConservative F_inviscid[3]; 2805c677226SJed Brown FluxInviscid(context, s, F_inviscid); 2815c677226SJed Brown 2825c677226SJed Brown // Total flux 2835c677226SJed Brown CeedScalar Flux[5][3]; 2842b89d87eSLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 2855c677226SJed Brown 286*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 287*2b730f8bSJeremy 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]); 288*2b730f8bSJeremy L Thompson } 2895c677226SJed Brown 2905c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 29188b783a1SJames Wright 2922b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 2933d02368aSJames Wright CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}, qi_dot[5], dx0[3] = {0}; 2943d02368aSJames Wright for (int j = 0; j < 5; j++) qi_dot[j] = q_dot[j][i]; 2953d02368aSJames Wright State s_dot = StateFromQi_fwd(context, s, qi_dot, x_i, dx0); 2963d02368aSJames Wright UnpackState_U(s_dot.U, U_dot); 2973d02368aSJames Wright 298*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) v[j][i] = wdetJ * (U_dot[j] - body_force[j]); 2992b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 3002b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 30188b783a1SJames Wright 302*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 303*2b730f8bSJeremy 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]); 304*2b730f8bSJeremy L Thompson } 3053d02368aSJames Wright for (CeedInt j = 0; j < 5; j++) jac_data[j][i] = qi[j]; 3063c4b7af6SJed Brown for (CeedInt j = 0; j < 6; j++) jac_data[5 + j][i] = kmstress[j]; 3073c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) jac_data[5 + 6 + j][i] = Tau_d[j]; 30888b783a1SJames Wright 30988b783a1SJames Wright } // End Quadrature Point Loop 31088b783a1SJames Wright 31188b783a1SJames Wright // Return 31288b783a1SJames Wright return 0; 31388b783a1SJames Wright } 314e334ad8fSJed Brown 315*2b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3163d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 3173d02368aSJames Wright } 3183d02368aSJames Wright 319*2b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3203d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 3213d02368aSJames Wright } 3223d02368aSJames Wright 323dc805cc4SLeila Ghaffari // ***************************************************************************** 3243d02368aSJames Wright // This QFunction implements the jacobian of the Navier-Stokes equations 325dc805cc4SLeila Ghaffari // for implicit time stepping method. 326dc805cc4SLeila Ghaffari // ***************************************************************************** 327*2b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IJacobian_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 328*2b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 329e334ad8fSJed Brown // *INDENT-OFF* 330e334ad8fSJed Brown // Inputs 331*2b730f8bSJeremy L Thompson const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1], 332*2b730f8bSJeremy L Thompson (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3], 333e334ad8fSJed Brown (*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 334e334ad8fSJed Brown // Outputs 335*2b730f8bSJeremy L Thompson CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0], (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 336e334ad8fSJed Brown // *INDENT-ON* 337e334ad8fSJed Brown // Context 338e334ad8fSJed Brown NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 339e334ad8fSJed Brown const CeedScalar *g = context->g; 340e334ad8fSJed Brown 341e334ad8fSJed Brown CeedPragmaSIMD 342e334ad8fSJed Brown // Quadrature Point Loop 343e334ad8fSJed Brown for (CeedInt i = 0; i < Q; i++) { 344e334ad8fSJed Brown // -- Interp-to-Interp q_data 345e334ad8fSJed Brown const CeedScalar wdetJ = q_data[0][i]; 346e334ad8fSJed Brown // -- Interp-to-Grad q_data 347e334ad8fSJed Brown // ---- Inverse of change of coordinate matrix: X_i,j 348e334ad8fSJed Brown // *INDENT-OFF* 349*2b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 350*2b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 35123d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 35223d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 353e334ad8fSJed Brown }; 354e334ad8fSJed Brown // *INDENT-ON* 355e334ad8fSJed Brown 356c98a0616SJames Wright CeedScalar qi[5], kmstress[6], Tau_d[3]; 3573d02368aSJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data[j][i]; 358e334ad8fSJed Brown for (int j = 0; j < 6; j++) kmstress[j] = jac_data[5 + j][i]; 359e334ad8fSJed Brown for (int j = 0; j < 3; j++) Tau_d[j] = jac_data[5 + 6 + j][i]; 360e334ad8fSJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 3613d02368aSJames Wright State s = StateFromQi(context, qi, x_i); 362e334ad8fSJed Brown 3633d02368aSJames Wright CeedScalar dqi[5], dx0[3] = {0}; 3643d02368aSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 3653d02368aSJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx0); 366e334ad8fSJed Brown 367e334ad8fSJed Brown State grad_ds[3]; 368e334ad8fSJed Brown for (int j = 0; j < 3; j++) { 3693d02368aSJames Wright CeedScalar dqi_j[5]; 370*2b730f8bSJeremy 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]; 3713d02368aSJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx0); 372e334ad8fSJed Brown } 373e334ad8fSJed Brown 374e334ad8fSJed Brown CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 375e334ad8fSJed Brown KMStrainRate(grad_ds, dstrain_rate); 376e334ad8fSJed Brown NewtonianStress(context, dstrain_rate, dkmstress); 377e334ad8fSJed Brown KMUnpack(dkmstress, dstress); 378e334ad8fSJed Brown KMUnpack(kmstress, stress); 379e334ad8fSJed Brown ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 380e334ad8fSJed Brown 381e334ad8fSJed Brown StateConservative dF_inviscid[3]; 382e334ad8fSJed Brown FluxInviscid_fwd(context, s, ds, dF_inviscid); 383e334ad8fSJed Brown 384e334ad8fSJed Brown // Total flux 385e334ad8fSJed Brown CeedScalar dFlux[5][3]; 3862b89d87eSLeila Ghaffari FluxTotal(dF_inviscid, dstress, dFe, dFlux); 387e334ad8fSJed Brown 388*2b730f8bSJeremy L Thompson for (int j = 0; j < 3; j++) { 389*2b730f8bSJeremy 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]); 390*2b730f8bSJeremy L Thompson } 391e334ad8fSJed Brown 392e334ad8fSJed Brown const CeedScalar dbody_force[5] = {0, ds.U.density * g[0], ds.U.density * g[1], ds.U.density * g[2], 0}; 3933d02368aSJames Wright CeedScalar dU[5] = {0.}; 3943d02368aSJames Wright UnpackState_U(ds.U, dU); 395*2b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]); 396e334ad8fSJed Brown 3972b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 3982b89d87eSLeila Ghaffari CeedScalar dstab[5][3], U_dot[5] = {0}; 3992b89d87eSLeila Ghaffari for (CeedInt j = 0; j < 5; j++) U_dot[j] = context->ijacobian_time_shift * dU[j]; 4002b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_ds, U_dot, dbody_force, x_i, dstab); 4012b89d87eSLeila Ghaffari 402*2b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) { 403*2b730f8bSJeremy 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]); 404*2b730f8bSJeremy L Thompson } 405e334ad8fSJed Brown } // End Quadrature Point Loop 406e334ad8fSJed Brown return 0; 407e334ad8fSJed Brown } 40865dd5cafSJames Wright 409*2b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4103d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 4113d02368aSJames Wright } 4123d02368aSJames Wright 413*2b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4143d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 4153d02368aSJames Wright } 4163d02368aSJames Wright 4172b89d87eSLeila Ghaffari // ***************************************************************************** 41865dd5cafSJames Wright // Compute boundary integral (ie. for strongly set inflows) 4192b89d87eSLeila Ghaffari // ***************************************************************************** 420*2b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 421*2b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 42265dd5cafSJames Wright //*INDENT-OFF* 423*2b730f8bSJeremy L Thompson const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1], 424*2b730f8bSJeremy L Thompson (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 42565dd5cafSJames Wright 426*2b730f8bSJeremy L Thompson CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0], (*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 42765dd5cafSJames Wright 42865dd5cafSJames Wright //*INDENT-ON* 42965dd5cafSJames Wright 4302c4e60d7SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 4312c4e60d7SJames Wright const bool is_implicit = context->is_implicit; 43265dd5cafSJames Wright 433*2b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 4342c4e60d7SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 435efe9d856SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 436efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 43765dd5cafSJames Wright 43865dd5cafSJames Wright const CeedScalar wdetJb = (is_implicit ? -1. : 1.) * q_data_sur[0][i]; 4395bce47c7SJames Wright // ---- Normal vector 440*2b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 44165dd5cafSJames Wright 4422c4e60d7SJames Wright const CeedScalar dXdx[2][3] = { 4432c4e60d7SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 4442c4e60d7SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 4452c4e60d7SJames Wright }; 44665dd5cafSJames Wright 4472c4e60d7SJames Wright State grad_s[3]; 4482c4e60d7SJames Wright for (CeedInt j = 0; j < 3; j++) { 449efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 450*2b730f8bSJeremy 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]; 4512c4e60d7SJames Wright dx_i[j] = 1.; 452efe9d856SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 4532c4e60d7SJames Wright } 45465dd5cafSJames Wright 4552c4e60d7SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 4562c4e60d7SJames Wright KMStrainRate(grad_s, strain_rate); 4572c4e60d7SJames Wright NewtonianStress(context, strain_rate, kmstress); 4582c4e60d7SJames Wright KMUnpack(kmstress, stress); 4592c4e60d7SJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 4602c4e60d7SJames Wright 4612c4e60d7SJames Wright StateConservative F_inviscid[3]; 4622c4e60d7SJames Wright FluxInviscid(context, s, F_inviscid); 4632c4e60d7SJames Wright 4645bce47c7SJames Wright CeedScalar Flux[5]; 4655bce47c7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 4662c4e60d7SJames Wright 4675bce47c7SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 46865dd5cafSJames Wright 4695bce47c7SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 470b55ac660SJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 47165dd5cafSJames Wright } 47265dd5cafSJames Wright return 0; 47365dd5cafSJames Wright } 47465dd5cafSJames Wright 475*2b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 47620840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromU, StateFromU_fwd); 47720840d50SJames Wright } 47820840d50SJames Wright 479*2b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 48020840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromY, StateFromY_fwd); 48120840d50SJames Wright } 48220840d50SJames Wright 4832b89d87eSLeila Ghaffari // ***************************************************************************** 484b55ac660SJames Wright // Jacobian for "set nothing" boundary integral 4852b89d87eSLeila Ghaffari // ***************************************************************************** 486*2b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 48720840d50SJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 488b55ac660SJames Wright // *INDENT-OFF* 489b55ac660SJames Wright // Inputs 490*2b730f8bSJeremy L Thompson const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1], 491*2b730f8bSJeremy L Thompson (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3], 492b55ac660SJames Wright (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 493b55ac660SJames Wright // Outputs 494b55ac660SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 495b55ac660SJames Wright // *INDENT-ON* 496b55ac660SJames Wright 497b55ac660SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 498b55ac660SJames Wright const bool implicit = context->is_implicit; 499b55ac660SJames Wright 500b55ac660SJames Wright CeedPragmaSIMD 501b55ac660SJames Wright // Quadrature Point Loop 502b55ac660SJames Wright for (CeedInt i = 0; i < Q; i++) { 503b55ac660SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 504b55ac660SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 505*2b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 506b55ac660SJames Wright const CeedScalar dXdx[2][3] = { 507b55ac660SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 508b55ac660SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 509b55ac660SJames Wright }; 510b55ac660SJames Wright 511efe9d856SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 512efe9d856SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 513b55ac660SJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 514efe9d856SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 51557e55a1cSJames Wright 516efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 517efe9d856SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 518b55ac660SJames Wright 519b55ac660SJames Wright State grad_ds[3]; 520b55ac660SJames Wright for (CeedInt j = 0; j < 3; j++) { 521efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 522*2b730f8bSJeremy 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]; 523b55ac660SJames Wright dx_i[j] = 1.; 524efe9d856SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 525b55ac660SJames Wright } 526b55ac660SJames Wright 527b55ac660SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 528b55ac660SJames Wright KMStrainRate(grad_ds, dstrain_rate); 529b55ac660SJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 530b55ac660SJames Wright KMUnpack(dkmstress, dstress); 531b55ac660SJames Wright KMUnpack(kmstress, stress); 532b55ac660SJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 533b55ac660SJames Wright 534b55ac660SJames Wright StateConservative dF_inviscid[3]; 535b55ac660SJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 536b55ac660SJames Wright 5375bce47c7SJames Wright CeedScalar dFlux[5]; 5385bce47c7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 539b55ac660SJames Wright 5405bce47c7SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 541b55ac660SJames Wright } // End Quadrature Point Loop 542b55ac660SJames Wright return 0; 543b55ac660SJames Wright } 544b55ac660SJames Wright 545*2b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 54620840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 54720840d50SJames Wright } 54820840d50SJames Wright 549*2b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 55020840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 55120840d50SJames Wright } 55220840d50SJames Wright 5532b89d87eSLeila Ghaffari // ***************************************************************************** 55430e9fa81SJames Wright // Outflow boundary condition, weakly setting a constant pressure 5552b89d87eSLeila Ghaffari // ***************************************************************************** 556*2b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 557*2b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 55830e9fa81SJames Wright // *INDENT-OFF* 55930e9fa81SJames Wright // Inputs 560*2b730f8bSJeremy L Thompson const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1], 561*2b730f8bSJeremy L Thompson (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 56230e9fa81SJames Wright // Outputs 563*2b730f8bSJeremy L Thompson CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0], (*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 56430e9fa81SJames Wright // *INDENT-ON* 56530e9fa81SJames Wright 56630e9fa81SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 56730e9fa81SJames Wright const bool implicit = context->is_implicit; 56830e9fa81SJames Wright const CeedScalar P0 = context->P0; 56930e9fa81SJames Wright 57030e9fa81SJames Wright CeedPragmaSIMD 57130e9fa81SJames Wright // Quadrature Point Loop 57230e9fa81SJames Wright for (CeedInt i = 0; i < Q; i++) { 57330e9fa81SJames Wright // Setup 57430e9fa81SJames Wright // -- Interp in 575ce9b5c20SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 576efe9d856SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 577efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 578ce9b5c20SJames Wright s.Y.pressure = P0; 57930e9fa81SJames Wright 58030e9fa81SJames Wright // -- Interp-to-Interp q_data 58130e9fa81SJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 58230e9fa81SJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 58330e9fa81SJames Wright // We can effect this by swapping the sign on this weight 58430e9fa81SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 58530e9fa81SJames Wright 5865bce47c7SJames Wright // ---- Normal vector 58720840d50SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 58830e9fa81SJames Wright 589ce9b5c20SJames Wright const CeedScalar dXdx[2][3] = { 590ce9b5c20SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 591ce9b5c20SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 592ce9b5c20SJames Wright }; 59330e9fa81SJames Wright 594ce9b5c20SJames Wright State grad_s[3]; 595ce9b5c20SJames Wright for (CeedInt j = 0; j < 3; j++) { 596efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 597*2b730f8bSJeremy 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]; 598ce9b5c20SJames Wright dx_i[j] = 1.; 599efe9d856SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 600ce9b5c20SJames Wright } 601ce9b5c20SJames Wright 602ce9b5c20SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 603ce9b5c20SJames Wright KMStrainRate(grad_s, strain_rate); 604ce9b5c20SJames Wright NewtonianStress(context, strain_rate, kmstress); 605ce9b5c20SJames Wright KMUnpack(kmstress, stress); 606ce9b5c20SJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 607ce9b5c20SJames Wright 608ce9b5c20SJames Wright StateConservative F_inviscid[3]; 609ce9b5c20SJames Wright FluxInviscid(context, s, F_inviscid); 610ce9b5c20SJames Wright 6115bce47c7SJames Wright CeedScalar Flux[5]; 6125bce47c7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 61330e9fa81SJames Wright 6145bce47c7SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 61530e9fa81SJames Wright 61630e9fa81SJames Wright // Save values for Jacobian 6175bce47c7SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 6180ec2498eSJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 61930e9fa81SJames Wright } // End Quadrature Point Loop 62030e9fa81SJames Wright return 0; 62130e9fa81SJames Wright } 62230e9fa81SJames Wright 623*2b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 62420840d50SJames Wright return PressureOutflow(ctx, Q, in, out, StateFromU, StateFromU_fwd); 62520840d50SJames Wright } 62620840d50SJames Wright 627*2b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 62820840d50SJames Wright return PressureOutflow(ctx, Q, in, out, StateFromY, StateFromY_fwd); 62920840d50SJames Wright } 63020840d50SJames Wright 6312b89d87eSLeila Ghaffari // ***************************************************************************** 63230e9fa81SJames Wright // Jacobian for weak-pressure outflow boundary condition 6332b89d87eSLeila Ghaffari // ***************************************************************************** 634*2b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 63520840d50SJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 63630e9fa81SJames Wright // *INDENT-OFF* 63730e9fa81SJames Wright // Inputs 638*2b730f8bSJeremy L Thompson const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1], 639*2b730f8bSJeremy L Thompson (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3], 6400ec2498eSJames Wright (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 64130e9fa81SJames Wright // Outputs 64230e9fa81SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 64330e9fa81SJames Wright // *INDENT-ON* 64430e9fa81SJames Wright 64530e9fa81SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 64630e9fa81SJames Wright const bool implicit = context->is_implicit; 64730e9fa81SJames Wright 64830e9fa81SJames Wright CeedPragmaSIMD 64930e9fa81SJames Wright // Quadrature Point Loop 65030e9fa81SJames Wright for (CeedInt i = 0; i < Q; i++) { 6510ec2498eSJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 65230e9fa81SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 65320840d50SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 6540ec2498eSJames Wright const CeedScalar dXdx[2][3] = { 6550ec2498eSJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 6560ec2498eSJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 6570ec2498eSJames Wright }; 6580ec2498eSJames Wright 659efe9d856SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 660efe9d856SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 6610ec2498eSJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 662efe9d856SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 66357e55a1cSJames Wright 664efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 665efe9d856SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 6660ec2498eSJames Wright s.Y.pressure = context->P0; 6670ec2498eSJames Wright ds.Y.pressure = 0.; 6680ec2498eSJames Wright 6690ec2498eSJames Wright State grad_ds[3]; 6700ec2498eSJames Wright for (CeedInt j = 0; j < 3; j++) { 671efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 672*2b730f8bSJeremy 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]; 6730ec2498eSJames Wright dx_i[j] = 1.; 674efe9d856SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 6750ec2498eSJames Wright } 6760ec2498eSJames Wright 6770ec2498eSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 6780ec2498eSJames Wright KMStrainRate(grad_ds, dstrain_rate); 6790ec2498eSJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 6800ec2498eSJames Wright KMUnpack(dkmstress, dstress); 6810ec2498eSJames Wright KMUnpack(kmstress, stress); 6820ec2498eSJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 68330e9fa81SJames Wright 684b5d317f8SJames Wright StateConservative dF_inviscid[3]; 685b5d317f8SJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 68630e9fa81SJames Wright 6875bce47c7SJames Wright CeedScalar dFlux[5]; 6885bce47c7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 689b5d317f8SJames Wright 6905bce47c7SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 69130e9fa81SJames Wright } // End Quadrature Point Loop 69230e9fa81SJames Wright return 0; 69330e9fa81SJames Wright } 69430e9fa81SJames Wright 695*2b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 69620840d50SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 69720840d50SJames Wright } 69820840d50SJames Wright 699*2b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 70020840d50SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 70120840d50SJames Wright } 702*2b730f8bSJeremy L Thompson 70388b783a1SJames Wright #endif // newtonian_h 704