xref: /libCEED/examples/fluids/qfunctions/newtonian.h (revision efe9d856d652f85e9e9f33171e1b615db5aa2505)
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;
793*efe9d856SJames Wright   State (*StateFromQi)(NewtonianIdealGasContext gas,
794*efe9d856SJames Wright                        const CeedScalar qi[5], const CeedScalar x[3]);
795*efe9d856SJames Wright   State (*StateFromQi_fwd)(NewtonianIdealGasContext gas,
796*efe9d856SJames Wright                            State s, const CeedScalar dqi[5],
797*efe9d856SJames Wright                            const CeedScalar x[3], const CeedScalar dx[3]);
798*efe9d856SJames Wright   StateFromQi     = context->is_primitive ? &StateFromY     : &StateFromU;
799*efe9d856SJames Wright   StateFromQi_fwd = context->is_primitive ? &StateFromY_fwd : &StateFromU_fwd;
800*efe9d856SJames Wright 
80165dd5cafSJames Wright 
80265dd5cafSJames Wright   CeedPragmaSIMD
80365dd5cafSJames Wright   for(CeedInt i=0; i<Q; i++) {
8042c4e60d7SJames Wright     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
805*efe9d856SJames Wright     const CeedScalar qi[5]  = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
806*efe9d856SJames Wright     State s = StateFromQi(context, qi, x_i);
80765dd5cafSJames Wright 
80865dd5cafSJames Wright     const CeedScalar wdetJb  = (is_implicit ? -1. : 1.) * q_data_sur[0][i];
80965dd5cafSJames Wright     // ---- Normal vect
81065dd5cafSJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
81165dd5cafSJames Wright                                 q_data_sur[2][i],
81265dd5cafSJames Wright                                 q_data_sur[3][i]
81365dd5cafSJames Wright                                };
81465dd5cafSJames Wright 
8152c4e60d7SJames Wright     const CeedScalar dXdx[2][3] = {
8162c4e60d7SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
8172c4e60d7SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
8182c4e60d7SJames Wright     };
81965dd5cafSJames Wright 
8202c4e60d7SJames Wright     State grad_s[3];
8212c4e60d7SJames Wright     for (CeedInt j=0; j<3; j++) {
822*efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi[5];
8232c4e60d7SJames Wright       for (CeedInt k=0; k<5; k++)
824*efe9d856SJames Wright         dqi[k] = Grad_q[0][k][i] * dXdx[0][j] +
8252c4e60d7SJames Wright                  Grad_q[1][k][i] * dXdx[1][j];
8262c4e60d7SJames Wright       dx_i[j] = 1.;
827*efe9d856SJames Wright       grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
8282c4e60d7SJames Wright     }
82965dd5cafSJames Wright 
8302c4e60d7SJames Wright     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
8312c4e60d7SJames Wright     KMStrainRate(grad_s, strain_rate);
8322c4e60d7SJames Wright     NewtonianStress(context, strain_rate, kmstress);
8332c4e60d7SJames Wright     KMUnpack(kmstress, stress);
8342c4e60d7SJames Wright     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
8352c4e60d7SJames Wright 
8362c4e60d7SJames Wright     StateConservative F_inviscid[3];
8372c4e60d7SJames Wright     FluxInviscid(context, s, F_inviscid);
8382c4e60d7SJames Wright 
8392c4e60d7SJames Wright     CeedScalar Flux[5] = {0.};
8402c4e60d7SJames Wright     for (int j=0; j<3; j++) {
8412c4e60d7SJames Wright       Flux[0] += F_inviscid[j].density * norm[j];
8422c4e60d7SJames Wright       for (int k=0; k<3; k++)
8432c4e60d7SJames Wright         Flux[k+1] += (F_inviscid[j].momentum[k] - stress[k][j]) * norm[j];
8442c4e60d7SJames Wright       Flux[4] += (F_inviscid[j].E_total + Fe[j])*norm[j];
8452c4e60d7SJames Wright     }
8462c4e60d7SJames Wright 
84765dd5cafSJames Wright     // -- Density
8482c4e60d7SJames Wright     v[0][i] = -wdetJb * Flux[0];
84965dd5cafSJames Wright 
85065dd5cafSJames Wright     // -- Momentum
85165dd5cafSJames Wright     for (CeedInt j=0; j<3; j++)
8522c4e60d7SJames Wright       v[j+1][i] = -wdetJb * Flux[j+1];
85365dd5cafSJames Wright 
85465dd5cafSJames Wright     // -- Total Energy Density
8552c4e60d7SJames Wright     v[4][i] = -wdetJb * Flux[4];
856b55ac660SJames Wright 
85757e55a1cSJames Wright     if (context->is_primitive) {
85857e55a1cSJames Wright       jac_data_sur[0][i] = s.Y.pressure;
85957e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.Y.velocity[j];
86057e55a1cSJames Wright       jac_data_sur[4][i] = s.Y.temperature;
86157e55a1cSJames Wright     } else {
862b55ac660SJames Wright       jac_data_sur[0][i] = s.U.density;
86357e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.U.momentum[j];
864b55ac660SJames Wright       jac_data_sur[4][i] = s.U.E_total;
86557e55a1cSJames Wright     }
866b55ac660SJames Wright     for (int j=0; j<6; j++) jac_data_sur[5+j][i] = kmstress[j];
86765dd5cafSJames Wright   }
86865dd5cafSJames Wright   return 0;
86965dd5cafSJames Wright }
87065dd5cafSJames Wright 
871b55ac660SJames Wright // Jacobian for "set nothing" boundary integral
872b55ac660SJames Wright CEED_QFUNCTION(BoundaryIntegral_Jacobian)(void *ctx, CeedInt Q,
873b55ac660SJames Wright     const CeedScalar *const *in,
874b55ac660SJames Wright     CeedScalar *const *out) {
875b55ac660SJames Wright   // *INDENT-OFF*
876b55ac660SJames Wright   // Inputs
877b55ac660SJames Wright   const CeedScalar (*dq)[CEED_Q_VLA]           = (const CeedScalar(*)[CEED_Q_VLA])in[0],
878b55ac660SJames Wright                    (*Grad_dq)[5][CEED_Q_VLA]   = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
879b55ac660SJames Wright                    (*q_data_sur)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[2],
880b55ac660SJames Wright                    (*x)[CEED_Q_VLA]            = (const CeedScalar(*)[CEED_Q_VLA])in[3],
881b55ac660SJames Wright                    (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
882b55ac660SJames Wright   // Outputs
883b55ac660SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
884b55ac660SJames Wright   // *INDENT-ON*
885b55ac660SJames Wright 
886b55ac660SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
887b55ac660SJames Wright   const bool implicit     = context->is_implicit;
888*efe9d856SJames Wright   State (*StateFromQi)(NewtonianIdealGasContext gas,
889*efe9d856SJames Wright                        const CeedScalar qi[5], const CeedScalar x[3]);
890*efe9d856SJames Wright   State (*StateFromQi_fwd)(NewtonianIdealGasContext gas,
891*efe9d856SJames Wright                            State s, const CeedScalar dqi[5],
892*efe9d856SJames Wright                            const CeedScalar x[3], const CeedScalar dx[3]);
893*efe9d856SJames Wright   StateFromQi     = context->is_primitive ? &StateFromY     : &StateFromU;
894*efe9d856SJames Wright   StateFromQi_fwd = context->is_primitive ? &StateFromY_fwd : &StateFromU_fwd;
895b55ac660SJames Wright 
896b55ac660SJames Wright   CeedPragmaSIMD
897b55ac660SJames Wright   // Quadrature Point Loop
898b55ac660SJames Wright   for (CeedInt i=0; i<Q; i++) {
899b55ac660SJames Wright     const CeedScalar x_i[3]  = {x[0][i], x[1][i], x[2][i]};
900b55ac660SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
901b55ac660SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
902b55ac660SJames Wright                                 q_data_sur[2][i],
903b55ac660SJames Wright                                 q_data_sur[3][i]
904b55ac660SJames Wright                                };
905b55ac660SJames Wright     const CeedScalar dXdx[2][3] = {
906b55ac660SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
907b55ac660SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
908b55ac660SJames Wright     };
909b55ac660SJames Wright 
910*efe9d856SJames Wright     CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.};
911*efe9d856SJames Wright     for (int j=0; j<5; j++) qi[j]    = jac_data_sur[j][i];
912b55ac660SJames Wright     for (int j=0; j<6; j++) kmstress[j] = jac_data_sur[5+j][i];
913*efe9d856SJames Wright     for (int j=0; j<5; j++) dqi[j]   = dq[j][i];
91457e55a1cSJames Wright 
915*efe9d856SJames Wright     State s  = StateFromQi(context, qi, x_i);
916*efe9d856SJames Wright     State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
917b55ac660SJames Wright 
918b55ac660SJames Wright     State grad_ds[3];
919b55ac660SJames Wright     for (CeedInt j=0; j<3; j++) {
920*efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi_j[5];
921b55ac660SJames Wright       for (CeedInt k=0; k<5; k++)
922*efe9d856SJames Wright         dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] +
923b55ac660SJames Wright                    Grad_dq[1][k][i] * dXdx[1][j];
924b55ac660SJames Wright       dx_i[j] = 1.;
925*efe9d856SJames Wright       grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i);
926b55ac660SJames Wright     }
927b55ac660SJames Wright 
928b55ac660SJames Wright     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
929b55ac660SJames Wright     KMStrainRate(grad_ds, dstrain_rate);
930b55ac660SJames Wright     NewtonianStress(context, dstrain_rate, dkmstress);
931b55ac660SJames Wright     KMUnpack(dkmstress, dstress);
932b55ac660SJames Wright     KMUnpack(kmstress, stress);
933b55ac660SJames Wright     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
934b55ac660SJames Wright 
935b55ac660SJames Wright     StateConservative dF_inviscid[3];
936b55ac660SJames Wright     FluxInviscid_fwd(context, s, ds, dF_inviscid);
937b55ac660SJames Wright 
938b55ac660SJames Wright     CeedScalar dFlux[5] = {0.};
939b55ac660SJames Wright     for (int j=0; j<3; j++) {
940b55ac660SJames Wright       dFlux[0] += dF_inviscid[j].density * norm[j];
941b55ac660SJames Wright       for (int k=0; k<3; k++)
942b55ac660SJames Wright         dFlux[k+1] += (dF_inviscid[j].momentum[k] - dstress[k][j]) * norm[j];
943b55ac660SJames Wright       dFlux[4] += (dF_inviscid[j].E_total + dFe[j]) * norm[j];
944b55ac660SJames Wright     }
945b55ac660SJames Wright 
946b55ac660SJames Wright     for (int j=0; j<5; j++)
947b55ac660SJames Wright       v[j][i] = -wdetJb * dFlux[j];
948b55ac660SJames Wright   } // End Quadrature Point Loop
949b55ac660SJames Wright   return 0;
950b55ac660SJames Wright }
951b55ac660SJames Wright 
95230e9fa81SJames Wright // Outflow boundary condition, weakly setting a constant pressure
95330e9fa81SJames Wright CEED_QFUNCTION(PressureOutflow)(void *ctx, CeedInt Q,
95430e9fa81SJames Wright                                 const CeedScalar *const *in,
95530e9fa81SJames Wright                                 CeedScalar *const *out) {
95630e9fa81SJames Wright   // *INDENT-OFF*
95730e9fa81SJames Wright   // Inputs
95830e9fa81SJames Wright   const CeedScalar (*q)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[0],
959ce9b5c20SJames Wright                    (*Grad_q)[5][CEED_Q_VLA]  = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
960ce9b5c20SJames Wright                    (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
961ce9b5c20SJames Wright                    (*x)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[3];
96230e9fa81SJames Wright   // Outputs
96330e9fa81SJames Wright   CeedScalar (*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA])out[0],
96430e9fa81SJames Wright              (*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1];
96530e9fa81SJames Wright   // *INDENT-ON*
96630e9fa81SJames Wright 
96730e9fa81SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
96830e9fa81SJames Wright   const bool       implicit = context->is_implicit;
96930e9fa81SJames Wright   const CeedScalar P0       = context->P0;
97030e9fa81SJames Wright 
971*efe9d856SJames Wright   State (*StateFromQi)(NewtonianIdealGasContext gas,
972*efe9d856SJames Wright                        const CeedScalar qi[5], const CeedScalar x[3]);
973*efe9d856SJames Wright   State (*StateFromQi_fwd)(NewtonianIdealGasContext gas,
974*efe9d856SJames Wright                            State s, const CeedScalar dqi[5],
975*efe9d856SJames Wright                            const CeedScalar x[3], const CeedScalar dx[3]);
976*efe9d856SJames Wright   StateFromQi     = context->is_primitive ? &StateFromY     : &StateFromU;
977*efe9d856SJames Wright   StateFromQi_fwd = context->is_primitive ? &StateFromY_fwd : &StateFromU_fwd;
978*efe9d856SJames Wright 
97930e9fa81SJames Wright   CeedPragmaSIMD
98030e9fa81SJames Wright   // Quadrature Point Loop
98130e9fa81SJames Wright   for (CeedInt i=0; i<Q; i++) {
98230e9fa81SJames Wright     // Setup
98330e9fa81SJames Wright     // -- Interp in
984ce9b5c20SJames Wright     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
985*efe9d856SJames Wright     const CeedScalar qi[5]  = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
986*efe9d856SJames Wright     State s = StateFromQi(context, qi, x_i);
987ce9b5c20SJames Wright     s.Y.pressure = P0;
98830e9fa81SJames Wright 
98930e9fa81SJames Wright     // -- Interp-to-Interp q_data
99030e9fa81SJames Wright     // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q).
99130e9fa81SJames Wright     // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q).
99230e9fa81SJames Wright     // We can effect this by swapping the sign on this weight
99330e9fa81SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
99430e9fa81SJames Wright 
99530e9fa81SJames Wright     // ---- Normal vect
99630e9fa81SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
99730e9fa81SJames Wright                                 q_data_sur[2][i],
99830e9fa81SJames Wright                                 q_data_sur[3][i]
99930e9fa81SJames Wright                                };
100030e9fa81SJames Wright 
1001ce9b5c20SJames Wright     const CeedScalar dXdx[2][3] = {
1002ce9b5c20SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
1003ce9b5c20SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
1004ce9b5c20SJames Wright     };
100530e9fa81SJames Wright 
1006ce9b5c20SJames Wright     State grad_s[3];
1007ce9b5c20SJames Wright     for (CeedInt j=0; j<3; j++) {
1008*efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi[5];
1009ce9b5c20SJames Wright       for (CeedInt k=0; k<5; k++)
1010*efe9d856SJames Wright         dqi[k] = Grad_q[0][k][i] * dXdx[0][j] +
1011ce9b5c20SJames Wright                  Grad_q[1][k][i] * dXdx[1][j];
1012ce9b5c20SJames Wright       dx_i[j] = 1.;
1013*efe9d856SJames Wright       grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
1014ce9b5c20SJames Wright     }
1015ce9b5c20SJames Wright 
1016ce9b5c20SJames Wright     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
1017ce9b5c20SJames Wright     KMStrainRate(grad_s, strain_rate);
1018ce9b5c20SJames Wright     NewtonianStress(context, strain_rate, kmstress);
1019ce9b5c20SJames Wright     KMUnpack(kmstress, stress);
1020ce9b5c20SJames Wright     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
1021ce9b5c20SJames Wright 
1022ce9b5c20SJames Wright     StateConservative F_inviscid[3];
1023ce9b5c20SJames Wright     FluxInviscid(context, s, F_inviscid);
1024ce9b5c20SJames Wright 
1025ce9b5c20SJames Wright     CeedScalar Flux[5] = {0.};
1026ce9b5c20SJames Wright     for (int j=0; j<3; j++) {
1027ce9b5c20SJames Wright       Flux[0] += F_inviscid[j].density * norm[j];
1028ce9b5c20SJames Wright       for (int k=0; k<3; k++)
1029ce9b5c20SJames Wright         Flux[k+1] += (F_inviscid[j].momentum[k] - stress[k][j]) * norm[j];
1030ce9b5c20SJames Wright       Flux[4] += (F_inviscid[j].E_total + Fe[j])*norm[j];
1031ce9b5c20SJames Wright     }
103230e9fa81SJames Wright 
103330e9fa81SJames Wright     // -- Density
1034ce9b5c20SJames Wright     v[0][i] = -wdetJb * Flux[0];
103530e9fa81SJames Wright 
103630e9fa81SJames Wright     // -- Momentum
103730e9fa81SJames Wright     for (CeedInt j=0; j<3; j++)
1038ce9b5c20SJames Wright       v[j+1][i] = -wdetJb * Flux[j+1];
103930e9fa81SJames Wright 
104030e9fa81SJames Wright     // -- Total Energy Density
1041ce9b5c20SJames Wright     v[4][i] = -wdetJb * Flux[4];
104230e9fa81SJames Wright 
104330e9fa81SJames Wright     // Save values for Jacobian
104457e55a1cSJames Wright     if (context->is_primitive) {
104557e55a1cSJames Wright       jac_data_sur[0][i] = s.Y.pressure;
104657e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.Y.velocity[j];
104757e55a1cSJames Wright       jac_data_sur[4][i] = s.Y.temperature;
104857e55a1cSJames Wright     } else {
1049ce9b5c20SJames Wright       jac_data_sur[0][i] = s.U.density;
105057e55a1cSJames Wright       for (int j=0; j<3; j++) jac_data_sur[j+1][i] = s.U.momentum[j];
1051ce9b5c20SJames Wright       jac_data_sur[4][i] = s.U.E_total;
105257e55a1cSJames Wright     }
10530ec2498eSJames Wright     for (int j=0; j<6; j++) jac_data_sur[5+j][i] = kmstress[j];
105430e9fa81SJames Wright   } // End Quadrature Point Loop
105530e9fa81SJames Wright   return 0;
105630e9fa81SJames Wright }
105730e9fa81SJames Wright 
105830e9fa81SJames Wright // Jacobian for weak-pressure outflow boundary condition
105930e9fa81SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian)(void *ctx, CeedInt Q,
1060*efe9d856SJames Wright     const CeedScalar *const *in, CeedScalar *const *out) {
106130e9fa81SJames Wright   // *INDENT-OFF*
106230e9fa81SJames Wright   // Inputs
106330e9fa81SJames Wright   const CeedScalar (*dq)[CEED_Q_VLA]           = (const CeedScalar(*)[CEED_Q_VLA])in[0],
10640ec2498eSJames Wright                    (*Grad_dq)[5][CEED_Q_VLA]   = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
10650ec2498eSJames Wright                    (*q_data_sur)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[2],
10660ec2498eSJames Wright                    (*x)[CEED_Q_VLA]            = (const CeedScalar(*)[CEED_Q_VLA])in[3],
10670ec2498eSJames Wright                    (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
106830e9fa81SJames Wright   // Outputs
106930e9fa81SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
107030e9fa81SJames Wright   // *INDENT-ON*
107130e9fa81SJames Wright 
107230e9fa81SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
107330e9fa81SJames Wright   const bool implicit     = context->is_implicit;
107430e9fa81SJames Wright 
1075*efe9d856SJames Wright   State (*StateFromQi)(NewtonianIdealGasContext gas,
1076*efe9d856SJames Wright                        const CeedScalar qi[5], const CeedScalar x[3]);
1077*efe9d856SJames Wright   State (*StateFromQi_fwd)(NewtonianIdealGasContext gas,
1078*efe9d856SJames Wright                            State s, const CeedScalar dQi[5],
1079*efe9d856SJames Wright                            const CeedScalar x[3], const CeedScalar dx[3]);
1080*efe9d856SJames Wright   StateFromQi     = context->is_primitive ? &StateFromY     : &StateFromU;
1081*efe9d856SJames Wright   StateFromQi_fwd = context->is_primitive ? &StateFromY_fwd : &StateFromU_fwd;
1082*efe9d856SJames Wright 
108330e9fa81SJames Wright   CeedPragmaSIMD
108430e9fa81SJames Wright   // Quadrature Point Loop
108530e9fa81SJames Wright   for (CeedInt i=0; i<Q; i++) {
10860ec2498eSJames Wright     const CeedScalar x_i[3]  = {x[0][i], x[1][i], x[2][i]};
108730e9fa81SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
108830e9fa81SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
108930e9fa81SJames Wright                                 q_data_sur[2][i],
109030e9fa81SJames Wright                                 q_data_sur[3][i]
109130e9fa81SJames Wright                                };
10920ec2498eSJames Wright     const CeedScalar dXdx[2][3] = {
10930ec2498eSJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
10940ec2498eSJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
10950ec2498eSJames Wright     };
10960ec2498eSJames Wright 
1097*efe9d856SJames Wright     CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.};
1098*efe9d856SJames Wright     for (int j=0; j<5; j++) qi[j]    = jac_data_sur[j][i];
10990ec2498eSJames Wright     for (int j=0; j<6; j++) kmstress[j] = jac_data_sur[5+j][i];
1100*efe9d856SJames Wright     for (int j=0; j<5; j++) dqi[j]   = dq[j][i];
110157e55a1cSJames Wright 
1102*efe9d856SJames Wright     State s  = StateFromQi(context, qi, x_i);
1103*efe9d856SJames Wright     State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
11040ec2498eSJames Wright     s.Y.pressure  = context->P0;
11050ec2498eSJames Wright     ds.Y.pressure = 0.;
11060ec2498eSJames Wright 
11070ec2498eSJames Wright     State grad_ds[3];
11080ec2498eSJames Wright     for (CeedInt j=0; j<3; j++) {
1109*efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi_j[5];
11100ec2498eSJames Wright       for (CeedInt k=0; k<5; k++)
1111*efe9d856SJames Wright         dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] +
11120ec2498eSJames Wright                    Grad_dq[1][k][i] * dXdx[1][j];
11130ec2498eSJames Wright       dx_i[j] = 1.;
1114*efe9d856SJames Wright       grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i);
11150ec2498eSJames Wright     }
11160ec2498eSJames Wright 
11170ec2498eSJames Wright     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
11180ec2498eSJames Wright     KMStrainRate(grad_ds, dstrain_rate);
11190ec2498eSJames Wright     NewtonianStress(context, dstrain_rate, dkmstress);
11200ec2498eSJames Wright     KMUnpack(dkmstress, dstress);
11210ec2498eSJames Wright     KMUnpack(kmstress, stress);
11220ec2498eSJames Wright     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
112330e9fa81SJames Wright 
1124b5d317f8SJames Wright     StateConservative dF_inviscid[3];
1125b5d317f8SJames Wright     FluxInviscid_fwd(context, s, ds, dF_inviscid);
112630e9fa81SJames Wright 
1127b5d317f8SJames Wright     CeedScalar dFlux[5] = {0.};
1128b5d317f8SJames Wright     for (int j=0; j<3; j++) {
1129b5d317f8SJames Wright       dFlux[0] += dF_inviscid[j].density * norm[j];
1130b5d317f8SJames Wright       for (int k=0; k<3; k++)
11310ec2498eSJames Wright         dFlux[k+1] += (dF_inviscid[j].momentum[k] - dstress[k][j]) * norm[j];
11320ec2498eSJames Wright       dFlux[4] += (dF_inviscid[j].E_total + dFe[j]) * norm[j];
1133b5d317f8SJames Wright     }
1134b5d317f8SJames Wright 
1135b5d317f8SJames Wright     for (int j=0; j<5; j++)
1136b5d317f8SJames Wright       v[j][i] = -wdetJb * dFlux[j];
113730e9fa81SJames Wright   } // End Quadrature Point Loop
113830e9fa81SJames Wright   return 0;
113930e9fa81SJames Wright }
114030e9fa81SJames Wright 
114188b783a1SJames Wright // *****************************************************************************
1142dc805cc4SLeila Ghaffari // This QFunction implements the Navier-Stokes equations (mentioned above) in
1143dc805cc4SLeila Ghaffari //   primitive variables and with implicit time stepping method
1144dc805cc4SLeila Ghaffari //
1145dc805cc4SLeila Ghaffari // *****************************************************************************
1146dc805cc4SLeila Ghaffari CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q,
1147dc805cc4SLeila Ghaffari     const CeedScalar *const *in, CeedScalar *const *out) {
1148dc805cc4SLeila Ghaffari   // *INDENT-OFF*
1149dc805cc4SLeila Ghaffari   // Inputs
1150dc805cc4SLeila Ghaffari   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
1151dc805cc4SLeila Ghaffari                    (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
1152dc805cc4SLeila Ghaffari                    (*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
1153dc805cc4SLeila Ghaffari                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
1154dc805cc4SLeila Ghaffari                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
1155dc805cc4SLeila Ghaffari   // Outputs
1156dc805cc4SLeila Ghaffari   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
1157dc805cc4SLeila Ghaffari              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1],
1158dc805cc4SLeila Ghaffari              (*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2];
1159dc805cc4SLeila Ghaffari   // *INDENT-ON*
1160dc805cc4SLeila Ghaffari   // Context
1161dc805cc4SLeila Ghaffari   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
1162dc805cc4SLeila Ghaffari   const CeedScalar mu     = context->mu;
1163dc805cc4SLeila Ghaffari   const CeedScalar cv     = context->cv;
1164dc805cc4SLeila Ghaffari   const CeedScalar cp     = context->cp;
1165dc805cc4SLeila Ghaffari   const CeedScalar *g     = context->g;
1166dc805cc4SLeila Ghaffari   const CeedScalar dt     = context->dt;
1167dc805cc4SLeila Ghaffari   const CeedScalar gamma  = cp / cv;
1168dc805cc4SLeila Ghaffari   const CeedScalar Rd     = cp - cv;
1169dc805cc4SLeila Ghaffari 
1170dc805cc4SLeila Ghaffari   CeedPragmaSIMD
1171dc805cc4SLeila Ghaffari   // Quadrature Point Loop
1172dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
1173dc805cc4SLeila Ghaffari     CeedScalar Y[5];
1174dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++) Y[j] = q[j][i];
1175dc805cc4SLeila Ghaffari     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
1176dc805cc4SLeila Ghaffari     State s = StateFromY(context, Y, x_i);
1177dc805cc4SLeila Ghaffari 
1178dc805cc4SLeila Ghaffari     // -- Interp-to-Interp q_data
1179dc805cc4SLeila Ghaffari     const CeedScalar wdetJ      =   q_data[0][i];
1180dc805cc4SLeila Ghaffari     // -- Interp-to-Grad q_data
1181dc805cc4SLeila Ghaffari     // ---- Inverse of change of coordinate matrix: X_i,j
1182dc805cc4SLeila Ghaffari     // *INDENT-OFF*
1183dc805cc4SLeila Ghaffari     const CeedScalar dXdx[3][3] = {{q_data[1][i],
1184dc805cc4SLeila Ghaffari                                     q_data[2][i],
1185dc805cc4SLeila Ghaffari                                     q_data[3][i]},
1186dc805cc4SLeila Ghaffari                                    {q_data[4][i],
1187dc805cc4SLeila Ghaffari                                     q_data[5][i],
1188dc805cc4SLeila Ghaffari                                     q_data[6][i]},
1189dc805cc4SLeila Ghaffari                                    {q_data[7][i],
1190dc805cc4SLeila Ghaffari                                     q_data[8][i],
1191dc805cc4SLeila Ghaffari                                     q_data[9][i]}
1192dc805cc4SLeila Ghaffari                                   };
1193dc805cc4SLeila Ghaffari     // *INDENT-ON*
1194dc805cc4SLeila Ghaffari     State grad_s[3];
1195dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1196dc805cc4SLeila Ghaffari       CeedScalar dx_i[3] = {0}, dY[5];
1197dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<5; k++)
1198dc805cc4SLeila Ghaffari         dY[k] = Grad_q[0][k][i] * dXdx[0][j] +
1199dc805cc4SLeila Ghaffari                 Grad_q[1][k][i] * dXdx[1][j] +
1200dc805cc4SLeila Ghaffari                 Grad_q[2][k][i] * dXdx[2][j];
1201dc805cc4SLeila Ghaffari       dx_i[j] = 1.;
1202dc805cc4SLeila Ghaffari       grad_s[j] = StateFromY_fwd(context, s, dY, x_i, dx_i);
1203dc805cc4SLeila Ghaffari     }
1204dc805cc4SLeila Ghaffari 
1205dc805cc4SLeila Ghaffari     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
1206dc805cc4SLeila Ghaffari     KMStrainRate(grad_s, strain_rate);
1207dc805cc4SLeila Ghaffari     NewtonianStress(context, strain_rate, kmstress);
1208dc805cc4SLeila Ghaffari     KMUnpack(kmstress, stress);
1209dc805cc4SLeila Ghaffari     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
1210dc805cc4SLeila Ghaffari 
1211dc805cc4SLeila Ghaffari     StateConservative F_inviscid[3];
1212dc805cc4SLeila Ghaffari     FluxInviscid(context, s, F_inviscid);
1213dc805cc4SLeila Ghaffari 
1214dc805cc4SLeila Ghaffari     // Total flux
1215dc805cc4SLeila Ghaffari     CeedScalar Flux[5][3];
1216dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1217dc805cc4SLeila Ghaffari       Flux[0][j] = F_inviscid[j].density;
1218dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<3; k++)
1219dc805cc4SLeila Ghaffari         Flux[k+1][j] = F_inviscid[j].momentum[k] - stress[k][j];
1220dc805cc4SLeila Ghaffari       Flux[4][j] = F_inviscid[j].E_total + Fe[j];
1221dc805cc4SLeila Ghaffari     }
1222dc805cc4SLeila Ghaffari 
1223dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1224dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<5; k++) {
1225dc805cc4SLeila Ghaffari         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * Flux[k][0] +
1226dc805cc4SLeila Ghaffari                                     dXdx[j][1] * Flux[k][1] +
1227dc805cc4SLeila Ghaffari                                     dXdx[j][2] * Flux[k][2]);
1228dc805cc4SLeila Ghaffari       }
1229dc805cc4SLeila Ghaffari     }
1230dc805cc4SLeila Ghaffari 
1231dc805cc4SLeila Ghaffari     const CeedScalar body_force[5] = {0, s.U.density *g[0], s.U.density *g[1], s.U.density *g[2], 0};
1232dc805cc4SLeila Ghaffari 
1233dc805cc4SLeila Ghaffari     CeedScalar Y_dot[5], dx0[3] = {0};
1234dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) Y_dot[j] = q_dot[j][i];
1235dc805cc4SLeila Ghaffari     State s_dot = StateFromY_fwd(context, s, Y_dot, x_i, dx0);
1236dc805cc4SLeila Ghaffari 
1237dc805cc4SLeila Ghaffari     CeedScalar U_dot[5] = {0.};
1238dc805cc4SLeila Ghaffari     U_dot[0] = s_dot.U.density;
1239dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++)
1240dc805cc4SLeila Ghaffari       U_dot[j+1] = s_dot.U.momentum[j];
1241dc805cc4SLeila Ghaffari     U_dot[4] = s_dot.U.E_total;
1242dc805cc4SLeila Ghaffari 
1243dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
1244dc805cc4SLeila Ghaffari       v[j][i] = wdetJ * (U_dot[j] - body_force[j]);
1245dc805cc4SLeila Ghaffari 
1246dc805cc4SLeila Ghaffari     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
1247dc805cc4SLeila Ghaffari     CeedScalar jacob_F_conv[3][5][5] = {0};
1248dc805cc4SLeila Ghaffari     computeFluxJacobian_NS(jacob_F_conv, s.U.density, s.Y.velocity, s.U.E_total,
1249dc805cc4SLeila Ghaffari                            gamma, g, x_i);
1250dc805cc4SLeila Ghaffari     CeedScalar grad_U[5][3];
1251dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
1252dc805cc4SLeila Ghaffari       grad_U[0][j] = grad_s[j].U.density;
1253dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<3; k++) grad_U[k+1][j] = grad_s[j].U.momentum[k];
1254dc805cc4SLeila Ghaffari       grad_U[4][j] = grad_s[j].U.E_total;
1255dc805cc4SLeila Ghaffari     }
1256dc805cc4SLeila Ghaffari 
1257dc805cc4SLeila Ghaffari     // strong_conv = dF/dq * dq/dx    (Strong convection)
1258dc805cc4SLeila Ghaffari     CeedScalar strong_conv[5] = {0};
1259dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++)
1260dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<5; k++)
1261dc805cc4SLeila Ghaffari         for (CeedInt l=0; l<5; l++)
1262dc805cc4SLeila Ghaffari           strong_conv[k] += jacob_F_conv[j][k][l] * grad_U[l][j];
1263dc805cc4SLeila Ghaffari 
1264dc805cc4SLeila Ghaffari     // Strong residual
1265dc805cc4SLeila Ghaffari     CeedScalar strong_res[5];
1266dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
1267dc805cc4SLeila Ghaffari       strong_res[j] = U_dot[j] + strong_conv[j] - body_force[j];
1268dc805cc4SLeila Ghaffari 
1269dc805cc4SLeila Ghaffari     // -- Stabilization method: none, SU, or SUPG
1270dc805cc4SLeila Ghaffari     CeedScalar stab[5][3] = {{0.}};
1271dc805cc4SLeila Ghaffari     CeedScalar tau_strong_res[5] = {0.}, tau_strong_res_conservative[5] = {0};
1272dc805cc4SLeila Ghaffari     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
1273dc805cc4SLeila Ghaffari     CeedScalar Tau_d[3] = {0.};
1274dc805cc4SLeila Ghaffari     switch (context->stabilization) {
1275dc805cc4SLeila Ghaffari     case STAB_NONE:        // Galerkin
1276dc805cc4SLeila Ghaffari       break;
1277dc805cc4SLeila Ghaffari     case STAB_SU:        // SU
1278dc805cc4SLeila Ghaffari       Tau_diagPrim(Tau_d, dXdx, s.Y.velocity, cv, context, mu, dt, s.U.density);
1279dc805cc4SLeila Ghaffari       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
1280dc805cc4SLeila Ghaffari       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
1281dc805cc4SLeila Ghaffari       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
1282dc805cc4SLeila Ghaffari       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
1283dc805cc4SLeila Ghaffari       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
1284dc805cc4SLeila Ghaffari       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
1285dc805cc4SLeila Ghaffari                                   tau_strong_conv, tau_strong_conv_conservative);
1286dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<3; j++)
1287dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<5; k++)
1288dc805cc4SLeila Ghaffari           for (CeedInt l=0; l<5; l++)
1289dc805cc4SLeila Ghaffari             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
1290dc805cc4SLeila Ghaffari 
1291dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<5; j++)
1292dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<3; k++)
1293dc805cc4SLeila Ghaffari           Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
1294dc805cc4SLeila Ghaffari                                     stab[j][1] * dXdx[k][1] +
1295dc805cc4SLeila Ghaffari                                     stab[j][2] * dXdx[k][2]);
1296dc805cc4SLeila Ghaffari 
1297dc805cc4SLeila Ghaffari       break;
1298dc805cc4SLeila Ghaffari     case STAB_SUPG:        // SUPG
1299dc805cc4SLeila Ghaffari       Tau_diagPrim(Tau_d, dXdx, s.Y.velocity, cv, context, mu, dt, s.U.density);
1300dc805cc4SLeila Ghaffari       tau_strong_res[0] = Tau_d[0] * strong_res[0];
1301dc805cc4SLeila Ghaffari       tau_strong_res[1] = Tau_d[1] * strong_res[1];
1302dc805cc4SLeila Ghaffari       tau_strong_res[2] = Tau_d[1] * strong_res[2];
1303dc805cc4SLeila Ghaffari       tau_strong_res[3] = Tau_d[1] * strong_res[3];
1304dc805cc4SLeila Ghaffari       tau_strong_res[4] = Tau_d[2] * strong_res[4];
1305dc805cc4SLeila Ghaffari 
1306dc805cc4SLeila Ghaffari       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
1307dc805cc4SLeila Ghaffari                                   tau_strong_res, tau_strong_res_conservative);
1308dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<3; j++)
1309dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<5; k++)
1310dc805cc4SLeila Ghaffari           for (CeedInt l=0; l<5; l++)
1311dc805cc4SLeila Ghaffari             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_res_conservative[l];
1312dc805cc4SLeila Ghaffari 
1313dc805cc4SLeila Ghaffari       for (CeedInt j=0; j<5; j++)
1314dc805cc4SLeila Ghaffari         for (CeedInt k=0; k<3; k++)
1315dc805cc4SLeila Ghaffari           Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
1316dc805cc4SLeila Ghaffari                                     stab[j][1] * dXdx[k][1] +
1317dc805cc4SLeila Ghaffari                                     stab[j][2] * dXdx[k][2]);
1318dc805cc4SLeila Ghaffari       break;
1319dc805cc4SLeila Ghaffari     }
1320dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++) jac_data[j][i] = Y[j];
1321dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<6; j++) jac_data[5+j][i] = kmstress[j];
1322dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) jac_data[5+6+j][i] = Tau_d[j];
1323dc805cc4SLeila Ghaffari 
1324dc805cc4SLeila Ghaffari   } // End Quadrature Point Loop
1325dc805cc4SLeila Ghaffari 
1326dc805cc4SLeila Ghaffari   // Return
1327dc805cc4SLeila Ghaffari   return 0;
1328dc805cc4SLeila Ghaffari }
1329dc805cc4SLeila Ghaffari 
1330dc805cc4SLeila Ghaffari // *****************************************************************************
1331dc805cc4SLeila Ghaffari // This QFunction implements the jacobean of the Navier-Stokes equations
1332dc805cc4SLeila Ghaffari //   in primitive variables for implicit time stepping method.
1333dc805cc4SLeila Ghaffari //
1334dc805cc4SLeila Ghaffari // *****************************************************************************
1335dc805cc4SLeila Ghaffari CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q,
1336dc805cc4SLeila Ghaffari     const CeedScalar *const *in, CeedScalar *const *out) {
1337dc805cc4SLeila Ghaffari   // *INDENT-OFF*
1338dc805cc4SLeila Ghaffari   // Inputs
1339dc805cc4SLeila Ghaffari   const CeedScalar (*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
1340dc805cc4SLeila Ghaffari                    (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
1341dc805cc4SLeila Ghaffari                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
1342dc805cc4SLeila Ghaffari                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
1343dc805cc4SLeila Ghaffari                    (*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
1344dc805cc4SLeila Ghaffari   // Outputs
1345dc805cc4SLeila Ghaffari   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
1346dc805cc4SLeila Ghaffari              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
1347dc805cc4SLeila Ghaffari   // *INDENT-ON*
1348dc805cc4SLeila Ghaffari   // Context
1349dc805cc4SLeila Ghaffari   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
1350dc805cc4SLeila Ghaffari   const CeedScalar *g = context->g;
1351dc805cc4SLeila Ghaffari   const CeedScalar cp = context->cp;
1352dc805cc4SLeila Ghaffari   const CeedScalar cv = context->cv;
1353dc805cc4SLeila Ghaffari   const CeedScalar Rd = cp - cv;
1354dc805cc4SLeila Ghaffari   const CeedScalar gamma = cp / cv;
1355dc805cc4SLeila Ghaffari 
1356dc805cc4SLeila Ghaffari   CeedPragmaSIMD
1357dc805cc4SLeila Ghaffari   // Quadrature Point Loop
1358dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
1359dc805cc4SLeila Ghaffari     // -- Interp-to-Interp q_data
1360dc805cc4SLeila Ghaffari     const CeedScalar wdetJ      =   q_data[0][i];
1361dc805cc4SLeila Ghaffari     // -- Interp-to-Grad q_data
1362dc805cc4SLeila Ghaffari     // ---- Inverse of change of coordinate matrix: X_i,j
1363dc805cc4SLeila Ghaffari     // *INDENT-OFF*
1364dc805cc4SLeila Ghaffari     const CeedScalar dXdx[3][3] = {{q_data[1][i],
1365dc805cc4SLeila Ghaffari                                     q_data[2][i],
1366dc805cc4SLeila Ghaffari                                     q_data[3][i]},
1367dc805cc4SLeila Ghaffari                                    {q_data[4][i],
1368dc805cc4SLeila Ghaffari                                     q_data[5][i],
1369dc805cc4SLeila Ghaffari                                     q_data[6][i]},
1370dc805cc4SLeila Ghaffari                                    {q_data[7][i],
1371dc805cc4SLeila Ghaffari                                     q_data[8][i],
1372dc805cc4SLeila Ghaffari                                     q_data[9][i]}
1373dc805cc4SLeila Ghaffari                                   };
1374dc805cc4SLeila Ghaffari     // *INDENT-ON*
1375dc805cc4SLeila Ghaffari 
1376dc805cc4SLeila Ghaffari     CeedScalar Y[5], kmstress[6], Tau_d[3] __attribute((unused));
1377dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) Y[j] = jac_data[j][i];
1378dc805cc4SLeila Ghaffari     for (int j=0; j<6; j++) kmstress[j] = jac_data[5+j][i];
1379dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) Tau_d[j] = jac_data[5+6+j][i];
1380dc805cc4SLeila Ghaffari     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
1381dc805cc4SLeila Ghaffari     State s = StateFromY(context, Y, x_i);
1382dc805cc4SLeila Ghaffari 
1383dc805cc4SLeila Ghaffari     CeedScalar dY[5], dx0[3] = {0};
1384dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) dY[j] = dq[j][i];
1385dc805cc4SLeila Ghaffari     State ds = StateFromY_fwd(context, s, dY, x_i, dx0);
1386dc805cc4SLeila Ghaffari 
1387dc805cc4SLeila Ghaffari     State grad_ds[3];
1388dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) {
1389dc805cc4SLeila Ghaffari       CeedScalar dYj[5];
1390dc805cc4SLeila Ghaffari       for (int k=0; k<5; k++)
1391dc805cc4SLeila Ghaffari         dYj[k] = Grad_dq[0][k][i] * dXdx[0][j] +
1392dc805cc4SLeila Ghaffari                  Grad_dq[1][k][i] * dXdx[1][j] +
1393dc805cc4SLeila Ghaffari                  Grad_dq[2][k][i] * dXdx[2][j];
1394dc805cc4SLeila Ghaffari       grad_ds[j] = StateFromY_fwd(context, s, dYj, x_i, dx0);
1395dc805cc4SLeila Ghaffari     }
1396dc805cc4SLeila Ghaffari 
1397dc805cc4SLeila Ghaffari     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
1398dc805cc4SLeila Ghaffari     KMStrainRate(grad_ds, dstrain_rate);
1399dc805cc4SLeila Ghaffari     NewtonianStress(context, dstrain_rate, dkmstress);
1400dc805cc4SLeila Ghaffari     KMUnpack(dkmstress, dstress);
1401dc805cc4SLeila Ghaffari     KMUnpack(kmstress, stress);
1402dc805cc4SLeila Ghaffari     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
1403dc805cc4SLeila Ghaffari 
1404dc805cc4SLeila Ghaffari     StateConservative dF_inviscid[3];
1405dc805cc4SLeila Ghaffari     FluxInviscid_fwd(context, s, ds, dF_inviscid);
1406dc805cc4SLeila Ghaffari 
1407dc805cc4SLeila Ghaffari     // Total flux
1408dc805cc4SLeila Ghaffari     CeedScalar dFlux[5][3];
1409dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) {
1410dc805cc4SLeila Ghaffari       dFlux[0][j] = dF_inviscid[j].density;
1411dc805cc4SLeila Ghaffari       for (int k=0; k<3; k++)
1412dc805cc4SLeila Ghaffari         dFlux[k+1][j] = dF_inviscid[j].momentum[k] - dstress[k][j];
1413dc805cc4SLeila Ghaffari       dFlux[4][j] = dF_inviscid[j].E_total + dFe[j];
1414dc805cc4SLeila Ghaffari     }
1415dc805cc4SLeila Ghaffari 
1416dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) {
1417dc805cc4SLeila Ghaffari       for (int k=0; k<5; k++) {
1418dc805cc4SLeila Ghaffari         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * dFlux[k][0] +
1419dc805cc4SLeila Ghaffari                                     dXdx[j][1] * dFlux[k][1] +
1420dc805cc4SLeila Ghaffari                                     dXdx[j][2] * dFlux[k][2]);
1421dc805cc4SLeila Ghaffari       }
1422dc805cc4SLeila Ghaffari     }
1423dc805cc4SLeila Ghaffari 
1424dc805cc4SLeila Ghaffari     const CeedScalar dbody_force[5] = {0,
1425dc805cc4SLeila Ghaffari                                        ds.U.density *g[0],
1426dc805cc4SLeila Ghaffari                                        ds.U.density *g[1],
1427dc805cc4SLeila Ghaffari                                        ds.U.density *g[2],
1428dc805cc4SLeila Ghaffari                                        0
1429dc805cc4SLeila Ghaffari                                       };
1430dc805cc4SLeila Ghaffari     CeedScalar dU[5] = {0.};
1431dc805cc4SLeila Ghaffari     dU[0] = ds.U.density;
1432dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++)
1433dc805cc4SLeila Ghaffari       dU[j+1] = ds.U.momentum[j];
1434dc805cc4SLeila Ghaffari     dU[4] = ds.U.E_total;
1435dc805cc4SLeila Ghaffari 
1436dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++)
1437dc805cc4SLeila Ghaffari       v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]);
1438dc805cc4SLeila Ghaffari 
1439dc805cc4SLeila Ghaffari     if (1) {
1440dc805cc4SLeila Ghaffari       CeedScalar jacob_F_conv[3][5][5] = {0};
1441dc805cc4SLeila Ghaffari       computeFluxJacobian_NS(jacob_F_conv, s.U.density, s.Y.velocity, s.U.E_total,
1442dc805cc4SLeila Ghaffari                              gamma, g, x_i);
1443dc805cc4SLeila Ghaffari       CeedScalar grad_dU[5][3];
1444dc805cc4SLeila Ghaffari       for (int j=0; j<3; j++) {
1445dc805cc4SLeila Ghaffari         grad_dU[0][j] = grad_ds[j].U.density;
1446dc805cc4SLeila Ghaffari         for (int k=0; k<3; k++) grad_dU[k+1][j] = grad_ds[j].U.momentum[k];
1447dc805cc4SLeila Ghaffari         grad_dU[4][j] = grad_ds[j].U.E_total;
1448dc805cc4SLeila Ghaffari       }
1449dc805cc4SLeila Ghaffari       CeedScalar dstrong_conv[5] = {0.};
1450dc805cc4SLeila Ghaffari       for (int j=0; j<3; j++)
1451dc805cc4SLeila Ghaffari         for (int k=0; k<5; k++)
1452dc805cc4SLeila Ghaffari           for (int l=0; l<5; l++)
1453dc805cc4SLeila Ghaffari             dstrong_conv[k] += jacob_F_conv[j][k][l] * grad_dU[l][j];
1454dc805cc4SLeila Ghaffari 
1455dc805cc4SLeila Ghaffari       CeedScalar dstrong_res[5];
1456dc805cc4SLeila Ghaffari       for (int j=0; j<5; j++)
1457dc805cc4SLeila Ghaffari         dstrong_res[j] = context->ijacobian_time_shift * dU[j] +
1458dc805cc4SLeila Ghaffari                          dstrong_conv[j] -
1459dc805cc4SLeila Ghaffari                          dbody_force[j];
1460dc805cc4SLeila Ghaffari 
1461dc805cc4SLeila Ghaffari       CeedScalar dtau_strong_res[5] = {0.},
1462dc805cc4SLeila Ghaffari                                       dtau_strong_res_conservative[5] = {0.};
1463dc805cc4SLeila Ghaffari       dtau_strong_res[0] = Tau_d[0] * dstrong_res[0];
1464dc805cc4SLeila Ghaffari       dtau_strong_res[1] = Tau_d[1] * dstrong_res[1];
1465dc805cc4SLeila Ghaffari       dtau_strong_res[2] = Tau_d[1] * dstrong_res[2];
1466dc805cc4SLeila Ghaffari       dtau_strong_res[3] = Tau_d[1] * dstrong_res[3];
1467dc805cc4SLeila Ghaffari       dtau_strong_res[4] = Tau_d[2] * dstrong_res[4];
1468dc805cc4SLeila Ghaffari       PrimitiveToConservative_fwd(s.U.density, s.Y.velocity, s.U.E_total, Rd, cv,
1469dc805cc4SLeila Ghaffari                                   dtau_strong_res, dtau_strong_res_conservative);
1470dc805cc4SLeila Ghaffari       CeedScalar dstab[5][3] = {0};
1471dc805cc4SLeila Ghaffari       for (int j=0; j<3; j++)
1472dc805cc4SLeila Ghaffari         for (int k=0; k<5; k++)
1473dc805cc4SLeila Ghaffari           for (int l=0; l<5; l++)
1474dc805cc4SLeila Ghaffari             dstab[k][j] += jacob_F_conv[j][k][l] * dtau_strong_res_conservative[l];
1475dc805cc4SLeila Ghaffari 
1476dc805cc4SLeila Ghaffari       for (int j=0; j<5; j++)
1477dc805cc4SLeila Ghaffari         for (int k=0; k<3; k++)
1478dc805cc4SLeila Ghaffari           Grad_v[k][j][i] += wdetJ*(dstab[j][0] * dXdx[k][0] +
1479dc805cc4SLeila Ghaffari                                     dstab[j][1] * dXdx[k][1] +
1480dc805cc4SLeila Ghaffari                                     dstab[j][2] * dXdx[k][2]);
1481dc805cc4SLeila Ghaffari 
1482dc805cc4SLeila Ghaffari     }
1483dc805cc4SLeila Ghaffari   } // End Quadrature Point Loop
1484dc805cc4SLeila Ghaffari   return 0;
1485dc805cc4SLeila Ghaffari }
1486dc805cc4SLeila Ghaffari // *****************************************************************************
1487dc805cc4SLeila Ghaffari 
148888b783a1SJames Wright #endif // newtonian_h
1489