xref: /libCEED/examples/fluids/qfunctions/newtonian.h (revision 57e55a1c25e80345e382270f49941411c9f30449)
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 
1288b783a1SJames Wright #ifndef newtonian_h
1388b783a1SJames Wright #define newtonian_h
1488b783a1SJames Wright 
1588b783a1SJames Wright #include <math.h>
1688b783a1SJames Wright #include <ceed.h>
17841e4c73SJed Brown #include "newtonian_types.h"
18c6e8c570SJames Wright #include "newtonian_state.h"
1913fa47b2SJames Wright #include "utils.h"
2088b783a1SJames Wright 
2188b783a1SJames Wright // *****************************************************************************
2288b783a1SJames Wright // Helper function for computing flux Jacobian
2388b783a1SJames Wright // *****************************************************************************
2488b783a1SJames Wright CEED_QFUNCTION_HELPER void computeFluxJacobian_NS(CeedScalar dF[3][5][5],
2588b783a1SJames Wright     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
2688626eedSJames Wright     const CeedScalar gamma, const CeedScalar g[3], const CeedScalar x[3]) {
2788b783a1SJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
2888626eedSJames Wright   CeedScalar e_potential = -(g[0]*x[0] + g[1]*x[1] + g[2]*x[2]);
2988b783a1SJames Wright   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
3088b783a1SJames Wright     for (CeedInt j=0; j<3; j++) { // Rows of each Jacobian matrix
3188626eedSJames Wright       dF[i][j+1][0] = ((i==j) ? ((gamma-1.)*(u_sq/2. - e_potential)) : 0.) -
3288626eedSJames Wright                       u[i]*u[j];
3388b783a1SJames Wright       for (CeedInt k=0; k<3; k++) { // Columns of each Jacobian matrix
3488b783a1SJames Wright         dF[i][0][k+1]   = ((i==k) ? 1. : 0.);
3588b783a1SJames Wright         dF[i][j+1][k+1] = ((j==k) ? u[i] : 0.) +
3688b783a1SJames Wright                           ((i==k) ? u[j] : 0.) -
3788b783a1SJames Wright                           ((i==j) ? u[k] : 0.) * (gamma-1.);
3888b783a1SJames Wright         dF[i][4][k+1]   = ((i==k) ? (E*gamma/rho - (gamma-1.)*u_sq/2.) : 0.) -
3988b783a1SJames Wright                           (gamma-1.)*u[i]*u[k];
4088b783a1SJames Wright       }
4188b783a1SJames Wright       dF[i][j+1][4] = ((i==j) ? (gamma-1.) : 0.);
4288b783a1SJames Wright     }
4388b783a1SJames Wright     dF[i][4][0] = u[i] * ((gamma-1.)*u_sq - E*gamma/rho);
4488b783a1SJames Wright     dF[i][4][4] = u[i] * gamma;
4588b783a1SJames Wright   }
4688b783a1SJames Wright }
4788b783a1SJames Wright 
4888b783a1SJames Wright // *****************************************************************************
4988626eedSJames Wright // Helper function for computing flux Jacobian of Primitive variables
5088626eedSJames Wright // *****************************************************************************
5188626eedSJames Wright CEED_QFUNCTION_HELPER void computeFluxJacobian_NSp(CeedScalar dF[3][5][5],
5288626eedSJames Wright     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
5388626eedSJames Wright     const CeedScalar Rd, const CeedScalar cv) {
5488626eedSJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
5588626eedSJames Wright   // TODO Add in gravity's contribution
5688626eedSJames Wright 
5788626eedSJames Wright   CeedScalar T    = ( E / rho - u_sq / 2. ) / cv;
5888626eedSJames Wright   CeedScalar drdT = -rho / T;
5988626eedSJames Wright   CeedScalar drdP = 1. / ( Rd * T);
6088626eedSJames Wright   CeedScalar etot =  E / rho ;
6188626eedSJames Wright   CeedScalar e2p  = drdP * etot + 1. ;
6288626eedSJames Wright   CeedScalar e3p  = ( E  + rho * Rd * T );
6388626eedSJames Wright   CeedScalar e4p  = drdT * etot + rho * cv ;
6488626eedSJames Wright 
6588626eedSJames Wright   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
6688626eedSJames Wright     for (CeedInt j=0; j<3; j++) { // j counts F^{m_j}
6788626eedSJames Wright //        [row][col] of A_i
6888626eedSJames Wright       dF[i][j+1][0] = drdP * u[i] * u[j] + ((i==j) ? 1. : 0.); // F^{{m_j} wrt p
6988626eedSJames Wright       for (CeedInt k=0; k<3; k++) { // k counts the wrt vel_k
70871db79fSKenneth E. Jansen         dF[i][0][k+1]   =  ((i==k) ? rho  : 0.);   // F^c wrt u_k
7188626eedSJames Wright         dF[i][j+1][k+1] = (((j==k) ? u[i] : 0.) +  // F^m_j wrt u_k
7288626eedSJames Wright                            ((i==k) ? u[j] : 0.) ) * rho;
7388626eedSJames Wright         dF[i][4][k+1]   = rho * u[i] * u[k]
7488626eedSJames Wright                           + ((i==k) ? e3p  : 0.) ; // F^e wrt u_k
7588626eedSJames Wright       }
7688626eedSJames Wright       dF[i][j+1][4] = drdT * u[i] * u[j]; // F^{m_j} wrt T
7788626eedSJames Wright     }
7888626eedSJames Wright     dF[i][4][0] = u[i] * e2p; // F^e wrt p
7988626eedSJames Wright     dF[i][4][4] = u[i] * e4p; // F^e wrt T
8088626eedSJames Wright     dF[i][0][0] = u[i] * drdP; // F^c wrt p
8188626eedSJames Wright     dF[i][0][4] = u[i] * drdT; // F^c wrt T
8288626eedSJames Wright   }
8388626eedSJames Wright }
8488626eedSJames Wright 
8588626eedSJames Wright CEED_QFUNCTION_HELPER void PrimitiveToConservative_fwd(const CeedScalar rho,
8688626eedSJames Wright     const CeedScalar u[3], const CeedScalar E, const CeedScalar Rd,
8788626eedSJames Wright     const CeedScalar cv, const CeedScalar dY[5], CeedScalar dU[5]) {
8888626eedSJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
8988626eedSJames Wright   CeedScalar T    = ( E / rho - u_sq / 2. ) / cv;
9088626eedSJames Wright   CeedScalar drdT = -rho / T;
9188626eedSJames Wright   CeedScalar drdP = 1. / ( Rd * T);
9288626eedSJames Wright   dU[0] = drdP * dY[0] + drdT * dY[4];
9388626eedSJames Wright   CeedScalar de_kinetic = 0;
94ba6664aeSJames Wright   for (CeedInt i=0; i<3; i++) {
9588626eedSJames Wright     dU[1+i] = dU[0] * u[i] + rho * dY[1+i];
9688626eedSJames Wright     de_kinetic += u[i] * dY[1+i];
9788626eedSJames Wright   }
9888626eedSJames Wright   dU[4] = rho * cv * dY[4] + dU[0] * cv * T // internal energy: rho * e
9988626eedSJames Wright           + rho * de_kinetic + .5 * dU[0] * u_sq; // kinetic energy: .5 * rho * |u|^2
10088626eedSJames Wright }
10188626eedSJames Wright 
10288626eedSJames Wright // *****************************************************************************
10388626eedSJames Wright // Helper function for computing Tau elements (stabilization constant)
10488626eedSJames Wright //   Model from:
10588626eedSJames Wright //     PHASTA
10688626eedSJames Wright //
10788626eedSJames Wright //   Tau[i] = itau=0 which is diagonal-Shakib (3 values still but not spatial)
10888626eedSJames Wright //
10988626eedSJames Wright // Where NOT UPDATED YET
11088626eedSJames Wright // *****************************************************************************
11188626eedSJames Wright CEED_QFUNCTION_HELPER void Tau_diagPrim(CeedScalar Tau_d[3],
11288626eedSJames Wright                                         const CeedScalar dXdx[3][3], const CeedScalar u[3],
11388626eedSJames Wright                                         const CeedScalar cv, const NewtonianIdealGasContext newt_ctx,
11488626eedSJames Wright                                         const CeedScalar mu, const CeedScalar dt,
11588626eedSJames Wright                                         const CeedScalar rho) {
11688626eedSJames Wright   // Context
11788626eedSJames Wright   const CeedScalar Ctau_t = newt_ctx->Ctau_t;
11888626eedSJames Wright   const CeedScalar Ctau_v = newt_ctx->Ctau_v;
11988626eedSJames Wright   const CeedScalar Ctau_C = newt_ctx->Ctau_C;
12088626eedSJames Wright   const CeedScalar Ctau_M = newt_ctx->Ctau_M;
12188626eedSJames Wright   const CeedScalar Ctau_E = newt_ctx->Ctau_E;
12288626eedSJames Wright   CeedScalar gijd[6];
12388626eedSJames Wright   CeedScalar tau;
12488626eedSJames Wright   CeedScalar dts;
12588626eedSJames Wright   CeedScalar fact;
12688626eedSJames Wright 
12788626eedSJames Wright   //*INDENT-OFF*
12888626eedSJames Wright   gijd[0] =   dXdx[0][0] * dXdx[0][0]
12988626eedSJames Wright             + dXdx[1][0] * dXdx[1][0]
13088626eedSJames Wright             + dXdx[2][0] * dXdx[2][0];
13188626eedSJames Wright 
13288626eedSJames Wright   gijd[1] =   dXdx[0][0] * dXdx[0][1]
13388626eedSJames Wright             + dXdx[1][0] * dXdx[1][1]
13488626eedSJames Wright             + dXdx[2][0] * dXdx[2][1];
13588626eedSJames Wright 
13688626eedSJames Wright   gijd[2] =   dXdx[0][1] * dXdx[0][1]
13788626eedSJames Wright             + dXdx[1][1] * dXdx[1][1]
13888626eedSJames Wright             + dXdx[2][1] * dXdx[2][1];
13988626eedSJames Wright 
14088626eedSJames Wright   gijd[3] =   dXdx[0][0] * dXdx[0][2]
14188626eedSJames Wright             + dXdx[1][0] * dXdx[1][2]
14288626eedSJames Wright             + dXdx[2][0] * dXdx[2][2];
14388626eedSJames Wright 
14488626eedSJames Wright   gijd[4] =   dXdx[0][1] * dXdx[0][2]
14588626eedSJames Wright             + dXdx[1][1] * dXdx[1][2]
14688626eedSJames Wright             + dXdx[2][1] * dXdx[2][2];
14788626eedSJames Wright 
14888626eedSJames Wright   gijd[5] =   dXdx[0][2] * dXdx[0][2]
14988626eedSJames Wright             + dXdx[1][2] * dXdx[1][2]
15088626eedSJames Wright             + dXdx[2][2] * dXdx[2][2];
15188626eedSJames Wright   //*INDENT-ON*
15288626eedSJames Wright 
15388626eedSJames Wright   dts = Ctau_t / dt ;
15488626eedSJames Wright 
15588626eedSJames Wright   tau = rho*rho*((4. * dts * dts)
15688626eedSJames Wright                  + u[0] * ( u[0] * gijd[0] + 2. * ( u[1] * gijd[1] + u[2] * gijd[3]))
15788626eedSJames Wright                  + u[1] * ( u[1] * gijd[2] + 2. *   u[2] * gijd[4])
15888626eedSJames Wright                  + u[2] *   u[2] * gijd[5])
15988626eedSJames Wright         + Ctau_v* mu * mu *
16088626eedSJames Wright         (gijd[0]*gijd[0] + gijd[2]*gijd[2] + gijd[5]*gijd[5] +
16188626eedSJames Wright          + 2. * (gijd[1]*gijd[1] + gijd[3]*gijd[3] + gijd[4]*gijd[4]));
16288626eedSJames Wright 
16388626eedSJames Wright   fact=sqrt(tau);
16488626eedSJames Wright 
16588626eedSJames Wright   Tau_d[0] = Ctau_C * fact / (rho*(gijd[0] + gijd[2] + gijd[5]))*0.125;
16688626eedSJames Wright 
16788626eedSJames Wright   Tau_d[1] = Ctau_M / fact;
16888626eedSJames Wright   Tau_d[2] = Ctau_E / ( fact * cv );
16988626eedSJames Wright 
17088626eedSJames Wright // consider putting back the way I initially had it  Ctau_E * Tau_d[1] /cv
17188626eedSJames Wright //  to avoid a division if the compiler is smart enough to see that cv IS
17288626eedSJames Wright // a constant that it could invert once for all elements
17388626eedSJames Wright // but in that case energy tau is scaled by the product of Ctau_E * Ctau_M
17488626eedSJames Wright // OR we could absorb cv into Ctau_E but this puts more burden on user to
17588626eedSJames Wright // know how to change constants with a change of fluid or units.  Same for
17688626eedSJames Wright // Ctau_v * mu * mu IF AND ONLY IF we don't add viscosity law =f(T)
17788626eedSJames Wright }
17888626eedSJames Wright 
17988626eedSJames Wright // *****************************************************************************
18088b783a1SJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems
18188b783a1SJames Wright // *****************************************************************************
18288b783a1SJames Wright CEED_QFUNCTION(ICsNewtonianIG)(void *ctx, CeedInt Q,
18388b783a1SJames Wright                                const CeedScalar *const *in, CeedScalar *const *out) {
18488b783a1SJames Wright   // Inputs
18588b783a1SJames Wright   const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
18688b783a1SJames Wright 
18788b783a1SJames Wright   // Outputs
18888b783a1SJames Wright   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
18988b783a1SJames Wright 
19088626eedSJames Wright   // Context
19188626eedSJames Wright   const SetupContext context = (SetupContext)ctx;
19288626eedSJames Wright   const CeedScalar theta0    = context->theta0;
19388626eedSJames Wright   const CeedScalar P0        = context->P0;
19488626eedSJames Wright   const CeedScalar cv        = context->cv;
19588626eedSJames Wright   const CeedScalar cp        = context->cp;
19688626eedSJames Wright   const CeedScalar *g        = context->g;
19788626eedSJames Wright   const CeedScalar Rd        = cp - cv;
19888626eedSJames Wright 
19988b783a1SJames Wright   // Quadrature Point Loop
20088b783a1SJames Wright   CeedPragmaSIMD
20188b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
20288b783a1SJames Wright     CeedScalar q[5] = {0.};
20388b783a1SJames Wright 
20488b783a1SJames Wright     // Setup
20588b783a1SJames Wright     // -- Coordinates
20688626eedSJames Wright     const CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]};
20788626eedSJames Wright     const CeedScalar e_potential = -(g[0]*x[0] + g[1]*x[1] + g[2]*x[2]);
20888b783a1SJames Wright 
20988b783a1SJames Wright     // -- Density
21088626eedSJames Wright     const CeedScalar rho = P0 / (Rd*theta0);
21188b783a1SJames Wright 
21288b783a1SJames Wright     // Initial Conditions
21388b783a1SJames Wright     q[0] = rho;
21488b783a1SJames Wright     q[1] = 0.0;
21588b783a1SJames Wright     q[2] = 0.0;
21688b783a1SJames Wright     q[3] = 0.0;
21788626eedSJames Wright     q[4] = rho * (cv*theta0 + e_potential);
21888b783a1SJames Wright 
21988b783a1SJames Wright     for (CeedInt j=0; j<5; j++)
22088b783a1SJames Wright       q0[j][i] = q[j];
22188b783a1SJames Wright   } // End of Quadrature Point Loop
22288b783a1SJames Wright   return 0;
22388b783a1SJames Wright }
22488b783a1SJames Wright 
22588b783a1SJames Wright // *****************************************************************************
226dc805cc4SLeila Ghaffari // This QFunction sets a "still" initial condition for generic Newtonian IG
227dc805cc4SLeila Ghaffari //   problems in primitive variables
228dc805cc4SLeila Ghaffari // *****************************************************************************
229dc805cc4SLeila Ghaffari CEED_QFUNCTION(ICsNewtonianIG_Prim)(void *ctx, CeedInt Q,
230dc805cc4SLeila Ghaffari                                     const CeedScalar *const *in, CeedScalar *const *out) {
231dc805cc4SLeila Ghaffari   // Outputs
232dc805cc4SLeila Ghaffari   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
233dc805cc4SLeila Ghaffari 
234dc805cc4SLeila Ghaffari   // Context
235dc805cc4SLeila Ghaffari   const SetupContext context = (SetupContext)ctx;
236dc805cc4SLeila Ghaffari   const CeedScalar theta0    = context->theta0;
237dc805cc4SLeila Ghaffari   const CeedScalar P0        = context->P0;
238dc805cc4SLeila Ghaffari 
239dc805cc4SLeila Ghaffari   // Quadrature Point Loop
240dc805cc4SLeila Ghaffari   CeedPragmaSIMD
241dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
242dc805cc4SLeila Ghaffari     CeedScalar q[5] = {0.};
243dc805cc4SLeila Ghaffari 
244dc805cc4SLeila Ghaffari     // Initial Conditions
245dc805cc4SLeila Ghaffari     q[0] = P0;
246dc805cc4SLeila Ghaffari     q[1] = 0.0;
247dc805cc4SLeila Ghaffari     q[2] = 0.0;
248dc805cc4SLeila Ghaffari     q[3] = 0.0;
249dc805cc4SLeila Ghaffari     q[4] = theta0;
250dc805cc4SLeila Ghaffari 
251dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
252dc805cc4SLeila Ghaffari       q0[j][i] = q[j];
253dc805cc4SLeila Ghaffari 
254dc805cc4SLeila Ghaffari   } // End of Quadrature Point Loop
255dc805cc4SLeila Ghaffari   return 0;
256dc805cc4SLeila Ghaffari }
257dc805cc4SLeila Ghaffari 
258dc805cc4SLeila Ghaffari // *****************************************************************************
25988b783a1SJames Wright // This QFunction implements the following formulation of Navier-Stokes with
26088b783a1SJames Wright //   explicit time stepping method
26188b783a1SJames Wright //
26288b783a1SJames Wright // This is 3D compressible Navier-Stokes in conservation form with state
26388b783a1SJames Wright //   variables of density, momentum density, and total energy density.
26488b783a1SJames Wright //
26588b783a1SJames Wright // State Variables: q = ( rho, U1, U2, U3, E )
26688b783a1SJames Wright //   rho - Mass Density
26788b783a1SJames Wright //   Ui  - Momentum Density,      Ui = rho ui
26888b783a1SJames Wright //   E   - Total Energy Density,  E  = rho (cv T + (u u)/2 + g z)
26988b783a1SJames Wright //
27088b783a1SJames Wright // Navier-Stokes Equations:
27188b783a1SJames Wright //   drho/dt + div( U )                               = 0
27288b783a1SJames Wright //   dU/dt   + div( rho (u x u) + P I3 ) + rho g khat = div( Fu )
27388b783a1SJames Wright //   dE/dt   + div( (E + P) u )                       = div( Fe )
27488b783a1SJames Wright //
27588b783a1SJames Wright // Viscous Stress:
27688b783a1SJames Wright //   Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3)
27788b783a1SJames Wright //
27888b783a1SJames Wright // Thermal Stress:
27988b783a1SJames Wright //   Fe = u Fu + k grad( T )
28088626eedSJames Wright // Equation of State
28188b783a1SJames Wright //   P = (gamma - 1) (E - rho (u u) / 2 - rho g z)
28288b783a1SJames Wright //
28388b783a1SJames Wright // Stabilization:
28488b783a1SJames Wright //   Tau = diag(TauC, TauM, TauM, TauM, TauE)
28588b783a1SJames Wright //     f1 = rho  sqrt(ui uj gij)
28688b783a1SJames Wright //     gij = dXi/dX * dXi/dX
28788b783a1SJames Wright //     TauC = Cc f1 / (8 gii)
28888b783a1SJames Wright //     TauM = min( 1 , 1 / f1 )
28988b783a1SJames Wright //     TauE = TauM / (Ce cv)
29088b783a1SJames Wright //
29188b783a1SJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
29288b783a1SJames Wright //
29388b783a1SJames Wright // Constants:
29488b783a1SJames Wright //   lambda = - 2 / 3,  From Stokes hypothesis
29588b783a1SJames Wright //   mu              ,  Dynamic viscosity
29688b783a1SJames Wright //   k               ,  Thermal conductivity
29788b783a1SJames Wright //   cv              ,  Specific heat, constant volume
29888b783a1SJames Wright //   cp              ,  Specific heat, constant pressure
29988b783a1SJames Wright //   g               ,  Gravity
30088b783a1SJames Wright //   gamma  = cp / cv,  Specific heat ratio
30188b783a1SJames Wright //
30288b783a1SJames Wright // We require the product of the inverse of the Jacobian (dXdx_j,k) and
30388b783a1SJames Wright // its transpose (dXdx_k,j) to properly compute integrals of the form:
30488b783a1SJames Wright // int( gradv gradu )
30588b783a1SJames Wright //
30688b783a1SJames Wright // *****************************************************************************
3075c677226SJed Brown CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q,
30888b783a1SJames Wright                                       const CeedScalar *const *in, CeedScalar *const *out) {
30988b783a1SJames Wright   // *INDENT-OFF*
31088b783a1SJames Wright   // Inputs
31188b783a1SJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
312a3ae0734SJed Brown                    (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
31388b783a1SJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
31488b783a1SJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3];
31588b783a1SJames Wright   // Outputs
31688b783a1SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
317a3ae0734SJed Brown              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
31888b783a1SJames Wright   // *INDENT-ON*
31988b783a1SJames Wright 
32088b783a1SJames Wright   // Context
32188b783a1SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
32288b783a1SJames Wright   const CeedScalar mu     = context->mu;
32388b783a1SJames Wright   const CeedScalar cv     = context->cv;
32488b783a1SJames Wright   const CeedScalar cp     = context->cp;
32588626eedSJames Wright   const CeedScalar *g     = context->g;
32688626eedSJames Wright   const CeedScalar dt     = context->dt;
32788b783a1SJames Wright   const CeedScalar gamma  = cp / cv;
32888626eedSJames Wright   const CeedScalar Rd     = cp - cv;
32988b783a1SJames Wright 
33088b783a1SJames Wright   CeedPragmaSIMD
33188b783a1SJames Wright   // Quadrature Point Loop
33288b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
3335c677226SJed Brown     CeedScalar U[5];
3345c677226SJed Brown     for (int j=0; j<5; j++) U[j] = q[j][i];
3355c677226SJed Brown     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
3365c677226SJed Brown     State s = StateFromU(context, U, x_i);
3375c677226SJed Brown 
33888b783a1SJames Wright     // -- Interp-to-Interp q_data
33988b783a1SJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
34088b783a1SJames Wright     // -- Interp-to-Grad q_data
34188b783a1SJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
34288b783a1SJames Wright     // *INDENT-OFF*
34388b783a1SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
34488b783a1SJames Wright                                     q_data[2][i],
34588b783a1SJames Wright                                     q_data[3][i]},
34688b783a1SJames Wright                                    {q_data[4][i],
34788b783a1SJames Wright                                     q_data[5][i],
34888b783a1SJames Wright                                     q_data[6][i]},
34988b783a1SJames Wright                                    {q_data[7][i],
35088b783a1SJames Wright                                     q_data[8][i],
35188b783a1SJames Wright                                     q_data[9][i]}
35288b783a1SJames Wright                                   };
35388b783a1SJames Wright     // *INDENT-ON*
3545c677226SJed Brown     State grad_s[3];
3553c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) {
3566f00d0e6SJed Brown       CeedScalar dx_i[3] = {0}, dU[5];
35739c69132SJed Brown       for (CeedInt k=0; k<5; k++)
35839c69132SJed Brown         dU[k] = Grad_q[0][k][i] * dXdx[0][j] +
35939c69132SJed Brown                 Grad_q[1][k][i] * dXdx[1][j] +
36039c69132SJed Brown                 Grad_q[2][k][i] * dXdx[2][j];
3615c677226SJed Brown       dx_i[j] = 1.;
3626f00d0e6SJed Brown       grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i);
3635c677226SJed Brown     }
3645c677226SJed Brown 
3655c677226SJed Brown     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
3665c677226SJed Brown     KMStrainRate(grad_s, strain_rate);
3675c677226SJed Brown     NewtonianStress(context, strain_rate, kmstress);
3685c677226SJed Brown     KMUnpack(kmstress, stress);
3695c677226SJed Brown     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
3705c677226SJed Brown 
3715c677226SJed Brown     StateConservative F_inviscid[3];
3725c677226SJed Brown     FluxInviscid(context, s, F_inviscid);
3735c677226SJed Brown 
3745c677226SJed Brown     // Total flux
3755c677226SJed Brown     CeedScalar Flux[5][3];
3763c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) {
3775c677226SJed Brown       Flux[0][j] = F_inviscid[j].density;
3783c4b7af6SJed Brown       for (CeedInt k=0; k<3; k++)
3795c677226SJed Brown         Flux[k+1][j] = F_inviscid[j].momentum[k] - stress[k][j];
3805c677226SJed Brown       Flux[4][j] = F_inviscid[j].E_total + Fe[j];
3815c677226SJed Brown     }
3825c677226SJed Brown 
3833c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) {
3843c4b7af6SJed Brown       for (CeedInt k=0; k<5; k++) {
385a3ae0734SJed Brown         Grad_v[j][k][i] = wdetJ * (dXdx[j][0] * Flux[k][0] +
3865c677226SJed Brown                                    dXdx[j][1] * Flux[k][1] +
3875c677226SJed Brown                                    dXdx[j][2] * Flux[k][2]);
3885c677226SJed Brown       }
3895c677226SJed Brown     }
3905c677226SJed Brown 
3915c677226SJed Brown     const CeedScalar body_force[5] = {0, s.U.density *g[0], s.U.density *g[1], s.U.density *g[2], 0};
3925c677226SJed Brown     for (int j=0; j<5; j++)
3935c677226SJed Brown       v[j][i] = wdetJ * body_force[j];
39488b783a1SJames Wright 
39588b783a1SJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
3965c677226SJed Brown     CeedScalar jacob_F_conv[3][5][5] = {0};
3975c677226SJed Brown     computeFluxJacobian_NS(jacob_F_conv, s.U.density, s.Y.velocity, s.U.E_total,
3985c677226SJed Brown                            gamma, g, x_i);
3995c677226SJed Brown     CeedScalar grad_U[5][3];
400ba6664aeSJames Wright     for (CeedInt j=0; j<3; j++) {
4015c677226SJed Brown       grad_U[0][j] = grad_s[j].U.density;
4023c4b7af6SJed Brown       for (CeedInt k=0; k<3; k++) grad_U[k+1][j] = grad_s[j].U.momentum[k];
4035c677226SJed Brown       grad_U[4][j] = grad_s[j].U.E_total;
40488b783a1SJames Wright     }
40588b783a1SJames Wright 
40688b783a1SJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
40788b783a1SJames Wright     CeedScalar strong_conv[5] = {0};
408ba6664aeSJames Wright     for (CeedInt j=0; j<3; j++)
409ba6664aeSJames Wright       for (CeedInt k=0; k<5; k++)
410ba6664aeSJames Wright         for (CeedInt l=0; l<5; l++)
4115c677226SJed Brown           strong_conv[k] += jacob_F_conv[j][k][l] * grad_U[l][j];
41288b783a1SJames Wright 
41388626eedSJames Wright     // -- Stabilization method: none, SU, or SUPG
41488626eedSJames Wright     CeedScalar stab[5][3] = {{0.}};
41588626eedSJames Wright     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
41688626eedSJames Wright     CeedScalar Tau_d[3] = {0.};
41788b783a1SJames Wright     switch (context->stabilization) {
41888b783a1SJames Wright     case STAB_NONE:        // Galerkin
41988b783a1SJames Wright       break;
42088b783a1SJames Wright     case STAB_SU:        // SU
4215c677226SJed Brown       Tau_diagPrim(Tau_d, dXdx, s.Y.velocity, cv, context, mu, dt, s.U.density);
42288626eedSJames Wright       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
42388626eedSJames Wright       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
42488626eedSJames Wright       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
42588626eedSJames Wright       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
42688626eedSJames Wright       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
4275c677226SJed Brown       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
4285c677226SJed Brown                                   tau_strong_conv,
42988626eedSJames Wright                                   tau_strong_conv_conservative);
430ba6664aeSJames Wright       for (CeedInt j=0; j<3; j++)
431ba6664aeSJames Wright         for (CeedInt k=0; k<5; k++)
432ba6664aeSJames Wright           for (CeedInt l=0; l<5; l++)
43388626eedSJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
43488b783a1SJames Wright 
435ba6664aeSJames Wright       for (CeedInt j=0; j<5; j++)
436ba6664aeSJames Wright         for (CeedInt k=0; k<3; k++)
437a3ae0734SJed Brown           Grad_v[k][j][i] -= wdetJ*(stab[j][0] * dXdx[k][0] +
43888b783a1SJames Wright                                     stab[j][1] * dXdx[k][1] +
43988b783a1SJames Wright                                     stab[j][2] * dXdx[k][2]);
44088b783a1SJames Wright       break;
44188b783a1SJames Wright     case STAB_SUPG:        // SUPG is not implemented for explicit scheme
44288b783a1SJames Wright       break;
44388b783a1SJames Wright     }
44488b783a1SJames Wright 
44588b783a1SJames Wright   } // End Quadrature Point Loop
44688b783a1SJames Wright 
44788b783a1SJames Wright   // Return
44888b783a1SJames Wright   return 0;
44988b783a1SJames Wright }
45088b783a1SJames Wright 
45188b783a1SJames Wright // *****************************************************************************
45288b783a1SJames Wright // This QFunction implements the Navier-Stokes equations (mentioned above) with
45388b783a1SJames Wright //   implicit time stepping method
45488b783a1SJames Wright //
45588b783a1SJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
45688b783a1SJames Wright //  SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) )
45788b783a1SJames Wright //                                       (diffussive terms will be added later)
45888b783a1SJames Wright //
45988b783a1SJames Wright // *****************************************************************************
46088b783a1SJames Wright CEED_QFUNCTION(IFunction_Newtonian)(void *ctx, CeedInt Q,
461dc805cc4SLeila Ghaffari                                     const CeedScalar *const *in, CeedScalar *const *out) {
46288b783a1SJames Wright   // *INDENT-OFF*
46388b783a1SJames Wright   // Inputs
46488b783a1SJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
465a3ae0734SJed Brown                    (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
46688b783a1SJames Wright                    (*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
46788b783a1SJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
46888b783a1SJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
46988b783a1SJames Wright   // Outputs
47088b783a1SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
471a3ae0734SJed Brown              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1],
472a3ae0734SJed Brown              (*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2];
47388b783a1SJames Wright   // *INDENT-ON*
47488b783a1SJames Wright   // Context
47588b783a1SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
47688b783a1SJames Wright   const CeedScalar mu     = context->mu;
47788b783a1SJames Wright   const CeedScalar cv     = context->cv;
47888b783a1SJames Wright   const CeedScalar cp     = context->cp;
47988626eedSJames Wright   const CeedScalar *g     = context->g;
48088626eedSJames Wright   const CeedScalar dt     = context->dt;
48188b783a1SJames Wright   const CeedScalar gamma  = cp / cv;
48288626eedSJames Wright   const CeedScalar Rd     = cp - cv;
48388b783a1SJames Wright 
48488b783a1SJames Wright   CeedPragmaSIMD
48588b783a1SJames Wright   // Quadrature Point Loop
48688b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
4875c677226SJed Brown     CeedScalar U[5];
4883c4b7af6SJed Brown     for (CeedInt j=0; j<5; j++) U[j] = q[j][i];
4895c677226SJed Brown     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
4905c677226SJed Brown     State s = StateFromU(context, U, x_i);
4915c677226SJed Brown 
49288b783a1SJames Wright     // -- Interp-to-Interp q_data
49388b783a1SJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
49488b783a1SJames Wright     // -- Interp-to-Grad q_data
49588b783a1SJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
49688b783a1SJames Wright     // *INDENT-OFF*
49788b783a1SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
49888b783a1SJames Wright                                     q_data[2][i],
49988b783a1SJames Wright                                     q_data[3][i]},
50088b783a1SJames Wright                                    {q_data[4][i],
50188b783a1SJames Wright                                     q_data[5][i],
50288b783a1SJames Wright                                     q_data[6][i]},
50388b783a1SJames Wright                                    {q_data[7][i],
50488b783a1SJames Wright                                     q_data[8][i],
50588b783a1SJames Wright                                     q_data[9][i]}
50688b783a1SJames Wright                                   };
50788b783a1SJames Wright     // *INDENT-ON*
5085c677226SJed Brown     State grad_s[3];
509ba6664aeSJames Wright     for (CeedInt j=0; j<3; j++) {
5106f00d0e6SJed Brown       CeedScalar dx_i[3] = {0}, dU[5];
51139c69132SJed Brown       for (CeedInt k=0; k<5; k++)
51239c69132SJed Brown         dU[k] = Grad_q[0][k][i] * dXdx[0][j] +
51339c69132SJed Brown                 Grad_q[1][k][i] * dXdx[1][j] +
51439c69132SJed Brown                 Grad_q[2][k][i] * dXdx[2][j];
5155c677226SJed Brown       dx_i[j] = 1.;
5166f00d0e6SJed Brown       grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i);
51788b783a1SJames Wright     }
5185c677226SJed Brown 
5195c677226SJed Brown     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
5205c677226SJed Brown     KMStrainRate(grad_s, strain_rate);
5215c677226SJed Brown     NewtonianStress(context, strain_rate, kmstress);
5225c677226SJed Brown     KMUnpack(kmstress, stress);
5235c677226SJed Brown     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
5245c677226SJed Brown 
5255c677226SJed Brown     StateConservative F_inviscid[3];
5265c677226SJed Brown     FluxInviscid(context, s, F_inviscid);
5275c677226SJed Brown 
5285c677226SJed Brown 
5295c677226SJed Brown     // Total flux
5305c677226SJed Brown     CeedScalar Flux[5][3];
5313c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) {
5325c677226SJed Brown       Flux[0][j] = F_inviscid[j].density;
533ba6664aeSJames Wright       for (CeedInt k=0; k<3; k++)
5345c677226SJed Brown         Flux[k+1][j] = F_inviscid[j].momentum[k] - stress[k][j];
5355c677226SJed Brown       Flux[4][j] = F_inviscid[j].E_total + Fe[j];
5365c677226SJed Brown     }
5375c677226SJed Brown 
5383c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) {
5393c4b7af6SJed Brown       for (CeedInt k=0; k<5; k++) {
540a3ae0734SJed Brown         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * Flux[k][0] +
5415c677226SJed Brown                                     dXdx[j][1] * Flux[k][1] +
5425c677226SJed Brown                                     dXdx[j][2] * Flux[k][2]);
5435c677226SJed Brown       }
5445c677226SJed Brown     }
5455c677226SJed Brown 
5465c677226SJed Brown     const CeedScalar body_force[5] = {0, s.U.density *g[0], s.U.density *g[1], s.U.density *g[2], 0};
5473c4b7af6SJed Brown     for (CeedInt j=0; j<5; j++)
5485c677226SJed Brown       v[j][i] = wdetJ * (q_dot[j][i] - body_force[j]);
54988b783a1SJames Wright 
55088b783a1SJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
5515c677226SJed Brown     CeedScalar jacob_F_conv[3][5][5] = {0};
5525c677226SJed Brown     computeFluxJacobian_NS(jacob_F_conv, s.U.density, s.Y.velocity, s.U.E_total,
5535c677226SJed Brown                            gamma, g, x_i);
5545c677226SJed Brown     CeedScalar grad_U[5][3];
555ba6664aeSJames Wright     for (CeedInt j=0; j<3; j++) {
5565c677226SJed Brown       grad_U[0][j] = grad_s[j].U.density;
5573c4b7af6SJed Brown       for (CeedInt k=0; k<3; k++) grad_U[k+1][j] = grad_s[j].U.momentum[k];
5585c677226SJed Brown       grad_U[4][j] = grad_s[j].U.E_total;
55988b783a1SJames Wright     }
5605c677226SJed Brown 
56188b783a1SJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
56288b783a1SJames Wright     CeedScalar strong_conv[5] = {0};
563ba6664aeSJames Wright     for (CeedInt j=0; j<3; j++)
564ba6664aeSJames Wright       for (CeedInt k=0; k<5; k++)
565ba6664aeSJames Wright         for (CeedInt l=0; l<5; l++)
5665c677226SJed Brown           strong_conv[k] += jacob_F_conv[j][k][l] * grad_U[l][j];
56788b783a1SJames Wright 
56888b783a1SJames Wright     // Strong residual
56988b783a1SJames Wright     CeedScalar strong_res[5];
570ba6664aeSJames Wright     for (CeedInt j=0; j<5; j++)
57188b783a1SJames Wright       strong_res[j] = q_dot[j][i] + strong_conv[j] - body_force[j];
57288b783a1SJames Wright 
57388b783a1SJames Wright     // -- Stabilization method: none, SU, or SUPG
57488626eedSJames Wright     CeedScalar stab[5][3] = {{0.}};
57588626eedSJames Wright     CeedScalar tau_strong_res[5] = {0.}, tau_strong_res_conservative[5] = {0};
57688626eedSJames Wright     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
57788626eedSJames Wright     CeedScalar Tau_d[3] = {0.};
57888b783a1SJames Wright     switch (context->stabilization) {
57988b783a1SJames Wright     case STAB_NONE:        // Galerkin
58088b783a1SJames Wright       break;
58188b783a1SJames Wright     case STAB_SU:        // SU
5825c677226SJed Brown       Tau_diagPrim(Tau_d, dXdx, s.Y.velocity, cv, context, mu, dt, s.U.density);
58388626eedSJames Wright       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
58488626eedSJames Wright       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
58588626eedSJames Wright       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
58688626eedSJames Wright       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
58788626eedSJames Wright       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
5885c677226SJed Brown       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
5895c677226SJed Brown                                   tau_strong_conv, tau_strong_conv_conservative);
590ba6664aeSJames Wright       for (CeedInt j=0; j<3; j++)
591ba6664aeSJames Wright         for (CeedInt k=0; k<5; k++)
592ba6664aeSJames Wright           for (CeedInt l=0; l<5; l++)
59388626eedSJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
59488b783a1SJames Wright 
595ba6664aeSJames Wright       for (CeedInt j=0; j<5; j++)
596ba6664aeSJames Wright         for (CeedInt k=0; k<3; k++)
597a3ae0734SJed Brown           Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
59888b783a1SJames Wright                                     stab[j][1] * dXdx[k][1] +
59988b783a1SJames Wright                                     stab[j][2] * dXdx[k][2]);
6003c4b7af6SJed Brown 
60188b783a1SJames Wright       break;
60288b783a1SJames Wright     case STAB_SUPG:        // SUPG
6035c677226SJed Brown       Tau_diagPrim(Tau_d, dXdx, s.Y.velocity, cv, context, mu, dt, s.U.density);
60488626eedSJames Wright       tau_strong_res[0] = Tau_d[0] * strong_res[0];
60588626eedSJames Wright       tau_strong_res[1] = Tau_d[1] * strong_res[1];
60688626eedSJames Wright       tau_strong_res[2] = Tau_d[1] * strong_res[2];
60788626eedSJames Wright       tau_strong_res[3] = Tau_d[1] * strong_res[3];
60888626eedSJames Wright       tau_strong_res[4] = Tau_d[2] * strong_res[4];
609dc805cc4SLeila Ghaffari 
6105c677226SJed Brown       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
6115c677226SJed Brown                                   tau_strong_res, tau_strong_res_conservative);
612ba6664aeSJames Wright       for (CeedInt j=0; j<3; j++)
613ba6664aeSJames Wright         for (CeedInt k=0; k<5; k++)
614ba6664aeSJames Wright           for (CeedInt l=0; l<5; l++)
61588626eedSJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_res_conservative[l];
61688b783a1SJames Wright 
617ba6664aeSJames Wright       for (CeedInt j=0; j<5; j++)
618ba6664aeSJames Wright         for (CeedInt k=0; k<3; k++)
619a3ae0734SJed Brown           Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
62088b783a1SJames Wright                                     stab[j][1] * dXdx[k][1] +
62188b783a1SJames Wright                                     stab[j][2] * dXdx[k][2]);
62288b783a1SJames Wright       break;
62388b783a1SJames Wright     }
6243c4b7af6SJed Brown     for (CeedInt j=0; j<5; j++) jac_data[j][i] = U[j];
6253c4b7af6SJed Brown     for (CeedInt j=0; j<6; j++) jac_data[5+j][i] = kmstress[j];
6263c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) jac_data[5+6+j][i] = Tau_d[j];
62788b783a1SJames Wright 
62888b783a1SJames Wright   } // End Quadrature Point Loop
62988b783a1SJames Wright 
63088b783a1SJames Wright   // Return
63188b783a1SJames Wright   return 0;
63288b783a1SJames Wright }
633e334ad8fSJed Brown 
634dc805cc4SLeila Ghaffari // *****************************************************************************
635dc805cc4SLeila Ghaffari // This QFunction implements the jacobean of the Navier-Stokes equations
636dc805cc4SLeila Ghaffari //   for implicit time stepping method.
637dc805cc4SLeila Ghaffari //
638dc805cc4SLeila Ghaffari // *****************************************************************************
639e334ad8fSJed Brown CEED_QFUNCTION(IJacobian_Newtonian)(void *ctx, CeedInt Q,
640e334ad8fSJed Brown                                     const CeedScalar *const *in,
641e334ad8fSJed Brown                                     CeedScalar *const *out) {
642e334ad8fSJed Brown   // *INDENT-OFF*
643e334ad8fSJed Brown   // Inputs
644e334ad8fSJed Brown   const CeedScalar (*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
645e334ad8fSJed Brown                    (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
646e334ad8fSJed Brown                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
647e334ad8fSJed Brown                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
648e334ad8fSJed Brown                    (*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
649e334ad8fSJed Brown   // Outputs
650e334ad8fSJed Brown   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
651e334ad8fSJed Brown              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
652e334ad8fSJed Brown   // *INDENT-ON*
653e334ad8fSJed Brown   // Context
654e334ad8fSJed Brown   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
655e334ad8fSJed Brown   const CeedScalar *g = context->g;
656e334ad8fSJed Brown   const CeedScalar cp = context->cp;
657e334ad8fSJed Brown   const CeedScalar cv = context->cv;
658e334ad8fSJed Brown   const CeedScalar Rd = cp - cv;
659e334ad8fSJed Brown   const CeedScalar gamma = cp / cv;
660e334ad8fSJed Brown 
661e334ad8fSJed Brown   CeedPragmaSIMD
662e334ad8fSJed Brown   // Quadrature Point Loop
663e334ad8fSJed Brown   for (CeedInt i=0; i<Q; i++) {
664e334ad8fSJed Brown     // -- Interp-to-Interp q_data
665e334ad8fSJed Brown     const CeedScalar wdetJ      =   q_data[0][i];
666e334ad8fSJed Brown     // -- Interp-to-Grad q_data
667e334ad8fSJed Brown     // ---- Inverse of change of coordinate matrix: X_i,j
668e334ad8fSJed Brown     // *INDENT-OFF*
669e334ad8fSJed Brown     const CeedScalar dXdx[3][3] = {{q_data[1][i],
670e334ad8fSJed Brown                                     q_data[2][i],
671e334ad8fSJed Brown                                     q_data[3][i]},
672e334ad8fSJed Brown                                    {q_data[4][i],
673e334ad8fSJed Brown                                     q_data[5][i],
674e334ad8fSJed Brown                                     q_data[6][i]},
675e334ad8fSJed Brown                                    {q_data[7][i],
676e334ad8fSJed Brown                                     q_data[8][i],
677e334ad8fSJed Brown                                     q_data[9][i]}
678e334ad8fSJed Brown                                   };
679e334ad8fSJed Brown     // *INDENT-ON*
680e334ad8fSJed Brown 
681e334ad8fSJed Brown     CeedScalar U[5], kmstress[6], Tau_d[3] __attribute((unused));
682e334ad8fSJed Brown     for (int j=0; j<5; j++) U[j] = jac_data[j][i];
683e334ad8fSJed Brown     for (int j=0; j<6; j++) kmstress[j] = jac_data[5+j][i];
684e334ad8fSJed Brown     for (int j=0; j<3; j++) Tau_d[j] = jac_data[5+6+j][i];
685e334ad8fSJed Brown     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
686e334ad8fSJed Brown     State s = StateFromU(context, U, x_i);
687e334ad8fSJed Brown 
688e334ad8fSJed Brown     CeedScalar dU[5], dx0[3] = {0};
689e334ad8fSJed Brown     for (int j=0; j<5; j++) dU[j] = dq[j][i];
690e334ad8fSJed Brown     State ds = StateFromU_fwd(context, s, dU, x_i, dx0);
691e334ad8fSJed Brown 
692e334ad8fSJed Brown     State grad_ds[3];
693e334ad8fSJed Brown     for (int j=0; j<3; j++) {
694e334ad8fSJed Brown       CeedScalar dUj[5];
695e334ad8fSJed Brown       for (int k=0; k<5; k++) dUj[k] = Grad_dq[0][k][i] * dXdx[0][j]
696e334ad8fSJed Brown                                          + Grad_dq[1][k][i] * dXdx[1][j]
697e334ad8fSJed Brown                                          + Grad_dq[2][k][i] * dXdx[2][j];
698e334ad8fSJed Brown       grad_ds[j] = StateFromU_fwd(context, s, dUj, x_i, dx0);
699e334ad8fSJed Brown     }
700e334ad8fSJed Brown 
701e334ad8fSJed Brown     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
702e334ad8fSJed Brown     KMStrainRate(grad_ds, dstrain_rate);
703e334ad8fSJed Brown     NewtonianStress(context, dstrain_rate, dkmstress);
704e334ad8fSJed Brown     KMUnpack(dkmstress, dstress);
705e334ad8fSJed Brown     KMUnpack(kmstress, stress);
706e334ad8fSJed Brown     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
707e334ad8fSJed Brown 
708e334ad8fSJed Brown     StateConservative dF_inviscid[3];
709e334ad8fSJed Brown     FluxInviscid_fwd(context, s, ds, dF_inviscid);
710e334ad8fSJed Brown 
711e334ad8fSJed Brown     // Total flux
712e334ad8fSJed Brown     CeedScalar dFlux[5][3];
713e334ad8fSJed Brown     for (int j=0; j<3; j++) {
714e334ad8fSJed Brown       dFlux[0][j] = dF_inviscid[j].density;
715e334ad8fSJed Brown       for (int k=0; k<3; k++)
716e334ad8fSJed Brown         dFlux[k+1][j] = dF_inviscid[j].momentum[k] - dstress[k][j];
717e334ad8fSJed Brown       dFlux[4][j] = dF_inviscid[j].E_total + dFe[j];
718e334ad8fSJed Brown     }
719e334ad8fSJed Brown 
720e334ad8fSJed Brown     for (int j=0; j<3; j++) {
721e334ad8fSJed Brown       for (int k=0; k<5; k++) {
722e334ad8fSJed Brown         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * dFlux[k][0] +
723e334ad8fSJed Brown                                     dXdx[j][1] * dFlux[k][1] +
724e334ad8fSJed Brown                                     dXdx[j][2] * dFlux[k][2]);
725e334ad8fSJed Brown       }
726e334ad8fSJed Brown     }
727e334ad8fSJed Brown 
728e334ad8fSJed Brown     const CeedScalar dbody_force[5] = {0, ds.U.density *g[0], ds.U.density *g[1], ds.U.density *g[2], 0};
729e334ad8fSJed Brown     for (int j=0; j<5; j++)
730e334ad8fSJed Brown       v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]);
731e334ad8fSJed Brown 
732e334ad8fSJed Brown     if (1) {
733e334ad8fSJed Brown       CeedScalar jacob_F_conv[3][5][5] = {0};
734e334ad8fSJed Brown       computeFluxJacobian_NS(jacob_F_conv, s.U.density, s.Y.velocity, s.U.E_total,
735e334ad8fSJed Brown                              gamma, g, x_i);
736e334ad8fSJed Brown       CeedScalar grad_dU[5][3];
737e334ad8fSJed Brown       for (int j=0; j<3; j++) {
738e334ad8fSJed Brown         grad_dU[0][j] = grad_ds[j].U.density;
739e334ad8fSJed Brown         for (int k=0; k<3; k++) grad_dU[k+1][j] = grad_ds[j].U.momentum[k];
740e334ad8fSJed Brown         grad_dU[4][j] = grad_ds[j].U.E_total;
741e334ad8fSJed Brown       }
742e334ad8fSJed Brown       CeedScalar dstrong_conv[5] = {0};
743e334ad8fSJed Brown       for (int j=0; j<3; j++)
744e334ad8fSJed Brown         for (int k=0; k<5; k++)
745e334ad8fSJed Brown           for (int l=0; l<5; l++)
746e334ad8fSJed Brown             dstrong_conv[k] += jacob_F_conv[j][k][l] * grad_dU[l][j];
747e334ad8fSJed Brown       CeedScalar dstrong_res[5];
748e334ad8fSJed Brown       for (int j=0; j<5; j++)
749e334ad8fSJed Brown         dstrong_res[j] = context->ijacobian_time_shift * dU[j] + dstrong_conv[j] -
750e334ad8fSJed Brown                          dbody_force[j];
751e334ad8fSJed Brown       CeedScalar dtau_strong_res[5] = {0.}, dtau_strong_res_conservative[5] = {0};
752e334ad8fSJed Brown       dtau_strong_res[0] = Tau_d[0] * dstrong_res[0];
753e334ad8fSJed Brown       dtau_strong_res[1] = Tau_d[1] * dstrong_res[1];
754e334ad8fSJed Brown       dtau_strong_res[2] = Tau_d[1] * dstrong_res[2];
755e334ad8fSJed Brown       dtau_strong_res[3] = Tau_d[1] * dstrong_res[3];
756e334ad8fSJed Brown       dtau_strong_res[4] = Tau_d[2] * dstrong_res[4];
757e334ad8fSJed Brown       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
758e334ad8fSJed Brown                                   dtau_strong_res, dtau_strong_res_conservative);
759e334ad8fSJed Brown       CeedScalar dstab[5][3] = {0};
760e334ad8fSJed Brown       for (int j=0; j<3; j++)
761e334ad8fSJed Brown         for (int k=0; k<5; k++)
762e334ad8fSJed Brown           for (int l=0; l<5; l++)
763e334ad8fSJed Brown             dstab[k][j] += jacob_F_conv[j][k][l] * dtau_strong_res_conservative[l];
764e334ad8fSJed Brown       for (int j=0; j<5; j++)
765e334ad8fSJed Brown         for (int k=0; k<3; k++)
766e334ad8fSJed Brown           Grad_v[k][j][i] += wdetJ*(dstab[j][0] * dXdx[k][0] +
767e334ad8fSJed Brown                                     dstab[j][1] * dXdx[k][1] +
768e334ad8fSJed Brown                                     dstab[j][2] * dXdx[k][2]);
769e334ad8fSJed Brown 
770e334ad8fSJed Brown     }
771e334ad8fSJed Brown   } // End Quadrature Point Loop
772e334ad8fSJed Brown   return 0;
773e334ad8fSJed Brown }
77465dd5cafSJames Wright 
77565dd5cafSJames Wright // Compute boundary integral (ie. for strongly set inflows)
77665dd5cafSJames Wright CEED_QFUNCTION(BoundaryIntegral)(void *ctx, CeedInt Q,
77765dd5cafSJames Wright                                  const CeedScalar *const *in,
77865dd5cafSJames Wright                                  CeedScalar *const *out) {
77965dd5cafSJames Wright 
78065dd5cafSJames Wright   //*INDENT-OFF*
78165dd5cafSJames Wright   const CeedScalar (*q)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[0],
7822c4e60d7SJames Wright                    (*Grad_q)[5][CEED_Q_VLA]  = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
7832c4e60d7SJames Wright                    (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
7842c4e60d7SJames Wright                    (*x)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[3];
78565dd5cafSJames Wright 
786b55ac660SJames Wright   CeedScalar (*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA]) out[0],
787b55ac660SJames Wright              (*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA]) out[1];
78865dd5cafSJames Wright 
78965dd5cafSJames Wright   //*INDENT-ON*
79065dd5cafSJames Wright 
7912c4e60d7SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext) ctx;
7922c4e60d7SJames Wright   const bool is_implicit  = context->is_implicit;
79365dd5cafSJames Wright 
79465dd5cafSJames Wright   CeedPragmaSIMD
79565dd5cafSJames Wright   for(CeedInt i=0; i<Q; i++) {
7962c4e60d7SJames Wright     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
797*57e55a1cSJames Wright     const CeedScalar solution_state[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
798*57e55a1cSJames Wright     State s = context->is_primitive ? StateFromY(context, solution_state, x_i)
799*57e55a1cSJames Wright               : StateFromU(context, solution_state, x_i);
80065dd5cafSJames Wright 
80165dd5cafSJames Wright     const CeedScalar wdetJb  = (is_implicit ? -1. : 1.) * q_data_sur[0][i];
80265dd5cafSJames Wright     // ---- Normal vect
80365dd5cafSJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
80465dd5cafSJames Wright                                 q_data_sur[2][i],
80565dd5cafSJames Wright                                 q_data_sur[3][i]
80665dd5cafSJames Wright                                };
80765dd5cafSJames Wright 
8082c4e60d7SJames Wright     const CeedScalar dXdx[2][3] = {
8092c4e60d7SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
8102c4e60d7SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
8112c4e60d7SJames Wright     };
81265dd5cafSJames Wright 
8132c4e60d7SJames Wright     State grad_s[3];
8142c4e60d7SJames Wright     for (CeedInt j=0; j<3; j++) {
8152c4e60d7SJames Wright       CeedScalar dx_i[3] = {0}, dU[5];
8162c4e60d7SJames Wright       for (CeedInt k=0; k<5; k++)
8172c4e60d7SJames Wright         dU[k] = Grad_q[0][k][i] * dXdx[0][j] +
8182c4e60d7SJames Wright                 Grad_q[1][k][i] * dXdx[1][j];
8192c4e60d7SJames Wright       dx_i[j] = 1.;
8202c4e60d7SJames Wright       grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i);
8212c4e60d7SJames Wright     }
82265dd5cafSJames Wright 
8232c4e60d7SJames Wright     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
8242c4e60d7SJames Wright     KMStrainRate(grad_s, strain_rate);
8252c4e60d7SJames Wright     NewtonianStress(context, strain_rate, kmstress);
8262c4e60d7SJames Wright     KMUnpack(kmstress, stress);
8272c4e60d7SJames Wright     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
8282c4e60d7SJames Wright 
8292c4e60d7SJames Wright     StateConservative F_inviscid[3];
8302c4e60d7SJames Wright     FluxInviscid(context, s, F_inviscid);
8312c4e60d7SJames Wright 
8322c4e60d7SJames Wright     CeedScalar Flux[5] = {0.};
8332c4e60d7SJames Wright     for (int j=0; j<3; j++) {
8342c4e60d7SJames Wright       Flux[0] += F_inviscid[j].density * norm[j];
8352c4e60d7SJames Wright       for (int k=0; k<3; k++)
8362c4e60d7SJames Wright         Flux[k+1] += (F_inviscid[j].momentum[k] - stress[k][j]) * norm[j];
8372c4e60d7SJames Wright       Flux[4] += (F_inviscid[j].E_total + Fe[j])*norm[j];
8382c4e60d7SJames Wright     }
8392c4e60d7SJames Wright 
84065dd5cafSJames Wright     // -- Density
8412c4e60d7SJames Wright     v[0][i] = -wdetJb * Flux[0];
84265dd5cafSJames Wright 
84365dd5cafSJames Wright     // -- Momentum
84465dd5cafSJames Wright     for (CeedInt j=0; j<3; j++)
8452c4e60d7SJames Wright       v[j+1][i] = -wdetJb * Flux[j+1];
84665dd5cafSJames Wright 
84765dd5cafSJames Wright     // -- Total Energy Density
8482c4e60d7SJames Wright     v[4][i] = -wdetJb * Flux[4];
849b55ac660SJames Wright 
850*57e55a1cSJames Wright     if (context->is_primitive) {
851*57e55a1cSJames Wright       jac_data_sur[0][i] = s.Y.pressure;
852*57e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.Y.velocity[j];
853*57e55a1cSJames Wright       jac_data_sur[4][i] = s.Y.temperature;
854*57e55a1cSJames Wright     } else {
855b55ac660SJames Wright       jac_data_sur[0][i] = s.U.density;
856*57e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.U.momentum[j];
857b55ac660SJames Wright       jac_data_sur[4][i] = s.U.E_total;
858*57e55a1cSJames Wright     }
859b55ac660SJames Wright     for (int j=0; j<6; j++) jac_data_sur[5+j][i] = kmstress[j];
86065dd5cafSJames Wright   }
86165dd5cafSJames Wright   return 0;
86265dd5cafSJames Wright }
86365dd5cafSJames Wright 
864b55ac660SJames Wright // Jacobian for "set nothing" boundary integral
865b55ac660SJames Wright CEED_QFUNCTION(BoundaryIntegral_Jacobian)(void *ctx, CeedInt Q,
866b55ac660SJames Wright     const CeedScalar *const *in,
867b55ac660SJames Wright     CeedScalar *const *out) {
868b55ac660SJames Wright   // *INDENT-OFF*
869b55ac660SJames Wright   // Inputs
870b55ac660SJames Wright   const CeedScalar (*dq)[CEED_Q_VLA]           = (const CeedScalar(*)[CEED_Q_VLA])in[0],
871b55ac660SJames Wright                    (*Grad_dq)[5][CEED_Q_VLA]   = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
872b55ac660SJames Wright                    (*q_data_sur)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[2],
873b55ac660SJames Wright                    (*x)[CEED_Q_VLA]            = (const CeedScalar(*)[CEED_Q_VLA])in[3],
874b55ac660SJames Wright                    (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
875b55ac660SJames Wright   // Outputs
876b55ac660SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
877b55ac660SJames Wright   // *INDENT-ON*
878b55ac660SJames Wright 
879b55ac660SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
880b55ac660SJames Wright   const bool implicit     = context->is_implicit;
881b55ac660SJames Wright 
882b55ac660SJames Wright   CeedPragmaSIMD
883b55ac660SJames Wright   // Quadrature Point Loop
884b55ac660SJames Wright   for (CeedInt i=0; i<Q; i++) {
885b55ac660SJames Wright     const CeedScalar x_i[3]  = {x[0][i], x[1][i], x[2][i]};
886b55ac660SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
887b55ac660SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
888b55ac660SJames Wright                                 q_data_sur[2][i],
889b55ac660SJames Wright                                 q_data_sur[3][i]
890b55ac660SJames Wright                                };
891b55ac660SJames Wright     const CeedScalar dXdx[2][3] = {
892b55ac660SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
893b55ac660SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
894b55ac660SJames Wright     };
895b55ac660SJames Wright 
896*57e55a1cSJames Wright     CeedScalar state[5], kmstress[6], dstate[5], dx_i[3] = {0.};
897*57e55a1cSJames Wright     for (int j=0; j<5; j++) state[j]    = jac_data_sur[j][i];
898b55ac660SJames Wright     for (int j=0; j<6; j++) kmstress[j] = jac_data_sur[5+j][i];
899*57e55a1cSJames Wright     for (int j=0; j<5; j++) dstate[j]   = dq[j][i];
900*57e55a1cSJames Wright 
901*57e55a1cSJames Wright     State s, ds;
902*57e55a1cSJames Wright     if (context->is_primitive) {
903*57e55a1cSJames Wright       s  = StateFromY(context, state, x_i);
904*57e55a1cSJames Wright       ds = StateFromY_fwd(context, s, dstate, x_i, dx_i);
905*57e55a1cSJames Wright     } else {
906*57e55a1cSJames Wright       s  = StateFromU(context, state, x_i);
907*57e55a1cSJames Wright       ds = StateFromU_fwd(context, s, dstate, x_i, dx_i);
908*57e55a1cSJames Wright     }
909b55ac660SJames Wright 
910b55ac660SJames Wright     State grad_ds[3];
911b55ac660SJames Wright     for (CeedInt j=0; j<3; j++) {
912b55ac660SJames Wright       CeedScalar dx_i[3] = {0}, dUj[5];
913b55ac660SJames Wright       for (CeedInt k=0; k<5; k++)
914b55ac660SJames Wright         dUj[k] = Grad_dq[0][k][i] * dXdx[0][j] +
915b55ac660SJames Wright                  Grad_dq[1][k][i] * dXdx[1][j];
916b55ac660SJames Wright       dx_i[j] = 1.;
917b55ac660SJames Wright       grad_ds[j] = StateFromU_fwd(context, s, dUj, x_i, dx_i);
918b55ac660SJames Wright     }
919b55ac660SJames Wright 
920b55ac660SJames Wright     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
921b55ac660SJames Wright     KMStrainRate(grad_ds, dstrain_rate);
922b55ac660SJames Wright     NewtonianStress(context, dstrain_rate, dkmstress);
923b55ac660SJames Wright     KMUnpack(dkmstress, dstress);
924b55ac660SJames Wright     KMUnpack(kmstress, stress);
925b55ac660SJames Wright     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
926b55ac660SJames Wright 
927b55ac660SJames Wright     StateConservative dF_inviscid[3];
928b55ac660SJames Wright     FluxInviscid_fwd(context, s, ds, dF_inviscid);
929b55ac660SJames Wright 
930b55ac660SJames Wright     CeedScalar dFlux[5] = {0.};
931b55ac660SJames Wright     for (int j=0; j<3; j++) {
932b55ac660SJames Wright       dFlux[0] += dF_inviscid[j].density * norm[j];
933b55ac660SJames Wright       for (int k=0; k<3; k++)
934b55ac660SJames Wright         dFlux[k+1] += (dF_inviscid[j].momentum[k] - dstress[k][j]) * norm[j];
935b55ac660SJames Wright       dFlux[4] += (dF_inviscid[j].E_total + dFe[j]) * norm[j];
936b55ac660SJames Wright     }
937b55ac660SJames Wright 
938b55ac660SJames Wright     for (int j=0; j<5; j++)
939b55ac660SJames Wright       v[j][i] = -wdetJb * dFlux[j];
940b55ac660SJames Wright   } // End Quadrature Point Loop
941b55ac660SJames Wright   return 0;
942b55ac660SJames Wright }
943b55ac660SJames Wright 
94430e9fa81SJames Wright // Outflow boundary condition, weakly setting a constant pressure
94530e9fa81SJames Wright CEED_QFUNCTION(PressureOutflow)(void *ctx, CeedInt Q,
94630e9fa81SJames Wright                                 const CeedScalar *const *in,
94730e9fa81SJames Wright                                 CeedScalar *const *out) {
94830e9fa81SJames Wright   // *INDENT-OFF*
94930e9fa81SJames Wright   // Inputs
95030e9fa81SJames Wright   const CeedScalar (*q)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[0],
951ce9b5c20SJames Wright                    (*Grad_q)[5][CEED_Q_VLA]  = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
952ce9b5c20SJames Wright                    (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
953ce9b5c20SJames Wright                    (*x)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[3];
95430e9fa81SJames Wright   // Outputs
95530e9fa81SJames Wright   CeedScalar (*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA])out[0],
95630e9fa81SJames Wright              (*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1];
95730e9fa81SJames Wright   // *INDENT-ON*
95830e9fa81SJames Wright 
95930e9fa81SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
96030e9fa81SJames Wright   const bool       implicit = context->is_implicit;
96130e9fa81SJames Wright   const CeedScalar P0       = context->P0;
96230e9fa81SJames Wright 
96330e9fa81SJames Wright   CeedPragmaSIMD
96430e9fa81SJames Wright   // Quadrature Point Loop
96530e9fa81SJames Wright   for (CeedInt i=0; i<Q; i++) {
96630e9fa81SJames Wright     // Setup
96730e9fa81SJames Wright     // -- Interp in
968ce9b5c20SJames Wright     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
969*57e55a1cSJames Wright     const CeedScalar solution_state[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
970*57e55a1cSJames Wright     State s = context->is_primitive ? StateFromY(context, solution_state, x_i)
971*57e55a1cSJames Wright               : StateFromU(context, solution_state, x_i);
972ce9b5c20SJames Wright     s.Y.pressure = P0;
97330e9fa81SJames Wright 
97430e9fa81SJames Wright     // -- Interp-to-Interp q_data
97530e9fa81SJames Wright     // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q).
97630e9fa81SJames Wright     // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q).
97730e9fa81SJames Wright     // We can effect this by swapping the sign on this weight
97830e9fa81SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
97930e9fa81SJames Wright 
98030e9fa81SJames Wright     // ---- Normal vect
98130e9fa81SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
98230e9fa81SJames Wright                                 q_data_sur[2][i],
98330e9fa81SJames Wright                                 q_data_sur[3][i]
98430e9fa81SJames Wright                                };
98530e9fa81SJames Wright 
986ce9b5c20SJames Wright     const CeedScalar dXdx[2][3] = {
987ce9b5c20SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
988ce9b5c20SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
989ce9b5c20SJames Wright     };
99030e9fa81SJames Wright 
991ce9b5c20SJames Wright     State grad_s[3];
992ce9b5c20SJames Wright     for (CeedInt j=0; j<3; j++) {
993ce9b5c20SJames Wright       CeedScalar dx_i[3] = {0}, dU[5];
994ce9b5c20SJames Wright       for (CeedInt k=0; k<5; k++)
995ce9b5c20SJames Wright         dU[k] = Grad_q[0][k][i] * dXdx[0][j] +
996ce9b5c20SJames Wright                 Grad_q[1][k][i] * dXdx[1][j];
997ce9b5c20SJames Wright       dx_i[j] = 1.;
998ce9b5c20SJames Wright       grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i);
999ce9b5c20SJames Wright     }
1000ce9b5c20SJames Wright 
1001ce9b5c20SJames Wright     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
1002ce9b5c20SJames Wright     KMStrainRate(grad_s, strain_rate);
1003ce9b5c20SJames Wright     NewtonianStress(context, strain_rate, kmstress);
1004ce9b5c20SJames Wright     KMUnpack(kmstress, stress);
1005ce9b5c20SJames Wright     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
1006ce9b5c20SJames Wright 
1007ce9b5c20SJames Wright     StateConservative F_inviscid[3];
1008ce9b5c20SJames Wright     FluxInviscid(context, s, F_inviscid);
1009ce9b5c20SJames Wright 
1010ce9b5c20SJames Wright     CeedScalar Flux[5] = {0.};
1011ce9b5c20SJames Wright     for (int j=0; j<3; j++) {
1012ce9b5c20SJames Wright       Flux[0] += F_inviscid[j].density * norm[j];
1013ce9b5c20SJames Wright       for (int k=0; k<3; k++)
1014ce9b5c20SJames Wright         Flux[k+1] += (F_inviscid[j].momentum[k] - stress[k][j]) * norm[j];
1015ce9b5c20SJames Wright       Flux[4] += (F_inviscid[j].E_total + Fe[j])*norm[j];
1016ce9b5c20SJames Wright     }
101730e9fa81SJames Wright 
101830e9fa81SJames Wright     // -- Density
1019ce9b5c20SJames Wright     v[0][i] = -wdetJb * Flux[0];
102030e9fa81SJames Wright 
102130e9fa81SJames Wright     // -- Momentum
102230e9fa81SJames Wright     for (CeedInt j=0; j<3; j++)
1023ce9b5c20SJames Wright       v[j+1][i] = -wdetJb * Flux[j+1];
102430e9fa81SJames Wright 
102530e9fa81SJames Wright     // -- Total Energy Density
1026ce9b5c20SJames Wright     v[4][i] = -wdetJb * Flux[4];
102730e9fa81SJames Wright 
102830e9fa81SJames Wright     // Save values for Jacobian
1029*57e55a1cSJames Wright     if (context->is_primitive) {
1030*57e55a1cSJames Wright       jac_data_sur[0][i] = s.Y.pressure;
1031*57e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.Y.velocity[j];
1032*57e55a1cSJames Wright       jac_data_sur[4][i] = s.Y.temperature;
1033*57e55a1cSJames Wright     } else {
1034ce9b5c20SJames Wright       jac_data_sur[0][i] = s.U.density;
1035*57e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.U.momentum[j];
1036ce9b5c20SJames Wright       jac_data_sur[4][i] = s.U.E_total;
1037*57e55a1cSJames Wright     }
10380ec2498eSJames Wright     for (int j=0; j<6; j++) jac_data_sur[5+j][i] = kmstress[j];
103930e9fa81SJames Wright   } // End Quadrature Point Loop
104030e9fa81SJames Wright   return 0;
104130e9fa81SJames Wright }
104230e9fa81SJames Wright 
104330e9fa81SJames Wright // Jacobian for weak-pressure outflow boundary condition
104430e9fa81SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian)(void *ctx, CeedInt Q,
104530e9fa81SJames Wright     const CeedScalar *const *in,
104630e9fa81SJames Wright     CeedScalar *const *out) {
104730e9fa81SJames Wright   // *INDENT-OFF*
104830e9fa81SJames Wright   // Inputs
104930e9fa81SJames Wright   const CeedScalar (*dq)[CEED_Q_VLA]           = (const CeedScalar(*)[CEED_Q_VLA])in[0],
10500ec2498eSJames Wright                    (*Grad_dq)[5][CEED_Q_VLA]   = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
10510ec2498eSJames Wright                    (*q_data_sur)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[2],
10520ec2498eSJames Wright                    (*x)[CEED_Q_VLA]            = (const CeedScalar(*)[CEED_Q_VLA])in[3],
10530ec2498eSJames Wright                    (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
105430e9fa81SJames Wright   // Outputs
105530e9fa81SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
105630e9fa81SJames Wright   // *INDENT-ON*
105730e9fa81SJames Wright 
105830e9fa81SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
105930e9fa81SJames Wright   const bool implicit     = context->is_implicit;
106030e9fa81SJames Wright 
106130e9fa81SJames Wright   CeedPragmaSIMD
106230e9fa81SJames Wright   // Quadrature Point Loop
106330e9fa81SJames Wright   for (CeedInt i=0; i<Q; i++) {
10640ec2498eSJames Wright     const CeedScalar x_i[3]  = {x[0][i], x[1][i], x[2][i]};
106530e9fa81SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
106630e9fa81SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
106730e9fa81SJames Wright                                 q_data_sur[2][i],
106830e9fa81SJames Wright                                 q_data_sur[3][i]
106930e9fa81SJames Wright                                };
10700ec2498eSJames Wright     const CeedScalar dXdx[2][3] = {
10710ec2498eSJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
10720ec2498eSJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
10730ec2498eSJames Wright     };
10740ec2498eSJames Wright 
1075*57e55a1cSJames Wright     CeedScalar state[5], kmstress[6], dstate[5], dx_i[3] = {0.};
1076*57e55a1cSJames Wright     for (int j=0; j<5; j++) state[j]    = jac_data_sur[j][i];
10770ec2498eSJames Wright     for (int j=0; j<6; j++) kmstress[j] = jac_data_sur[5+j][i];
1078*57e55a1cSJames Wright     for (int j=0; j<5; j++) dstate[j]   = dq[j][i];
1079*57e55a1cSJames Wright 
1080*57e55a1cSJames Wright     State s, ds;
1081*57e55a1cSJames Wright     if (context->is_primitive) {
1082*57e55a1cSJames Wright       s  = StateFromY(context, state, x_i);
1083*57e55a1cSJames Wright       ds = StateFromY_fwd(context, s, dstate, x_i, dx_i);
1084*57e55a1cSJames Wright     } else {
1085*57e55a1cSJames Wright       s  = StateFromU(context, state, x_i);
1086*57e55a1cSJames Wright       ds = StateFromU_fwd(context, s, dstate, x_i, dx_i);
1087*57e55a1cSJames Wright     }
10880ec2498eSJames Wright     s.Y.pressure  = context->P0;
10890ec2498eSJames Wright     ds.Y.pressure = 0.;
10900ec2498eSJames Wright 
10910ec2498eSJames Wright     State grad_ds[3];
10920ec2498eSJames Wright     for (CeedInt j=0; j<3; j++) {
10930ec2498eSJames Wright       CeedScalar dx_i[3] = {0}, dUj[5];
10940ec2498eSJames Wright       for (CeedInt k=0; k<5; k++)
10950ec2498eSJames Wright         dUj[k] = Grad_dq[0][k][i] * dXdx[0][j] +
10960ec2498eSJames Wright                  Grad_dq[1][k][i] * dXdx[1][j];
10970ec2498eSJames Wright       dx_i[j] = 1.;
10980ec2498eSJames Wright       grad_ds[j] = StateFromU_fwd(context, s, dUj, x_i, dx_i);
10990ec2498eSJames Wright     }
11000ec2498eSJames Wright 
11010ec2498eSJames Wright     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
11020ec2498eSJames Wright     KMStrainRate(grad_ds, dstrain_rate);
11030ec2498eSJames Wright     NewtonianStress(context, dstrain_rate, dkmstress);
11040ec2498eSJames Wright     KMUnpack(dkmstress, dstress);
11050ec2498eSJames Wright     KMUnpack(kmstress, stress);
11060ec2498eSJames Wright     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
110730e9fa81SJames Wright 
1108b5d317f8SJames Wright     StateConservative dF_inviscid[3];
1109b5d317f8SJames Wright     FluxInviscid_fwd(context, s, ds, dF_inviscid);
111030e9fa81SJames Wright 
1111b5d317f8SJames Wright     CeedScalar dFlux[5] = {0.};
1112b5d317f8SJames Wright     for (int j=0; j<3; j++) {
1113b5d317f8SJames Wright       dFlux[0] += dF_inviscid[j].density * norm[j];
1114b5d317f8SJames Wright       for (int k=0; k<3; k++)
11150ec2498eSJames Wright         dFlux[k+1] += (dF_inviscid[j].momentum[k] - dstress[k][j]) * norm[j];
11160ec2498eSJames Wright       dFlux[4] += (dF_inviscid[j].E_total + dFe[j]) * norm[j];
1117b5d317f8SJames Wright     }
1118b5d317f8SJames Wright 
1119b5d317f8SJames Wright     for (int j=0; j<5; j++)
1120b5d317f8SJames Wright       v[j][i] = -wdetJb * dFlux[j];
112130e9fa81SJames Wright   } // End Quadrature Point Loop
112230e9fa81SJames Wright   return 0;
112330e9fa81SJames Wright }
112430e9fa81SJames Wright 
112588b783a1SJames Wright // *****************************************************************************
1126dc805cc4SLeila Ghaffari // This QFunction implements the Navier-Stokes equations (mentioned above) in
1127dc805cc4SLeila Ghaffari //   primitive variables and with implicit time stepping method
1128dc805cc4SLeila Ghaffari //
1129dc805cc4SLeila Ghaffari // *****************************************************************************
1130dc805cc4SLeila Ghaffari CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q,
1131dc805cc4SLeila Ghaffari     const CeedScalar *const *in, CeedScalar *const *out) {
1132dc805cc4SLeila Ghaffari   // *INDENT-OFF*
1133dc805cc4SLeila Ghaffari   // Inputs
1134dc805cc4SLeila Ghaffari   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
1135dc805cc4SLeila Ghaffari                    (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
1136dc805cc4SLeila Ghaffari                    (*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
1137dc805cc4SLeila Ghaffari                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
1138dc805cc4SLeila Ghaffari                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
1139dc805cc4SLeila Ghaffari   // Outputs
1140dc805cc4SLeila Ghaffari   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
1141dc805cc4SLeila Ghaffari              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1],
1142dc805cc4SLeila Ghaffari              (*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2];
1143dc805cc4SLeila Ghaffari   // *INDENT-ON*
1144dc805cc4SLeila Ghaffari   // Context
1145dc805cc4SLeila Ghaffari   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
1146dc805cc4SLeila Ghaffari   const CeedScalar mu     = context->mu;
1147dc805cc4SLeila Ghaffari   const CeedScalar cv     = context->cv;
1148dc805cc4SLeila Ghaffari   const CeedScalar cp     = context->cp;
1149dc805cc4SLeila Ghaffari   const CeedScalar *g     = context->g;
1150dc805cc4SLeila Ghaffari   const CeedScalar dt     = context->dt;
1151dc805cc4SLeila Ghaffari   const CeedScalar gamma  = cp / cv;
1152dc805cc4SLeila Ghaffari   const CeedScalar Rd     = cp - cv;
1153dc805cc4SLeila Ghaffari 
1154dc805cc4SLeila Ghaffari   CeedPragmaSIMD
1155dc805cc4SLeila Ghaffari   // Quadrature Point Loop
1156dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
1157dc805cc4SLeila Ghaffari     CeedScalar Y[5];
1158dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++) Y[j] = q[j][i];
1159dc805cc4SLeila Ghaffari     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
1160dc805cc4SLeila Ghaffari     State s = StateFromY(context, Y, x_i);
1161dc805cc4SLeila Ghaffari 
1162dc805cc4SLeila Ghaffari     // -- Interp-to-Interp q_data
1163dc805cc4SLeila Ghaffari     const CeedScalar wdetJ      =   q_data[0][i];
1164dc805cc4SLeila Ghaffari     // -- Interp-to-Grad q_data
1165dc805cc4SLeila Ghaffari     // ---- Inverse of change of coordinate matrix: X_i,j
1166dc805cc4SLeila Ghaffari     // *INDENT-OFF*
1167dc805cc4SLeila Ghaffari     const CeedScalar dXdx[3][3] = {{q_data[1][i],
1168dc805cc4SLeila Ghaffari                                     q_data[2][i],
1169dc805cc4SLeila Ghaffari                                     q_data[3][i]},
1170dc805cc4SLeila Ghaffari                                    {q_data[4][i],
1171dc805cc4SLeila Ghaffari                                     q_data[5][i],
1172dc805cc4SLeila Ghaffari                                     q_data[6][i]},
1173dc805cc4SLeila Ghaffari                                    {q_data[7][i],
1174dc805cc4SLeila Ghaffari                                     q_data[8][i],
1175dc805cc4SLeila Ghaffari                                     q_data[9][i]}
1176dc805cc4SLeila Ghaffari                                   };
1177dc805cc4SLeila Ghaffari     // *INDENT-ON*
1178dc805cc4SLeila Ghaffari     State grad_s[3];
1179dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1180dc805cc4SLeila Ghaffari       CeedScalar dx_i[3] = {0}, dY[5];
1181dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<5; k++)
1182dc805cc4SLeila Ghaffari         dY[k] = Grad_q[0][k][i] * dXdx[0][j] +
1183dc805cc4SLeila Ghaffari                 Grad_q[1][k][i] * dXdx[1][j] +
1184dc805cc4SLeila Ghaffari                 Grad_q[2][k][i] * dXdx[2][j];
1185dc805cc4SLeila Ghaffari       dx_i[j] = 1.;
1186dc805cc4SLeila Ghaffari       grad_s[j] = StateFromY_fwd(context, s, dY, x_i, dx_i);
1187dc805cc4SLeila Ghaffari     }
1188dc805cc4SLeila Ghaffari 
1189dc805cc4SLeila Ghaffari     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
1190dc805cc4SLeila Ghaffari     KMStrainRate(grad_s, strain_rate);
1191dc805cc4SLeila Ghaffari     NewtonianStress(context, strain_rate, kmstress);
1192dc805cc4SLeila Ghaffari     KMUnpack(kmstress, stress);
1193dc805cc4SLeila Ghaffari     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
1194dc805cc4SLeila Ghaffari 
1195dc805cc4SLeila Ghaffari     StateConservative F_inviscid[3];
1196dc805cc4SLeila Ghaffari     FluxInviscid(context, s, F_inviscid);
1197dc805cc4SLeila Ghaffari 
1198dc805cc4SLeila Ghaffari     // Total flux
1199dc805cc4SLeila Ghaffari     CeedScalar Flux[5][3];
1200dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1201dc805cc4SLeila Ghaffari       Flux[0][j] = F_inviscid[j].density;
1202dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<3; k++)
1203dc805cc4SLeila Ghaffari         Flux[k+1][j] = F_inviscid[j].momentum[k] - stress[k][j];
1204dc805cc4SLeila Ghaffari       Flux[4][j] = F_inviscid[j].E_total + Fe[j];
1205dc805cc4SLeila Ghaffari     }
1206dc805cc4SLeila Ghaffari 
1207dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1208dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<5; k++) {
1209dc805cc4SLeila Ghaffari         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * Flux[k][0] +
1210dc805cc4SLeila Ghaffari                                     dXdx[j][1] * Flux[k][1] +
1211dc805cc4SLeila Ghaffari                                     dXdx[j][2] * Flux[k][2]);
1212dc805cc4SLeila Ghaffari       }
1213dc805cc4SLeila Ghaffari     }
1214dc805cc4SLeila Ghaffari 
1215dc805cc4SLeila Ghaffari     const CeedScalar body_force[5] = {0, s.U.density *g[0], s.U.density *g[1], s.U.density *g[2], 0};
1216dc805cc4SLeila Ghaffari 
1217dc805cc4SLeila Ghaffari     CeedScalar Y_dot[5], dx0[3] = {0};
1218dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) Y_dot[j] = q_dot[j][i];
1219dc805cc4SLeila Ghaffari     State s_dot = StateFromY_fwd(context, s, Y_dot, x_i, dx0);
1220dc805cc4SLeila Ghaffari 
1221dc805cc4SLeila Ghaffari     CeedScalar U_dot[5] = {0.};
1222dc805cc4SLeila Ghaffari     U_dot[0] = s_dot.U.density;
1223dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++)
1224dc805cc4SLeila Ghaffari       U_dot[j+1] = s_dot.U.momentum[j];
1225dc805cc4SLeila Ghaffari     U_dot[4] = s_dot.U.E_total;
1226dc805cc4SLeila Ghaffari 
1227dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
1228dc805cc4SLeila Ghaffari       v[j][i] = wdetJ * (U_dot[j] - body_force[j]);
1229dc805cc4SLeila Ghaffari 
1230dc805cc4SLeila Ghaffari     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
1231dc805cc4SLeila Ghaffari     CeedScalar jacob_F_conv[3][5][5] = {0};
1232dc805cc4SLeila Ghaffari     computeFluxJacobian_NS(jacob_F_conv, s.U.density, s.Y.velocity, s.U.E_total,
1233dc805cc4SLeila Ghaffari                            gamma, g, x_i);
1234dc805cc4SLeila Ghaffari     CeedScalar grad_U[5][3];
1235dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1236dc805cc4SLeila Ghaffari       grad_U[0][j] = grad_s[j].U.density;
1237dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<3; k++) grad_U[k+1][j] = grad_s[j].U.momentum[k];
1238dc805cc4SLeila Ghaffari       grad_U[4][j] = grad_s[j].U.E_total;
1239dc805cc4SLeila Ghaffari     }
1240dc805cc4SLeila Ghaffari 
1241dc805cc4SLeila Ghaffari     // strong_conv = dF/dq * dq/dx    (Strong convection)
1242dc805cc4SLeila Ghaffari     CeedScalar strong_conv[5] = {0};
1243dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++)
1244dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<5; k++)
1245dc805cc4SLeila Ghaffari         for (CeedInt l=0; l<5; l++)
1246dc805cc4SLeila Ghaffari           strong_conv[k] += jacob_F_conv[j][k][l] * grad_U[l][j];
1247dc805cc4SLeila Ghaffari 
1248dc805cc4SLeila Ghaffari     // Strong residual
1249dc805cc4SLeila Ghaffari     CeedScalar strong_res[5];
1250dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
1251dc805cc4SLeila Ghaffari       strong_res[j] = U_dot[j] + strong_conv[j] - body_force[j];
1252dc805cc4SLeila Ghaffari 
1253dc805cc4SLeila Ghaffari     // -- Stabilization method: none, SU, or SUPG
1254dc805cc4SLeila Ghaffari     CeedScalar stab[5][3] = {{0.}};
1255dc805cc4SLeila Ghaffari     CeedScalar tau_strong_res[5] = {0.}, tau_strong_res_conservative[5] = {0};
1256dc805cc4SLeila Ghaffari     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
1257dc805cc4SLeila Ghaffari     CeedScalar Tau_d[3] = {0.};
1258dc805cc4SLeila Ghaffari     switch (context->stabilization) {
1259dc805cc4SLeila Ghaffari     case STAB_NONE:        // Galerkin
1260dc805cc4SLeila Ghaffari       break;
1261dc805cc4SLeila Ghaffari     case STAB_SU:        // SU
1262dc805cc4SLeila Ghaffari       Tau_diagPrim(Tau_d, dXdx, s.Y.velocity, cv, context, mu, dt, s.U.density);
1263dc805cc4SLeila Ghaffari       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
1264dc805cc4SLeila Ghaffari       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
1265dc805cc4SLeila Ghaffari       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
1266dc805cc4SLeila Ghaffari       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
1267dc805cc4SLeila Ghaffari       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
1268dc805cc4SLeila Ghaffari       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
1269dc805cc4SLeila Ghaffari                                   tau_strong_conv, tau_strong_conv_conservative);
1270dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<3; j++)
1271dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<5; k++)
1272dc805cc4SLeila Ghaffari           for (CeedInt l=0; l<5; l++)
1273dc805cc4SLeila Ghaffari             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
1274dc805cc4SLeila Ghaffari 
1275dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<5; j++)
1276dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<3; k++)
1277dc805cc4SLeila Ghaffari           Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
1278dc805cc4SLeila Ghaffari                                     stab[j][1] * dXdx[k][1] +
1279dc805cc4SLeila Ghaffari                                     stab[j][2] * dXdx[k][2]);
1280dc805cc4SLeila Ghaffari 
1281dc805cc4SLeila Ghaffari       break;
1282dc805cc4SLeila Ghaffari     case STAB_SUPG:        // SUPG
1283dc805cc4SLeila Ghaffari       Tau_diagPrim(Tau_d, dXdx, s.Y.velocity, cv, context, mu, dt, s.U.density);
1284dc805cc4SLeila Ghaffari       tau_strong_res[0] = Tau_d[0] * strong_res[0];
1285dc805cc4SLeila Ghaffari       tau_strong_res[1] = Tau_d[1] * strong_res[1];
1286dc805cc4SLeila Ghaffari       tau_strong_res[2] = Tau_d[1] * strong_res[2];
1287dc805cc4SLeila Ghaffari       tau_strong_res[3] = Tau_d[1] * strong_res[3];
1288dc805cc4SLeila Ghaffari       tau_strong_res[4] = Tau_d[2] * strong_res[4];
1289dc805cc4SLeila Ghaffari 
1290dc805cc4SLeila Ghaffari       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
1291dc805cc4SLeila Ghaffari                                   tau_strong_res, tau_strong_res_conservative);
1292dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<3; j++)
1293dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<5; k++)
1294dc805cc4SLeila Ghaffari           for (CeedInt l=0; l<5; l++)
1295dc805cc4SLeila Ghaffari             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_res_conservative[l];
1296dc805cc4SLeila Ghaffari 
1297dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<5; j++)
1298dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<3; k++)
1299dc805cc4SLeila Ghaffari           Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
1300dc805cc4SLeila Ghaffari                                     stab[j][1] * dXdx[k][1] +
1301dc805cc4SLeila Ghaffari                                     stab[j][2] * dXdx[k][2]);
1302dc805cc4SLeila Ghaffari       break;
1303dc805cc4SLeila Ghaffari     }
1304dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++) jac_data[j][i] = Y[j];
1305dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<6; j++) jac_data[5+j][i] = kmstress[j];
1306dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) jac_data[5+6+j][i] = Tau_d[j];
1307dc805cc4SLeila Ghaffari 
1308dc805cc4SLeila Ghaffari   } // End Quadrature Point Loop
1309dc805cc4SLeila Ghaffari 
1310dc805cc4SLeila Ghaffari   // Return
1311dc805cc4SLeila Ghaffari   return 0;
1312dc805cc4SLeila Ghaffari }
1313dc805cc4SLeila Ghaffari 
1314dc805cc4SLeila Ghaffari // *****************************************************************************
1315dc805cc4SLeila Ghaffari // This QFunction implements the jacobean of the Navier-Stokes equations
1316dc805cc4SLeila Ghaffari //   in primitive variables for implicit time stepping method.
1317dc805cc4SLeila Ghaffari //
1318dc805cc4SLeila Ghaffari // *****************************************************************************
1319dc805cc4SLeila Ghaffari CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q,
1320dc805cc4SLeila Ghaffari     const CeedScalar *const *in, CeedScalar *const *out) {
1321dc805cc4SLeila Ghaffari   // *INDENT-OFF*
1322dc805cc4SLeila Ghaffari   // Inputs
1323dc805cc4SLeila Ghaffari   const CeedScalar (*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
1324dc805cc4SLeila Ghaffari                    (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
1325dc805cc4SLeila Ghaffari                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
1326dc805cc4SLeila Ghaffari                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
1327dc805cc4SLeila Ghaffari                    (*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
1328dc805cc4SLeila Ghaffari   // Outputs
1329dc805cc4SLeila Ghaffari   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
1330dc805cc4SLeila Ghaffari              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
1331dc805cc4SLeila Ghaffari   // *INDENT-ON*
1332dc805cc4SLeila Ghaffari   // Context
1333dc805cc4SLeila Ghaffari   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
1334dc805cc4SLeila Ghaffari   const CeedScalar *g = context->g;
1335dc805cc4SLeila Ghaffari   const CeedScalar cp = context->cp;
1336dc805cc4SLeila Ghaffari   const CeedScalar cv = context->cv;
1337dc805cc4SLeila Ghaffari   const CeedScalar Rd = cp - cv;
1338dc805cc4SLeila Ghaffari   const CeedScalar gamma = cp / cv;
1339dc805cc4SLeila Ghaffari 
1340dc805cc4SLeila Ghaffari   CeedPragmaSIMD
1341dc805cc4SLeila Ghaffari   // Quadrature Point Loop
1342dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
1343dc805cc4SLeila Ghaffari     // -- Interp-to-Interp q_data
1344dc805cc4SLeila Ghaffari     const CeedScalar wdetJ      =   q_data[0][i];
1345dc805cc4SLeila Ghaffari     // -- Interp-to-Grad q_data
1346dc805cc4SLeila Ghaffari     // ---- Inverse of change of coordinate matrix: X_i,j
1347dc805cc4SLeila Ghaffari     // *INDENT-OFF*
1348dc805cc4SLeila Ghaffari     const CeedScalar dXdx[3][3] = {{q_data[1][i],
1349dc805cc4SLeila Ghaffari                                     q_data[2][i],
1350dc805cc4SLeila Ghaffari                                     q_data[3][i]},
1351dc805cc4SLeila Ghaffari                                    {q_data[4][i],
1352dc805cc4SLeila Ghaffari                                     q_data[5][i],
1353dc805cc4SLeila Ghaffari                                     q_data[6][i]},
1354dc805cc4SLeila Ghaffari                                    {q_data[7][i],
1355dc805cc4SLeila Ghaffari                                     q_data[8][i],
1356dc805cc4SLeila Ghaffari                                     q_data[9][i]}
1357dc805cc4SLeila Ghaffari                                   };
1358dc805cc4SLeila Ghaffari     // *INDENT-ON*
1359dc805cc4SLeila Ghaffari 
1360dc805cc4SLeila Ghaffari     CeedScalar Y[5], kmstress[6], Tau_d[3] __attribute((unused));
1361dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) Y[j] = jac_data[j][i];
1362dc805cc4SLeila Ghaffari     for (int j=0; j<6; j++) kmstress[j] = jac_data[5+j][i];
1363dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) Tau_d[j] = jac_data[5+6+j][i];
1364dc805cc4SLeila Ghaffari     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
1365dc805cc4SLeila Ghaffari     State s = StateFromY(context, Y, x_i);
1366dc805cc4SLeila Ghaffari 
1367dc805cc4SLeila Ghaffari     CeedScalar dY[5], dx0[3] = {0};
1368dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) dY[j] = dq[j][i];
1369dc805cc4SLeila Ghaffari     State ds = StateFromY_fwd(context, s, dY, x_i, dx0);
1370dc805cc4SLeila Ghaffari 
1371dc805cc4SLeila Ghaffari     State grad_ds[3];
1372dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) {
1373dc805cc4SLeila Ghaffari       CeedScalar dYj[5];
1374dc805cc4SLeila Ghaffari       for (int k=0; k<5; k++)
1375dc805cc4SLeila Ghaffari         dYj[k] = Grad_dq[0][k][i] * dXdx[0][j] +
1376dc805cc4SLeila Ghaffari                  Grad_dq[1][k][i] * dXdx[1][j] +
1377dc805cc4SLeila Ghaffari                  Grad_dq[2][k][i] * dXdx[2][j];
1378dc805cc4SLeila Ghaffari       grad_ds[j] = StateFromY_fwd(context, s, dYj, x_i, dx0);
1379dc805cc4SLeila Ghaffari     }
1380dc805cc4SLeila Ghaffari 
1381dc805cc4SLeila Ghaffari     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
1382dc805cc4SLeila Ghaffari     KMStrainRate(grad_ds, dstrain_rate);
1383dc805cc4SLeila Ghaffari     NewtonianStress(context, dstrain_rate, dkmstress);
1384dc805cc4SLeila Ghaffari     KMUnpack(dkmstress, dstress);
1385dc805cc4SLeila Ghaffari     KMUnpack(kmstress, stress);
1386dc805cc4SLeila Ghaffari     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
1387dc805cc4SLeila Ghaffari 
1388dc805cc4SLeila Ghaffari     StateConservative dF_inviscid[3];
1389dc805cc4SLeila Ghaffari     FluxInviscid_fwd(context, s, ds, dF_inviscid);
1390dc805cc4SLeila Ghaffari 
1391dc805cc4SLeila Ghaffari     // Total flux
1392dc805cc4SLeila Ghaffari     CeedScalar dFlux[5][3];
1393dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) {
1394dc805cc4SLeila Ghaffari       dFlux[0][j] = dF_inviscid[j].density;
1395dc805cc4SLeila Ghaffari       for (int k=0; k<3; k++)
1396dc805cc4SLeila Ghaffari         dFlux[k+1][j] = dF_inviscid[j].momentum[k] - dstress[k][j];
1397dc805cc4SLeila Ghaffari       dFlux[4][j] = dF_inviscid[j].E_total + dFe[j];
1398dc805cc4SLeila Ghaffari     }
1399dc805cc4SLeila Ghaffari 
1400dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) {
1401dc805cc4SLeila Ghaffari       for (int k=0; k<5; k++) {
1402dc805cc4SLeila Ghaffari         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * dFlux[k][0] +
1403dc805cc4SLeila Ghaffari                                     dXdx[j][1] * dFlux[k][1] +
1404dc805cc4SLeila Ghaffari                                     dXdx[j][2] * dFlux[k][2]);
1405dc805cc4SLeila Ghaffari       }
1406dc805cc4SLeila Ghaffari     }
1407dc805cc4SLeila Ghaffari 
1408dc805cc4SLeila Ghaffari     const CeedScalar dbody_force[5] = {0,
1409dc805cc4SLeila Ghaffari                                        ds.U.density *g[0],
1410dc805cc4SLeila Ghaffari                                        ds.U.density *g[1],
1411dc805cc4SLeila Ghaffari                                        ds.U.density *g[2],
1412dc805cc4SLeila Ghaffari                                        0
1413dc805cc4SLeila Ghaffari                                       };
1414dc805cc4SLeila Ghaffari     CeedScalar dU[5] = {0.};
1415dc805cc4SLeila Ghaffari     dU[0] = ds.U.density;
1416dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++)
1417dc805cc4SLeila Ghaffari       dU[j+1] = ds.U.momentum[j];
1418dc805cc4SLeila Ghaffari     dU[4] = ds.U.E_total;
1419dc805cc4SLeila Ghaffari 
1420dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++)
1421dc805cc4SLeila Ghaffari       v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]);
1422dc805cc4SLeila Ghaffari 
1423dc805cc4SLeila Ghaffari     if (1) {
1424dc805cc4SLeila Ghaffari       CeedScalar jacob_F_conv[3][5][5] = {0};
1425dc805cc4SLeila Ghaffari       computeFluxJacobian_NS(jacob_F_conv, s.U.density, s.Y.velocity, s.U.E_total,
1426dc805cc4SLeila Ghaffari                              gamma, g, x_i);
1427dc805cc4SLeila Ghaffari       CeedScalar grad_dU[5][3];
1428dc805cc4SLeila Ghaffari       for (int j=0; j<3; j++) {
1429dc805cc4SLeila Ghaffari         grad_dU[0][j] = grad_ds[j].U.density;
1430dc805cc4SLeila Ghaffari         for (int k=0; k<3; k++) grad_dU[k+1][j] = grad_ds[j].U.momentum[k];
1431dc805cc4SLeila Ghaffari         grad_dU[4][j] = grad_ds[j].U.E_total;
1432dc805cc4SLeila Ghaffari       }
1433dc805cc4SLeila Ghaffari       CeedScalar dstrong_conv[5] = {0.};
1434dc805cc4SLeila Ghaffari       for (int j=0; j<3; j++)
1435dc805cc4SLeila Ghaffari         for (int k=0; k<5; k++)
1436dc805cc4SLeila Ghaffari           for (int l=0; l<5; l++)
1437dc805cc4SLeila Ghaffari             dstrong_conv[k] += jacob_F_conv[j][k][l] * grad_dU[l][j];
1438dc805cc4SLeila Ghaffari 
1439dc805cc4SLeila Ghaffari       CeedScalar dstrong_res[5];
1440dc805cc4SLeila Ghaffari       for (int j=0; j<5; j++)
1441dc805cc4SLeila Ghaffari         dstrong_res[j] = context->ijacobian_time_shift * dU[j] +
1442dc805cc4SLeila Ghaffari                          dstrong_conv[j] -
1443dc805cc4SLeila Ghaffari                          dbody_force[j];
1444dc805cc4SLeila Ghaffari 
1445dc805cc4SLeila Ghaffari       CeedScalar dtau_strong_res[5] = {0.},
1446dc805cc4SLeila Ghaffari                                       dtau_strong_res_conservative[5] = {0.};
1447dc805cc4SLeila Ghaffari       dtau_strong_res[0] = Tau_d[0] * dstrong_res[0];
1448dc805cc4SLeila Ghaffari       dtau_strong_res[1] = Tau_d[1] * dstrong_res[1];
1449dc805cc4SLeila Ghaffari       dtau_strong_res[2] = Tau_d[1] * dstrong_res[2];
1450dc805cc4SLeila Ghaffari       dtau_strong_res[3] = Tau_d[1] * dstrong_res[3];
1451dc805cc4SLeila Ghaffari       dtau_strong_res[4] = Tau_d[2] * dstrong_res[4];
1452dc805cc4SLeila Ghaffari       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
1453dc805cc4SLeila Ghaffari                                   dtau_strong_res, dtau_strong_res_conservative);
1454dc805cc4SLeila Ghaffari       CeedScalar dstab[5][3] = {0};
1455dc805cc4SLeila Ghaffari       for (int j=0; j<3; j++)
1456dc805cc4SLeila Ghaffari         for (int k=0; k<5; k++)
1457dc805cc4SLeila Ghaffari           for (int l=0; l<5; l++)
1458dc805cc4SLeila Ghaffari             dstab[k][j] += jacob_F_conv[j][k][l] * dtau_strong_res_conservative[l];
1459dc805cc4SLeila Ghaffari 
1460dc805cc4SLeila Ghaffari       for (int j=0; j<5; j++)
1461dc805cc4SLeila Ghaffari         for (int k=0; k<3; k++)
1462dc805cc4SLeila Ghaffari           Grad_v[k][j][i] += wdetJ*(dstab[j][0] * dXdx[k][0] +
1463dc805cc4SLeila Ghaffari                                     dstab[j][1] * dXdx[k][1] +
1464dc805cc4SLeila Ghaffari                                     dstab[j][2] * dXdx[k][2]);
1465dc805cc4SLeila Ghaffari 
1466dc805cc4SLeila Ghaffari     }
1467dc805cc4SLeila Ghaffari   } // End Quadrature Point Loop
1468dc805cc4SLeila Ghaffari   return 0;
1469dc805cc4SLeila Ghaffari }
1470dc805cc4SLeila Ghaffari // *****************************************************************************
1471dc805cc4SLeila Ghaffari 
147288b783a1SJames Wright #endif // newtonian_h
1473