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 // ***************************************************************************** 68dc805cc4SLeila Ghaffari // This QFunction sets a "still" initial condition for generic Newtonian IG 69dc805cc4SLeila Ghaffari // problems in primitive variables 70dc805cc4SLeila Ghaffari // ***************************************************************************** 712b730f8bSJeremy 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 812b730f8bSJeremy 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 912b730f8bSJeremy 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 // ***************************************************************************** 1462b730f8bSJeremy L Thompson CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 14788b783a1SJames Wright // Inputs 148*46603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 149*46603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 150*46603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 151*46603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 152*46603fc5SJames Wright 15388b783a1SJames Wright // Outputs 154*46603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 155*46603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 15688b783a1SJames Wright 15788b783a1SJames Wright // Context 15888b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 15988626eedSJames Wright const CeedScalar *g = context->g; 16088626eedSJames Wright const CeedScalar dt = context->dt; 16188b783a1SJames Wright 16288b783a1SJames Wright // Quadrature Point Loop 163*46603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 1645c677226SJed Brown CeedScalar U[5]; 1655c677226SJed Brown for (int j = 0; j < 5; j++) U[j] = q[j][i]; 1665c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 1675c677226SJed Brown State s = StateFromU(context, U, x_i); 1685c677226SJed Brown 16988b783a1SJames Wright // -- Interp-to-Interp q_data 17088b783a1SJames Wright const CeedScalar wdetJ = q_data[0][i]; 17188b783a1SJames Wright // -- Interp-to-Grad q_data 17288b783a1SJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 1732b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 1742b730f8bSJeremy 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 }; 1785c677226SJed Brown State grad_s[3]; 1793c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) { 1806f00d0e6SJed Brown CeedScalar dx_i[3] = {0}, dU[5]; 1812b730f8bSJeremy 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]; 1825c677226SJed Brown dx_i[j] = 1.; 1836f00d0e6SJed Brown grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i); 1845c677226SJed Brown } 1855c677226SJed Brown 1865c677226SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 1875c677226SJed Brown KMStrainRate(grad_s, strain_rate); 1885c677226SJed Brown NewtonianStress(context, strain_rate, kmstress); 1895c677226SJed Brown KMUnpack(kmstress, stress); 1905c677226SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 1915c677226SJed Brown 1925c677226SJed Brown StateConservative F_inviscid[3]; 1935c677226SJed Brown FluxInviscid(context, s, F_inviscid); 1945c677226SJed Brown 1955c677226SJed Brown // Total flux 1965c677226SJed Brown CeedScalar Flux[5][3]; 1972b89d87eSLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 1985c677226SJed Brown 1992b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 2002b730f8bSJeremy 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]); 2012b730f8bSJeremy L Thompson } 2025c677226SJed Brown 2035c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 2042b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * body_force[j]; 20588b783a1SJames Wright 2062b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 2072b89d87eSLeila Ghaffari CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}; 2082b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 2092b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 21088b783a1SJames Wright 2112b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 2122b730f8bSJeremy 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]); 2132b730f8bSJeremy L Thompson } 21488b783a1SJames Wright } // End Quadrature Point Loop 21588b783a1SJames Wright 21688b783a1SJames Wright // Return 21788b783a1SJames Wright return 0; 21888b783a1SJames Wright } 21988b783a1SJames Wright 22088b783a1SJames Wright // ***************************************************************************** 22188b783a1SJames Wright // This QFunction implements the Navier-Stokes equations (mentioned above) with 22288b783a1SJames Wright // implicit time stepping method 22388b783a1SJames Wright // 22488b783a1SJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 22588b783a1SJames Wright // SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) ) 22688b783a1SJames Wright // (diffussive terms will be added later) 22788b783a1SJames Wright // 22888b783a1SJames Wright // ***************************************************************************** 2292b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IFunction_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 2302b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 23188b783a1SJames Wright // Inputs 232*46603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 233*46603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 234*46603fc5SJames Wright const CeedScalar(*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 235*46603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 236*46603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 237*46603fc5SJames Wright 23888b783a1SJames Wright // Outputs 239*46603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 240*46603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 241*46603fc5SJames Wright CeedScalar(*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2]; 242*46603fc5SJames Wright 24388b783a1SJames Wright // Context 24488b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 24588626eedSJames Wright const CeedScalar *g = context->g; 24688626eedSJames Wright const CeedScalar dt = context->dt; 24788b783a1SJames Wright 24888b783a1SJames Wright // Quadrature Point Loop 249*46603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 250*46603fc5SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 2515c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 252*46603fc5SJames Wright const 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 2582b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 2592b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 26023d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 26123d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 26288b783a1SJames Wright }; 2635c677226SJed Brown State grad_s[3]; 264ba6664aeSJames Wright for (CeedInt j = 0; j < 3; j++) { 2653d02368aSJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 266*46603fc5SJames Wright for (CeedInt k = 0; k < 5; k++) { 267*46603fc5SJames 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]; 268*46603fc5SJames Wright } 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 2862b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 287*46603fc5SJames Wright for (CeedInt k = 0; k < 5; k++) { 288*46603fc5SJames 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]); 289*46603fc5SJames Wright } 2902b730f8bSJeremy L Thompson } 2915c677226SJed Brown 2925c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 29388b783a1SJames Wright 2942b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 2953d02368aSJames Wright CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}, qi_dot[5], dx0[3] = {0}; 2963d02368aSJames Wright for (int j = 0; j < 5; j++) qi_dot[j] = q_dot[j][i]; 2973d02368aSJames Wright State s_dot = StateFromQi_fwd(context, s, qi_dot, x_i, dx0); 2983d02368aSJames Wright UnpackState_U(s_dot.U, U_dot); 2993d02368aSJames Wright 3002b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) v[j][i] = wdetJ * (U_dot[j] - body_force[j]); 3012b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 3022b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 30388b783a1SJames Wright 3042b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 305*46603fc5SJames Wright for (CeedInt k = 0; k < 3; k++) { 306*46603fc5SJames 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]); 307*46603fc5SJames Wright } 3082b730f8bSJeremy L Thompson } 3093d02368aSJames Wright for (CeedInt j = 0; j < 5; j++) jac_data[j][i] = qi[j]; 3103c4b7af6SJed Brown for (CeedInt j = 0; j < 6; j++) jac_data[5 + j][i] = kmstress[j]; 3113c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) jac_data[5 + 6 + j][i] = Tau_d[j]; 31288b783a1SJames Wright 31388b783a1SJames Wright } // End Quadrature Point Loop 31488b783a1SJames Wright 31588b783a1SJames Wright // Return 31688b783a1SJames Wright return 0; 31788b783a1SJames Wright } 318e334ad8fSJed Brown 3192b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3203d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 3213d02368aSJames Wright } 3223d02368aSJames Wright 3232b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3243d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 3253d02368aSJames Wright } 3263d02368aSJames Wright 327dc805cc4SLeila Ghaffari // ***************************************************************************** 3283d02368aSJames Wright // This QFunction implements the jacobian of the Navier-Stokes equations 329dc805cc4SLeila Ghaffari // for implicit time stepping method. 330dc805cc4SLeila Ghaffari // ***************************************************************************** 3312b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IJacobian_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 3322b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 333e334ad8fSJed Brown // Inputs 334*46603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 335*46603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 336*46603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 337*46603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 338*46603fc5SJames Wright const CeedScalar(*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 339*46603fc5SJames Wright 340e334ad8fSJed Brown // Outputs 341*46603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 342*46603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 343*46603fc5SJames Wright 344e334ad8fSJed Brown // Context 345e334ad8fSJed Brown NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 346e334ad8fSJed Brown const CeedScalar *g = context->g; 347e334ad8fSJed Brown 348e334ad8fSJed Brown // Quadrature Point Loop 349*46603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 350e334ad8fSJed Brown // -- Interp-to-Interp q_data 351e334ad8fSJed Brown const CeedScalar wdetJ = q_data[0][i]; 352e334ad8fSJed Brown // -- Interp-to-Grad q_data 353e334ad8fSJed Brown // ---- Inverse of change of coordinate matrix: X_i,j 3542b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 3552b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 35623d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 35723d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 358e334ad8fSJed Brown }; 359e334ad8fSJed Brown 360c98a0616SJames Wright CeedScalar qi[5], kmstress[6], Tau_d[3]; 3613d02368aSJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data[j][i]; 362e334ad8fSJed Brown for (int j = 0; j < 6; j++) kmstress[j] = jac_data[5 + j][i]; 363e334ad8fSJed Brown for (int j = 0; j < 3; j++) Tau_d[j] = jac_data[5 + 6 + j][i]; 364e334ad8fSJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 3653d02368aSJames Wright State s = StateFromQi(context, qi, x_i); 366e334ad8fSJed Brown 3673d02368aSJames Wright CeedScalar dqi[5], dx0[3] = {0}; 3683d02368aSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 3693d02368aSJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx0); 370e334ad8fSJed Brown 371e334ad8fSJed Brown State grad_ds[3]; 372e334ad8fSJed Brown for (int j = 0; j < 3; j++) { 3733d02368aSJames Wright CeedScalar dqi_j[5]; 3742b730f8bSJeremy 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]; 3753d02368aSJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx0); 376e334ad8fSJed Brown } 377e334ad8fSJed Brown 378e334ad8fSJed Brown CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 379e334ad8fSJed Brown KMStrainRate(grad_ds, dstrain_rate); 380e334ad8fSJed Brown NewtonianStress(context, dstrain_rate, dkmstress); 381e334ad8fSJed Brown KMUnpack(dkmstress, dstress); 382e334ad8fSJed Brown KMUnpack(kmstress, stress); 383e334ad8fSJed Brown ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 384e334ad8fSJed Brown 385e334ad8fSJed Brown StateConservative dF_inviscid[3]; 386e334ad8fSJed Brown FluxInviscid_fwd(context, s, ds, dF_inviscid); 387e334ad8fSJed Brown 388e334ad8fSJed Brown // Total flux 389e334ad8fSJed Brown CeedScalar dFlux[5][3]; 3902b89d87eSLeila Ghaffari FluxTotal(dF_inviscid, dstress, dFe, dFlux); 391e334ad8fSJed Brown 3922b730f8bSJeremy L Thompson for (int j = 0; j < 3; j++) { 3932b730f8bSJeremy 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]); 3942b730f8bSJeremy L Thompson } 395e334ad8fSJed Brown 396e334ad8fSJed Brown const CeedScalar dbody_force[5] = {0, ds.U.density * g[0], ds.U.density * g[1], ds.U.density * g[2], 0}; 3973d02368aSJames Wright CeedScalar dU[5] = {0.}; 3983d02368aSJames Wright UnpackState_U(ds.U, dU); 3992b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]); 400e334ad8fSJed Brown 4012b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 4022b89d87eSLeila Ghaffari CeedScalar dstab[5][3], U_dot[5] = {0}; 4032b89d87eSLeila Ghaffari for (CeedInt j = 0; j < 5; j++) U_dot[j] = context->ijacobian_time_shift * dU[j]; 4042b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_ds, U_dot, dbody_force, x_i, dstab); 4052b89d87eSLeila Ghaffari 4062b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) { 4072b730f8bSJeremy 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]); 4082b730f8bSJeremy L Thompson } 409e334ad8fSJed Brown } // End Quadrature Point Loop 410e334ad8fSJed Brown return 0; 411e334ad8fSJed Brown } 41265dd5cafSJames Wright 4132b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4143d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 4153d02368aSJames Wright } 4163d02368aSJames Wright 4172b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4183d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 4193d02368aSJames Wright } 4203d02368aSJames Wright 4212b89d87eSLeila Ghaffari // ***************************************************************************** 42265dd5cafSJames Wright // Compute boundary integral (ie. for strongly set inflows) 4232b89d87eSLeila Ghaffari // ***************************************************************************** 4242b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 4252b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 426*46603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 427*46603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 428*46603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 429*46603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 43065dd5cafSJames Wright 431*46603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 432*46603fc5SJames Wright CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 43365dd5cafSJames Wright 4342c4e60d7SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 4352c4e60d7SJames Wright const bool is_implicit = context->is_implicit; 43665dd5cafSJames Wright 4372b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 4382c4e60d7SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 439efe9d856SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 440efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 44165dd5cafSJames Wright 44265dd5cafSJames Wright const CeedScalar wdetJb = (is_implicit ? -1. : 1.) * q_data_sur[0][i]; 4435bce47c7SJames Wright // ---- Normal vector 4442b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 44565dd5cafSJames Wright 4462c4e60d7SJames Wright const CeedScalar dXdx[2][3] = { 4472c4e60d7SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 4482c4e60d7SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 4492c4e60d7SJames Wright }; 45065dd5cafSJames Wright 4512c4e60d7SJames Wright State grad_s[3]; 4522c4e60d7SJames Wright for (CeedInt j = 0; j < 3; j++) { 453efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 4542b730f8bSJeremy 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]; 4552c4e60d7SJames Wright dx_i[j] = 1.; 456efe9d856SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 4572c4e60d7SJames Wright } 45865dd5cafSJames Wright 4592c4e60d7SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 4602c4e60d7SJames Wright KMStrainRate(grad_s, strain_rate); 4612c4e60d7SJames Wright NewtonianStress(context, strain_rate, kmstress); 4622c4e60d7SJames Wright KMUnpack(kmstress, stress); 4632c4e60d7SJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 4642c4e60d7SJames Wright 4652c4e60d7SJames Wright StateConservative F_inviscid[3]; 4662c4e60d7SJames Wright FluxInviscid(context, s, F_inviscid); 4672c4e60d7SJames Wright 4685bce47c7SJames Wright CeedScalar Flux[5]; 4695bce47c7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 4702c4e60d7SJames Wright 4715bce47c7SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 47265dd5cafSJames Wright 4735bce47c7SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 474b55ac660SJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 47565dd5cafSJames Wright } 47665dd5cafSJames Wright return 0; 47765dd5cafSJames Wright } 47865dd5cafSJames Wright 4792b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 48020840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromU, StateFromU_fwd); 48120840d50SJames Wright } 48220840d50SJames Wright 4832b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 48420840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromY, StateFromY_fwd); 48520840d50SJames Wright } 48620840d50SJames Wright 4872b89d87eSLeila Ghaffari // ***************************************************************************** 488b55ac660SJames Wright // Jacobian for "set nothing" boundary integral 4892b89d87eSLeila Ghaffari // ***************************************************************************** 4902b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 49120840d50SJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 492b55ac660SJames Wright // Inputs 493*46603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 494*46603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 495*46603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 496*46603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 497*46603fc5SJames Wright const CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 498*46603fc5SJames Wright 499b55ac660SJames Wright // Outputs 500b55ac660SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 501b55ac660SJames Wright 502b55ac660SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 503b55ac660SJames Wright const bool implicit = context->is_implicit; 504b55ac660SJames Wright 505b55ac660SJames Wright // Quadrature Point Loop 506*46603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 507b55ac660SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 508b55ac660SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 5092b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 510b55ac660SJames Wright const CeedScalar dXdx[2][3] = { 511b55ac660SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 512b55ac660SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 513b55ac660SJames Wright }; 514b55ac660SJames Wright 515efe9d856SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 516efe9d856SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 517b55ac660SJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 518efe9d856SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 51957e55a1cSJames Wright 520efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 521efe9d856SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 522b55ac660SJames Wright 523b55ac660SJames Wright State grad_ds[3]; 524b55ac660SJames Wright for (CeedInt j = 0; j < 3; j++) { 525efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 5262b730f8bSJeremy 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]; 527b55ac660SJames Wright dx_i[j] = 1.; 528efe9d856SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 529b55ac660SJames Wright } 530b55ac660SJames Wright 531b55ac660SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 532b55ac660SJames Wright KMStrainRate(grad_ds, dstrain_rate); 533b55ac660SJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 534b55ac660SJames Wright KMUnpack(dkmstress, dstress); 535b55ac660SJames Wright KMUnpack(kmstress, stress); 536b55ac660SJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 537b55ac660SJames Wright 538b55ac660SJames Wright StateConservative dF_inviscid[3]; 539b55ac660SJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 540b55ac660SJames Wright 5415bce47c7SJames Wright CeedScalar dFlux[5]; 5425bce47c7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 543b55ac660SJames Wright 5445bce47c7SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 545b55ac660SJames Wright } // End Quadrature Point Loop 546b55ac660SJames Wright return 0; 547b55ac660SJames Wright } 548b55ac660SJames Wright 5492b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 55020840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 55120840d50SJames Wright } 55220840d50SJames Wright 5532b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 55420840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 55520840d50SJames Wright } 55620840d50SJames Wright 5572b89d87eSLeila Ghaffari // ***************************************************************************** 55830e9fa81SJames Wright // Outflow boundary condition, weakly setting a constant pressure 5592b89d87eSLeila Ghaffari // ***************************************************************************** 5602b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 5612b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 56230e9fa81SJames Wright // Inputs 563*46603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 564*46603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 565*46603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 566*46603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 567*46603fc5SJames Wright 56830e9fa81SJames Wright // Outputs 569*46603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 570*46603fc5SJames Wright CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 57130e9fa81SJames Wright 57230e9fa81SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 57330e9fa81SJames Wright const bool implicit = context->is_implicit; 57430e9fa81SJames Wright const CeedScalar P0 = context->P0; 57530e9fa81SJames Wright 57630e9fa81SJames Wright // Quadrature Point Loop 577*46603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 57830e9fa81SJames Wright // Setup 57930e9fa81SJames Wright // -- Interp in 580ce9b5c20SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 581efe9d856SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 582efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 583ce9b5c20SJames Wright s.Y.pressure = P0; 58430e9fa81SJames Wright 58530e9fa81SJames Wright // -- Interp-to-Interp q_data 58630e9fa81SJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 58730e9fa81SJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 58830e9fa81SJames Wright // We can effect this by swapping the sign on this weight 58930e9fa81SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 59030e9fa81SJames Wright 5915bce47c7SJames Wright // ---- Normal vector 59220840d50SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 59330e9fa81SJames Wright 594ce9b5c20SJames Wright const CeedScalar dXdx[2][3] = { 595ce9b5c20SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 596ce9b5c20SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 597ce9b5c20SJames Wright }; 59830e9fa81SJames Wright 599ce9b5c20SJames Wright State grad_s[3]; 600ce9b5c20SJames Wright for (CeedInt j = 0; j < 3; j++) { 601efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 6022b730f8bSJeremy 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]; 603ce9b5c20SJames Wright dx_i[j] = 1.; 604efe9d856SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 605ce9b5c20SJames Wright } 606ce9b5c20SJames Wright 607ce9b5c20SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 608ce9b5c20SJames Wright KMStrainRate(grad_s, strain_rate); 609ce9b5c20SJames Wright NewtonianStress(context, strain_rate, kmstress); 610ce9b5c20SJames Wright KMUnpack(kmstress, stress); 611ce9b5c20SJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 612ce9b5c20SJames Wright 613ce9b5c20SJames Wright StateConservative F_inviscid[3]; 614ce9b5c20SJames Wright FluxInviscid(context, s, F_inviscid); 615ce9b5c20SJames Wright 6165bce47c7SJames Wright CeedScalar Flux[5]; 6175bce47c7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 61830e9fa81SJames Wright 6195bce47c7SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 62030e9fa81SJames Wright 62130e9fa81SJames Wright // Save values for Jacobian 6225bce47c7SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 6230ec2498eSJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 62430e9fa81SJames Wright } // End Quadrature Point Loop 62530e9fa81SJames Wright return 0; 62630e9fa81SJames Wright } 62730e9fa81SJames Wright 6282b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 62920840d50SJames Wright return PressureOutflow(ctx, Q, in, out, StateFromU, StateFromU_fwd); 63020840d50SJames Wright } 63120840d50SJames Wright 6322b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 63320840d50SJames Wright return PressureOutflow(ctx, Q, in, out, StateFromY, StateFromY_fwd); 63420840d50SJames Wright } 63520840d50SJames Wright 6362b89d87eSLeila Ghaffari // ***************************************************************************** 63730e9fa81SJames Wright // Jacobian for weak-pressure outflow boundary condition 6382b89d87eSLeila Ghaffari // ***************************************************************************** 6392b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 64020840d50SJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 64130e9fa81SJames Wright // Inputs 642*46603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 643*46603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 644*46603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 645*46603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 646*46603fc5SJames Wright const CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 647*46603fc5SJames Wright 64830e9fa81SJames Wright // Outputs 64930e9fa81SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 65030e9fa81SJames Wright 65130e9fa81SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 65230e9fa81SJames Wright const bool implicit = context->is_implicit; 65330e9fa81SJames Wright 65430e9fa81SJames Wright // Quadrature Point Loop 655*46603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 6560ec2498eSJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 65730e9fa81SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 65820840d50SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 6590ec2498eSJames Wright const CeedScalar dXdx[2][3] = { 6600ec2498eSJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 6610ec2498eSJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 6620ec2498eSJames Wright }; 6630ec2498eSJames Wright 664efe9d856SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 665efe9d856SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 6660ec2498eSJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 667efe9d856SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 66857e55a1cSJames Wright 669efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 670efe9d856SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 6710ec2498eSJames Wright s.Y.pressure = context->P0; 6720ec2498eSJames Wright ds.Y.pressure = 0.; 6730ec2498eSJames Wright 6740ec2498eSJames Wright State grad_ds[3]; 6750ec2498eSJames Wright for (CeedInt j = 0; j < 3; j++) { 676efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 6772b730f8bSJeremy 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]; 6780ec2498eSJames Wright dx_i[j] = 1.; 679efe9d856SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 6800ec2498eSJames Wright } 6810ec2498eSJames Wright 6820ec2498eSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 6830ec2498eSJames Wright KMStrainRate(grad_ds, dstrain_rate); 6840ec2498eSJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 6850ec2498eSJames Wright KMUnpack(dkmstress, dstress); 6860ec2498eSJames Wright KMUnpack(kmstress, stress); 6870ec2498eSJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 68830e9fa81SJames Wright 689b5d317f8SJames Wright StateConservative dF_inviscid[3]; 690b5d317f8SJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 69130e9fa81SJames Wright 6925bce47c7SJames Wright CeedScalar dFlux[5]; 6935bce47c7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 694b5d317f8SJames Wright 6955bce47c7SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 69630e9fa81SJames Wright } // End Quadrature Point Loop 69730e9fa81SJames Wright return 0; 69830e9fa81SJames Wright } 69930e9fa81SJames Wright 7002b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 70120840d50SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 70220840d50SJames Wright } 70320840d50SJames Wright 7042b730f8bSJeremy L Thompson CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 70520840d50SJames Wright return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 70620840d50SJames Wright } 7072b730f8bSJeremy L Thompson 70888b783a1SJames Wright #endif // newtonian_h 709