xref: /libCEED/examples/fluids/qfunctions/newtonian.h (revision 20840d5027c5dd695d8ebd45bd884db127586bc6)
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 <ceed.h>
16c9c2c079SJeremy L Thompson #include <math.h>
17c6e8c570SJames Wright #include "newtonian_state.h"
18c9c2c079SJeremy L Thompson #include "newtonian_types.h"
192b89d87eSLeila Ghaffari #include "stabilization.h"
20c9c2c079SJeremy L Thompson #include "utils.h"
2188626eedSJames Wright 
2288626eedSJames Wright // *****************************************************************************
2388b783a1SJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems
2488b783a1SJames Wright // *****************************************************************************
2588b783a1SJames Wright CEED_QFUNCTION(ICsNewtonianIG)(void *ctx, CeedInt Q,
2688b783a1SJames Wright                                const CeedScalar *const *in, CeedScalar *const *out) {
2788b783a1SJames Wright   // Inputs
2888b783a1SJames Wright   const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
2988b783a1SJames Wright 
3088b783a1SJames Wright   // Outputs
3188b783a1SJames Wright   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
3288b783a1SJames Wright 
3388626eedSJames Wright   // Context
3488626eedSJames Wright   const SetupContext context = (SetupContext)ctx;
3588626eedSJames Wright   const CeedScalar theta0    = context->theta0;
3688626eedSJames Wright   const CeedScalar P0        = context->P0;
3788626eedSJames Wright   const CeedScalar cv        = context->cv;
3888626eedSJames Wright   const CeedScalar cp        = context->cp;
3988626eedSJames Wright   const CeedScalar *g        = context->g;
4088626eedSJames Wright   const CeedScalar Rd        = cp - cv;
4188626eedSJames Wright 
4288b783a1SJames Wright   // Quadrature Point Loop
4388b783a1SJames Wright   CeedPragmaSIMD
4488b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
4588b783a1SJames Wright     CeedScalar q[5] = {0.};
4688b783a1SJames Wright 
4788b783a1SJames Wright     // Setup
4888b783a1SJames Wright     // -- Coordinates
4988626eedSJames Wright     const CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]};
502b89d87eSLeila Ghaffari     const CeedScalar e_potential = -Dot3(g, x);
5188b783a1SJames Wright 
5288b783a1SJames Wright     // -- Density
5388626eedSJames Wright     const CeedScalar rho = P0 / (Rd*theta0);
5488b783a1SJames Wright 
5588b783a1SJames Wright     // Initial Conditions
5688b783a1SJames Wright     q[0] = rho;
5788b783a1SJames Wright     q[1] = 0.0;
5888b783a1SJames Wright     q[2] = 0.0;
5988b783a1SJames Wright     q[3] = 0.0;
6088626eedSJames Wright     q[4] = rho * (cv*theta0 + e_potential);
6188b783a1SJames Wright 
6288b783a1SJames Wright     for (CeedInt j=0; j<5; j++)
6388b783a1SJames Wright       q0[j][i] = q[j];
642b89d87eSLeila Ghaffari 
6588b783a1SJames Wright   } // End of Quadrature Point Loop
6688b783a1SJames Wright   return 0;
6788b783a1SJames Wright }
6888b783a1SJames Wright 
6988b783a1SJames Wright // *****************************************************************************
70dc805cc4SLeila Ghaffari // This QFunction sets a "still" initial condition for generic Newtonian IG
71dc805cc4SLeila Ghaffari //   problems in primitive variables
72dc805cc4SLeila Ghaffari // *****************************************************************************
73dc805cc4SLeila Ghaffari CEED_QFUNCTION(ICsNewtonianIG_Prim)(void *ctx, CeedInt Q,
74dc805cc4SLeila Ghaffari                                     const CeedScalar *const *in, CeedScalar *const *out) {
75dc805cc4SLeila Ghaffari   // Outputs
76dc805cc4SLeila Ghaffari   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
77dc805cc4SLeila Ghaffari 
78dc805cc4SLeila Ghaffari   // Context
79dc805cc4SLeila Ghaffari   const SetupContext context = (SetupContext)ctx;
80dc805cc4SLeila Ghaffari   const CeedScalar theta0    = context->theta0;
81dc805cc4SLeila Ghaffari   const CeedScalar P0        = context->P0;
82dc805cc4SLeila Ghaffari 
83dc805cc4SLeila Ghaffari   // Quadrature Point Loop
84dc805cc4SLeila Ghaffari   CeedPragmaSIMD
85dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
86dc805cc4SLeila Ghaffari     CeedScalar q[5] = {0.};
87dc805cc4SLeila Ghaffari 
88dc805cc4SLeila Ghaffari     // Initial Conditions
89dc805cc4SLeila Ghaffari     q[0] = P0;
90dc805cc4SLeila Ghaffari     q[1] = 0.0;
91dc805cc4SLeila Ghaffari     q[2] = 0.0;
92dc805cc4SLeila Ghaffari     q[3] = 0.0;
93dc805cc4SLeila Ghaffari     q[4] = theta0;
94dc805cc4SLeila Ghaffari 
95dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
96dc805cc4SLeila Ghaffari       q0[j][i] = q[j];
97dc805cc4SLeila Ghaffari 
98dc805cc4SLeila Ghaffari   } // End of Quadrature Point Loop
99dc805cc4SLeila Ghaffari   return 0;
100dc805cc4SLeila Ghaffari }
101dc805cc4SLeila Ghaffari 
102dc805cc4SLeila Ghaffari // *****************************************************************************
10388b783a1SJames Wright // This QFunction implements the following formulation of Navier-Stokes with
10488b783a1SJames Wright //   explicit time stepping method
10588b783a1SJames Wright //
10688b783a1SJames Wright // This is 3D compressible Navier-Stokes in conservation form with state
10788b783a1SJames Wright //   variables of density, momentum density, and total energy density.
10888b783a1SJames Wright //
10988b783a1SJames Wright // State Variables: q = ( rho, U1, U2, U3, E )
11088b783a1SJames Wright //   rho - Mass Density
11188b783a1SJames Wright //   Ui  - Momentum Density,      Ui = rho ui
11288b783a1SJames Wright //   E   - Total Energy Density,  E  = rho (cv T + (u u)/2 + g z)
11388b783a1SJames Wright //
11488b783a1SJames Wright // Navier-Stokes Equations:
11588b783a1SJames Wright //   drho/dt + div( U )                               = 0
11688b783a1SJames Wright //   dU/dt   + div( rho (u x u) + P I3 ) + rho g khat = div( Fu )
11788b783a1SJames Wright //   dE/dt   + div( (E + P) u )                       = div( Fe )
11888b783a1SJames Wright //
11988b783a1SJames Wright // Viscous Stress:
12088b783a1SJames Wright //   Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3)
12188b783a1SJames Wright //
12288b783a1SJames Wright // Thermal Stress:
12388b783a1SJames Wright //   Fe = u Fu + k grad( T )
12488626eedSJames Wright // Equation of State
12588b783a1SJames Wright //   P = (gamma - 1) (E - rho (u u) / 2 - rho g z)
12688b783a1SJames Wright //
12788b783a1SJames Wright // Stabilization:
12888b783a1SJames Wright //   Tau = diag(TauC, TauM, TauM, TauM, TauE)
12988b783a1SJames Wright //     f1 = rho  sqrt(ui uj gij)
13088b783a1SJames Wright //     gij = dXi/dX * dXi/dX
13188b783a1SJames Wright //     TauC = Cc f1 / (8 gii)
13288b783a1SJames Wright //     TauM = min( 1 , 1 / f1 )
13388b783a1SJames Wright //     TauE = TauM / (Ce cv)
13488b783a1SJames Wright //
13588b783a1SJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
13688b783a1SJames Wright //
13788b783a1SJames Wright // Constants:
13888b783a1SJames Wright //   lambda = - 2 / 3,  From Stokes hypothesis
13988b783a1SJames Wright //   mu              ,  Dynamic viscosity
14088b783a1SJames Wright //   k               ,  Thermal conductivity
14188b783a1SJames Wright //   cv              ,  Specific heat, constant volume
14288b783a1SJames Wright //   cp              ,  Specific heat, constant pressure
14388b783a1SJames Wright //   g               ,  Gravity
14488b783a1SJames Wright //   gamma  = cp / cv,  Specific heat ratio
14588b783a1SJames Wright //
14688b783a1SJames Wright // We require the product of the inverse of the Jacobian (dXdx_j,k) and
14788b783a1SJames Wright // its transpose (dXdx_k,j) to properly compute integrals of the form:
14888b783a1SJames Wright // int( gradv gradu )
14988b783a1SJames Wright //
15088b783a1SJames Wright // *****************************************************************************
1515c677226SJed Brown CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q,
15288b783a1SJames Wright                                       const CeedScalar *const *in, CeedScalar *const *out) {
15388b783a1SJames Wright   // *INDENT-OFF*
15488b783a1SJames Wright   // Inputs
15588b783a1SJames Wright   const CeedScalar (*q)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[0],
156a3ae0734SJed Brown                    (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
15788b783a1SJames Wright                    (*q_data)[CEED_Q_VLA]    = (const CeedScalar(*)[CEED_Q_VLA])in[2],
15888b783a1SJames Wright                    (*x)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[3];
15988b783a1SJames Wright   // Outputs
16088b783a1SJames Wright   CeedScalar (*v)[CEED_Q_VLA]         = (CeedScalar(*)[CEED_Q_VLA])out[0],
161a3ae0734SJed Brown              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
16288b783a1SJames Wright   // *INDENT-ON*
16388b783a1SJames Wright 
16488b783a1SJames Wright   // Context
16588b783a1SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
16688626eedSJames Wright   const CeedScalar *g = context->g;
16788626eedSJames Wright   const CeedScalar dt = context->dt;
16888b783a1SJames Wright 
16988b783a1SJames Wright   CeedPragmaSIMD
17088b783a1SJames Wright   // Quadrature Point Loop
17188b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
1725c677226SJed Brown     CeedScalar U[5];
1735c677226SJed Brown     for (int j=0; j<5; j++) U[j] = q[j][i];
1745c677226SJed Brown     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
1755c677226SJed Brown     State s = StateFromU(context, U, x_i);
1765c677226SJed Brown 
17788b783a1SJames Wright     // -- Interp-to-Interp q_data
17888b783a1SJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
17988b783a1SJames Wright     // -- Interp-to-Grad q_data
18088b783a1SJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
18188b783a1SJames Wright     // *INDENT-OFF*
18223d6ba15SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i], q_data[2][i], q_data[3][i]},
18323d6ba15SJames Wright                                    {q_data[4][i], q_data[5][i], q_data[6][i]},
18423d6ba15SJames Wright                                    {q_data[7][i], q_data[8][i], q_data[9][i]}
18588b783a1SJames Wright                                   };
18688b783a1SJames Wright     // *INDENT-ON*
1875c677226SJed Brown     State grad_s[3];
1883c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) {
1896f00d0e6SJed Brown       CeedScalar dx_i[3] = {0}, dU[5];
19039c69132SJed Brown       for (CeedInt k=0; k<5; k++)
19139c69132SJed Brown         dU[k] = Grad_q[0][k][i] * dXdx[0][j] +
19239c69132SJed Brown                 Grad_q[1][k][i] * dXdx[1][j] +
19339c69132SJed Brown                 Grad_q[2][k][i] * dXdx[2][j];
1945c677226SJed Brown       dx_i[j] = 1.;
1956f00d0e6SJed Brown       grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i);
1965c677226SJed Brown     }
1975c677226SJed Brown 
1985c677226SJed Brown     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
1995c677226SJed Brown     KMStrainRate(grad_s, strain_rate);
2005c677226SJed Brown     NewtonianStress(context, strain_rate, kmstress);
2015c677226SJed Brown     KMUnpack(kmstress, stress);
2025c677226SJed Brown     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
2035c677226SJed Brown 
2045c677226SJed Brown     StateConservative F_inviscid[3];
2055c677226SJed Brown     FluxInviscid(context, s, F_inviscid);
2065c677226SJed Brown 
2075c677226SJed Brown     // Total flux
2085c677226SJed Brown     CeedScalar Flux[5][3];
2092b89d87eSLeila Ghaffari     FluxTotal(F_inviscid, stress, Fe, Flux);
2105c677226SJed Brown 
2112b89d87eSLeila Ghaffari     for (CeedInt j=0; j<3; j++)
2122b89d87eSLeila Ghaffari       for (CeedInt k=0; k<5; k++)
213a3ae0734SJed Brown         Grad_v[j][k][i] = wdetJ * (dXdx[j][0] * Flux[k][0] +
2145c677226SJed Brown                                    dXdx[j][1] * Flux[k][1] +
2155c677226SJed Brown                                    dXdx[j][2] * Flux[k][2]);
2165c677226SJed Brown 
2175c677226SJed Brown     const CeedScalar body_force[5] = {0, s.U.density *g[0], s.U.density *g[1], s.U.density *g[2], 0};
2185c677226SJed Brown     for (int j=0; j<5; j++)
2195c677226SJed Brown       v[j][i] = wdetJ * body_force[j];
22088b783a1SJames Wright 
2212b89d87eSLeila Ghaffari     // -- Stabilization method: none (Galerkin), SU, or SUPG
2222b89d87eSLeila Ghaffari     CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0};
2232b89d87eSLeila Ghaffari     Tau_diagPrim(context, s, dXdx, dt, Tau_d);
2242b89d87eSLeila Ghaffari     Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab);
22588b783a1SJames Wright 
226ba6664aeSJames Wright     for (CeedInt j=0; j<5; j++)
227ba6664aeSJames Wright       for (CeedInt k=0; k<3; k++)
228a3ae0734SJed Brown         Grad_v[k][j][i] -= wdetJ*(stab[j][0] * dXdx[k][0] +
22988b783a1SJames Wright                                   stab[j][1] * dXdx[k][1] +
23088b783a1SJames Wright                                   stab[j][2] * dXdx[k][2]);
23188b783a1SJames Wright 
23288b783a1SJames Wright   } // End Quadrature Point Loop
23388b783a1SJames Wright 
23488b783a1SJames Wright   // Return
23588b783a1SJames Wright   return 0;
23688b783a1SJames Wright }
23788b783a1SJames Wright 
23888b783a1SJames Wright // *****************************************************************************
23988b783a1SJames Wright // This QFunction implements the Navier-Stokes equations (mentioned above) with
24088b783a1SJames Wright //   implicit time stepping method
24188b783a1SJames Wright //
24288b783a1SJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
24388b783a1SJames Wright //  SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) )
24488b783a1SJames Wright //                                       (diffussive terms will be added later)
24588b783a1SJames Wright //
24688b783a1SJames Wright // *****************************************************************************
24788b783a1SJames Wright CEED_QFUNCTION(IFunction_Newtonian)(void *ctx, CeedInt Q,
248dc805cc4SLeila Ghaffari                                     const CeedScalar *const *in, CeedScalar *const *out) {
24988b783a1SJames Wright   // *INDENT-OFF*
25088b783a1SJames Wright   // Inputs
25188b783a1SJames Wright   const CeedScalar (*q)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[0],
252a3ae0734SJed Brown                    (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
25388b783a1SJames Wright                    (*q_dot)[CEED_Q_VLA]     = (const CeedScalar(*)[CEED_Q_VLA])in[2],
25488b783a1SJames Wright                    (*q_data)[CEED_Q_VLA]    = (const CeedScalar(*)[CEED_Q_VLA])in[3],
25588b783a1SJames Wright                    (*x)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[4];
25688b783a1SJames Wright   // Outputs
25788b783a1SJames Wright   CeedScalar (*v)[CEED_Q_VLA]         = (CeedScalar(*)[CEED_Q_VLA])out[0],
258a3ae0734SJed Brown              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1],
259a3ae0734SJed Brown              (*jac_data)[CEED_Q_VLA]  = (CeedScalar(*)[CEED_Q_VLA])out[2];
26088b783a1SJames Wright   // *INDENT-ON*
26188b783a1SJames Wright   // Context
26288b783a1SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
26388626eedSJames Wright   const CeedScalar *g = context->g;
26488626eedSJames Wright   const CeedScalar dt = context->dt;
26588b783a1SJames Wright 
26688b783a1SJames Wright   CeedPragmaSIMD
26788b783a1SJames Wright   // Quadrature Point Loop
26888b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
2695c677226SJed Brown     CeedScalar U[5];
2703c4b7af6SJed Brown     for (CeedInt j=0; j<5; j++) U[j] = q[j][i];
2715c677226SJed Brown     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
2725c677226SJed Brown     State s = StateFromU(context, U, x_i);
2735c677226SJed Brown 
27488b783a1SJames Wright     // -- Interp-to-Interp q_data
27588b783a1SJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
27688b783a1SJames Wright     // -- Interp-to-Grad q_data
27788b783a1SJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
27888b783a1SJames Wright     // *INDENT-OFF*
27923d6ba15SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i], q_data[2][i], q_data[3][i]},
28023d6ba15SJames Wright                                    {q_data[4][i], q_data[5][i], q_data[6][i]},
28123d6ba15SJames Wright                                    {q_data[7][i], q_data[8][i], q_data[9][i]}
28288b783a1SJames Wright                                   };
28388b783a1SJames Wright     // *INDENT-ON*
2845c677226SJed Brown     State grad_s[3];
285ba6664aeSJames Wright     for (CeedInt j=0; j<3; j++) {
2866f00d0e6SJed Brown       CeedScalar dx_i[3] = {0}, dU[5];
28739c69132SJed Brown       for (CeedInt k=0; k<5; k++)
28839c69132SJed Brown         dU[k] = Grad_q[0][k][i] * dXdx[0][j] +
28939c69132SJed Brown                 Grad_q[1][k][i] * dXdx[1][j] +
29039c69132SJed Brown                 Grad_q[2][k][i] * dXdx[2][j];
2915c677226SJed Brown       dx_i[j] = 1.;
2926f00d0e6SJed Brown       grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i);
29388b783a1SJames Wright     }
2945c677226SJed Brown 
2955c677226SJed Brown     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
2965c677226SJed Brown     KMStrainRate(grad_s, strain_rate);
2975c677226SJed Brown     NewtonianStress(context, strain_rate, kmstress);
2985c677226SJed Brown     KMUnpack(kmstress, stress);
2995c677226SJed Brown     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
3005c677226SJed Brown 
3015c677226SJed Brown     StateConservative F_inviscid[3];
3025c677226SJed Brown     FluxInviscid(context, s, F_inviscid);
3035c677226SJed Brown 
3045c677226SJed Brown     // Total flux
3055c677226SJed Brown     CeedScalar Flux[5][3];
3062b89d87eSLeila Ghaffari     FluxTotal(F_inviscid, stress, Fe, Flux);
3075c677226SJed Brown 
3082b89d87eSLeila Ghaffari     for (CeedInt j=0; j<3; j++)
3092b89d87eSLeila Ghaffari       for (CeedInt k=0; k<5; k++)
310a3ae0734SJed Brown         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * Flux[k][0] +
3115c677226SJed Brown                                     dXdx[j][1] * Flux[k][1] +
3125c677226SJed Brown                                     dXdx[j][2] * Flux[k][2]);
3135c677226SJed Brown 
3145c677226SJed Brown     const CeedScalar body_force[5] = {0, s.U.density *g[0], s.U.density *g[1], s.U.density *g[2], 0};
3153c4b7af6SJed Brown     for (CeedInt j=0; j<5; j++)
3165c677226SJed Brown       v[j][i] = wdetJ * (q_dot[j][i] - body_force[j]);
31788b783a1SJames Wright 
3182b89d87eSLeila Ghaffari     // -- Stabilization method: none (Galerkin), SU, or SUPG
3192b89d87eSLeila Ghaffari     CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0};
3202b89d87eSLeila Ghaffari     for (CeedInt j=0; j<5; j++) U_dot[j] = q_dot[j][i];
3212b89d87eSLeila Ghaffari     Tau_diagPrim(context, s, dXdx, dt, Tau_d);
3222b89d87eSLeila Ghaffari     Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab);
32388b783a1SJames Wright 
324ba6664aeSJames Wright     for (CeedInt j=0; j<5; j++)
325ba6664aeSJames Wright       for (CeedInt k=0; k<3; k++)
326a3ae0734SJed Brown         Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
32788b783a1SJames Wright                                   stab[j][1] * dXdx[k][1] +
32888b783a1SJames Wright                                   stab[j][2] * dXdx[k][2]);
3293c4b7af6SJed Brown 
3303c4b7af6SJed Brown     for (CeedInt j=0; j<5; j++) jac_data[j][i]     = U[j];
3313c4b7af6SJed Brown     for (CeedInt j=0; j<6; j++) jac_data[5+j][i]   = kmstress[j];
3323c4b7af6SJed Brown     for (CeedInt j=0; j<3; j++) jac_data[5+6+j][i] = Tau_d[j];
33388b783a1SJames Wright 
33488b783a1SJames Wright   } // End Quadrature Point Loop
33588b783a1SJames Wright 
33688b783a1SJames Wright   // Return
33788b783a1SJames Wright   return 0;
33888b783a1SJames Wright }
339e334ad8fSJed Brown 
340dc805cc4SLeila Ghaffari // *****************************************************************************
341dc805cc4SLeila Ghaffari // This QFunction implements the jacobean of the Navier-Stokes equations
342dc805cc4SLeila Ghaffari //   for implicit time stepping method.
343dc805cc4SLeila Ghaffari //
344dc805cc4SLeila Ghaffari // *****************************************************************************
345e334ad8fSJed Brown CEED_QFUNCTION(IJacobian_Newtonian)(void *ctx, CeedInt Q,
346e334ad8fSJed Brown                                     const CeedScalar *const *in,
347e334ad8fSJed Brown                                     CeedScalar *const *out) {
348e334ad8fSJed Brown   // *INDENT-OFF*
349e334ad8fSJed Brown   // Inputs
350e334ad8fSJed Brown   const CeedScalar (*dq)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[0],
351e334ad8fSJed Brown                    (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
352e334ad8fSJed Brown                    (*q_data)[CEED_Q_VLA]     = (const CeedScalar(*)[CEED_Q_VLA])in[2],
353e334ad8fSJed Brown                    (*x)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[3],
354e334ad8fSJed Brown                    (*jac_data)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[4];
355e334ad8fSJed Brown   // Outputs
356e334ad8fSJed Brown   CeedScalar (*v)[CEED_Q_VLA]         = (CeedScalar(*)[CEED_Q_VLA])out[0],
357e334ad8fSJed Brown              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
358e334ad8fSJed Brown   // *INDENT-ON*
359e334ad8fSJed Brown   // Context
360e334ad8fSJed Brown   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
361e334ad8fSJed Brown   const CeedScalar *g = context->g;
362e334ad8fSJed Brown 
363e334ad8fSJed Brown   CeedPragmaSIMD
364e334ad8fSJed Brown   // Quadrature Point Loop
365e334ad8fSJed Brown   for (CeedInt i=0; i<Q; i++) {
366e334ad8fSJed Brown     // -- Interp-to-Interp q_data
367e334ad8fSJed Brown     const CeedScalar wdetJ      =   q_data[0][i];
368e334ad8fSJed Brown     // -- Interp-to-Grad q_data
369e334ad8fSJed Brown     // ---- Inverse of change of coordinate matrix: X_i,j
370e334ad8fSJed Brown     // *INDENT-OFF*
37123d6ba15SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i], q_data[2][i], q_data[3][i]},
37223d6ba15SJames Wright                                    {q_data[4][i], q_data[5][i], q_data[6][i]},
37323d6ba15SJames Wright                                    {q_data[7][i], q_data[8][i], q_data[9][i]}
374e334ad8fSJed Brown                                   };
375e334ad8fSJed Brown     // *INDENT-ON*
376e334ad8fSJed Brown 
377e334ad8fSJed Brown     CeedScalar U[5], kmstress[6], Tau_d[3] __attribute((unused));
378e334ad8fSJed Brown     for (int j=0; j<5; j++) U[j]        = jac_data[j][i];
379e334ad8fSJed Brown     for (int j=0; j<6; j++) kmstress[j] = jac_data[5+j][i];
380e334ad8fSJed Brown     for (int j=0; j<3; j++) Tau_d[j]    = jac_data[5+6+j][i];
381e334ad8fSJed Brown     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
382e334ad8fSJed Brown     State s = StateFromU(context, U, x_i);
383e334ad8fSJed Brown 
384e334ad8fSJed Brown     CeedScalar dU[5], dx0[3] = {0};
385e334ad8fSJed Brown     for (int j=0; j<5; j++) dU[j] = dq[j][i];
386e334ad8fSJed Brown     State ds = StateFromU_fwd(context, s, dU, x_i, dx0);
387e334ad8fSJed Brown 
388e334ad8fSJed Brown     State grad_ds[3];
389e334ad8fSJed Brown     for (int j=0; j<3; j++) {
390e334ad8fSJed Brown       CeedScalar dUj[5];
3912b89d87eSLeila Ghaffari       for (int k=0; k<5; k++)
3922b89d87eSLeila Ghaffari         dUj[k] = Grad_dq[0][k][i] * dXdx[0][j] +
3932b89d87eSLeila Ghaffari                  Grad_dq[1][k][i] * dXdx[1][j] +
3942b89d87eSLeila Ghaffari                  Grad_dq[2][k][i] * dXdx[2][j];
395e334ad8fSJed Brown       grad_ds[j] = StateFromU_fwd(context, s, dUj, x_i, dx0);
396e334ad8fSJed Brown     }
397e334ad8fSJed Brown 
398e334ad8fSJed Brown     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
399e334ad8fSJed Brown     KMStrainRate(grad_ds, dstrain_rate);
400e334ad8fSJed Brown     NewtonianStress(context, dstrain_rate, dkmstress);
401e334ad8fSJed Brown     KMUnpack(dkmstress, dstress);
402e334ad8fSJed Brown     KMUnpack(kmstress, stress);
403e334ad8fSJed Brown     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
404e334ad8fSJed Brown 
405e334ad8fSJed Brown     StateConservative dF_inviscid[3];
406e334ad8fSJed Brown     FluxInviscid_fwd(context, s, ds, dF_inviscid);
407e334ad8fSJed Brown 
408e334ad8fSJed Brown     // Total flux
409e334ad8fSJed Brown     CeedScalar dFlux[5][3];
4102b89d87eSLeila Ghaffari     FluxTotal(dF_inviscid, dstress, dFe, dFlux);
411e334ad8fSJed Brown 
4122b89d87eSLeila Ghaffari     for (int j=0; j<3; j++)
4132b89d87eSLeila Ghaffari       for (int k=0; k<5; k++)
414e334ad8fSJed Brown         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * dFlux[k][0] +
415e334ad8fSJed Brown                                     dXdx[j][1] * dFlux[k][1] +
416e334ad8fSJed Brown                                     dXdx[j][2] * dFlux[k][2]);
417e334ad8fSJed Brown 
418e334ad8fSJed Brown     const CeedScalar dbody_force[5] = {0, ds.U.density *g[0], ds.U.density *g[1], ds.U.density *g[2], 0};
419e334ad8fSJed Brown     for (int j=0; j<5; j++)
420e334ad8fSJed Brown       v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]);
421e334ad8fSJed Brown 
4222b89d87eSLeila Ghaffari     // -- Stabilization method: none (Galerkin), SU, or SUPG
4232b89d87eSLeila Ghaffari     CeedScalar dstab[5][3], U_dot[5] = {0};
4242b89d87eSLeila Ghaffari     for (CeedInt j=0; j<5; j++) U_dot[j] = context->ijacobian_time_shift * dU[j];
4252b89d87eSLeila Ghaffari     Stabilization(context, s, Tau_d, grad_ds, U_dot, dbody_force, x_i, dstab);
4262b89d87eSLeila Ghaffari 
427e334ad8fSJed Brown     for (int j=0; j<5; j++)
428e334ad8fSJed Brown       for (int k=0; k<3; k++)
429e334ad8fSJed Brown         Grad_v[k][j][i] += wdetJ*(dstab[j][0] * dXdx[k][0] +
430e334ad8fSJed Brown                                   dstab[j][1] * dXdx[k][1] +
431e334ad8fSJed Brown                                   dstab[j][2] * dXdx[k][2]);
432e334ad8fSJed Brown 
433e334ad8fSJed Brown   } // End Quadrature Point Loop
434e334ad8fSJed Brown   return 0;
435e334ad8fSJed Brown }
43665dd5cafSJames Wright 
4372b89d87eSLeila Ghaffari // *****************************************************************************
43865dd5cafSJames Wright // Compute boundary integral (ie. for strongly set inflows)
4392b89d87eSLeila Ghaffari // *****************************************************************************
440*20840d50SJames Wright CEED_QFUNCTION_HELPER int BoundaryIntegral(void *ctx, CeedInt Q,
441*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out,
442*20840d50SJames Wright     StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) {
44365dd5cafSJames Wright 
44465dd5cafSJames Wright   //*INDENT-OFF*
44565dd5cafSJames Wright   const CeedScalar (*q)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[0],
4462c4e60d7SJames Wright                    (*Grad_q)[5][CEED_Q_VLA]  = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
4472c4e60d7SJames Wright                    (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
4482c4e60d7SJames Wright                    (*x)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[3];
44965dd5cafSJames Wright 
450b55ac660SJames Wright   CeedScalar (*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA]) out[0],
451b55ac660SJames Wright              (*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA]) out[1];
45265dd5cafSJames Wright 
45365dd5cafSJames Wright   //*INDENT-ON*
45465dd5cafSJames Wright 
4552c4e60d7SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext) ctx;
4562c4e60d7SJames Wright   const bool is_implicit  = context->is_implicit;
45765dd5cafSJames Wright 
45865dd5cafSJames Wright   CeedPragmaSIMD
45965dd5cafSJames Wright   for(CeedInt i=0; i<Q; i++) {
4602c4e60d7SJames Wright     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
461efe9d856SJames Wright     const CeedScalar qi[5]  = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
462efe9d856SJames Wright     State s = StateFromQi(context, qi, x_i);
46365dd5cafSJames Wright 
46465dd5cafSJames Wright     const CeedScalar wdetJb  = (is_implicit ? -1. : 1.) * q_data_sur[0][i];
4655bce47c7SJames Wright     // ---- Normal vector
46665dd5cafSJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
46765dd5cafSJames Wright                                 q_data_sur[2][i],
46865dd5cafSJames Wright                                 q_data_sur[3][i]
46965dd5cafSJames Wright                                };
47065dd5cafSJames Wright 
4712c4e60d7SJames Wright     const CeedScalar dXdx[2][3] = {
4722c4e60d7SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
4732c4e60d7SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
4742c4e60d7SJames Wright     };
47565dd5cafSJames Wright 
4762c4e60d7SJames Wright     State grad_s[3];
4772c4e60d7SJames Wright     for (CeedInt j=0; j<3; j++) {
478efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi[5];
4792c4e60d7SJames Wright       for (CeedInt k=0; k<5; k++)
480efe9d856SJames Wright         dqi[k] = Grad_q[0][k][i] * dXdx[0][j] +
4812c4e60d7SJames Wright                  Grad_q[1][k][i] * dXdx[1][j];
4822c4e60d7SJames Wright       dx_i[j] = 1.;
483efe9d856SJames Wright       grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
4842c4e60d7SJames Wright     }
48565dd5cafSJames Wright 
4862c4e60d7SJames Wright     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
4872c4e60d7SJames Wright     KMStrainRate(grad_s, strain_rate);
4882c4e60d7SJames Wright     NewtonianStress(context, strain_rate, kmstress);
4892c4e60d7SJames Wright     KMUnpack(kmstress, stress);
4902c4e60d7SJames Wright     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
4912c4e60d7SJames Wright 
4922c4e60d7SJames Wright     StateConservative F_inviscid[3];
4932c4e60d7SJames Wright     FluxInviscid(context, s, F_inviscid);
4942c4e60d7SJames Wright 
4955bce47c7SJames Wright     CeedScalar Flux[5];
4965bce47c7SJames Wright     FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux);
4972c4e60d7SJames Wright 
4985bce47c7SJames Wright     for (CeedInt j=0; j<5; j++) v[j][i] = -wdetJb * Flux[j];
49965dd5cafSJames Wright 
5005bce47c7SJames Wright     for (int j=0; j<5; j++) jac_data_sur[j][i]   = qi[j];
501b55ac660SJames Wright     for (int j=0; j<6; j++) jac_data_sur[5+j][i] = kmstress[j];
50265dd5cafSJames Wright   }
50365dd5cafSJames Wright   return 0;
50465dd5cafSJames Wright }
50565dd5cafSJames Wright 
506*20840d50SJames Wright CEED_QFUNCTION(BoundaryIntegral_Conserv)(void *ctx, CeedInt Q,
507*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out) {
508*20840d50SJames Wright   return BoundaryIntegral(ctx, Q, in, out, StateFromU, StateFromU_fwd);
509*20840d50SJames Wright }
510*20840d50SJames Wright 
511*20840d50SJames Wright CEED_QFUNCTION(BoundaryIntegral_Prim)(void *ctx, CeedInt Q,
512*20840d50SJames Wright                                       const CeedScalar *const *in, CeedScalar *const *out) {
513*20840d50SJames Wright   return BoundaryIntegral(ctx, Q, in, out, StateFromY, StateFromY_fwd);
514*20840d50SJames Wright }
515*20840d50SJames Wright 
5162b89d87eSLeila Ghaffari // *****************************************************************************
517b55ac660SJames Wright // Jacobian for "set nothing" boundary integral
5182b89d87eSLeila Ghaffari // *****************************************************************************
519*20840d50SJames Wright CEED_QFUNCTION_HELPER int BoundaryIntegral_Jacobian(void *ctx, CeedInt Q,
520*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out,
521*20840d50SJames Wright     StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) {
522b55ac660SJames Wright   // *INDENT-OFF*
523b55ac660SJames Wright   // Inputs
524b55ac660SJames Wright   const CeedScalar (*dq)[CEED_Q_VLA]           = (const CeedScalar(*)[CEED_Q_VLA])in[0],
525b55ac660SJames Wright                    (*Grad_dq)[5][CEED_Q_VLA]   = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
526b55ac660SJames Wright                    (*q_data_sur)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[2],
527b55ac660SJames Wright                    (*x)[CEED_Q_VLA]            = (const CeedScalar(*)[CEED_Q_VLA])in[3],
528b55ac660SJames Wright                    (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
529b55ac660SJames Wright   // Outputs
530b55ac660SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
531b55ac660SJames Wright   // *INDENT-ON*
532b55ac660SJames Wright 
533b55ac660SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
534b55ac660SJames Wright   const bool implicit     = context->is_implicit;
535b55ac660SJames Wright 
536b55ac660SJames Wright   CeedPragmaSIMD
537b55ac660SJames Wright   // Quadrature Point Loop
538b55ac660SJames Wright   for (CeedInt i=0; i<Q; i++) {
539b55ac660SJames Wright     const CeedScalar x_i[3]  = {x[0][i], x[1][i], x[2][i]};
540b55ac660SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
541b55ac660SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i],
542b55ac660SJames Wright                                 q_data_sur[2][i],
543b55ac660SJames Wright                                 q_data_sur[3][i]
544b55ac660SJames Wright                                };
545b55ac660SJames Wright     const CeedScalar dXdx[2][3] = {
546b55ac660SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
547b55ac660SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
548b55ac660SJames Wright     };
549b55ac660SJames Wright 
550efe9d856SJames Wright     CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.};
551efe9d856SJames Wright     for (int j=0; j<5; j++) qi[j]       = jac_data_sur[j][i];
552b55ac660SJames Wright     for (int j=0; j<6; j++) kmstress[j] = jac_data_sur[5+j][i];
553efe9d856SJames Wright     for (int j=0; j<5; j++) dqi[j]      = dq[j][i];
55457e55a1cSJames Wright 
555efe9d856SJames Wright     State s  = StateFromQi(context, qi, x_i);
556efe9d856SJames Wright     State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
557b55ac660SJames Wright 
558b55ac660SJames Wright     State grad_ds[3];
559b55ac660SJames Wright     for (CeedInt j=0; j<3; j++) {
560efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi_j[5];
561b55ac660SJames Wright       for (CeedInt k=0; k<5; k++)
562efe9d856SJames Wright         dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] +
563b55ac660SJames Wright                    Grad_dq[1][k][i] * dXdx[1][j];
564b55ac660SJames Wright       dx_i[j] = 1.;
565efe9d856SJames Wright       grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i);
566b55ac660SJames Wright     }
567b55ac660SJames Wright 
568b55ac660SJames Wright     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
569b55ac660SJames Wright     KMStrainRate(grad_ds, dstrain_rate);
570b55ac660SJames Wright     NewtonianStress(context, dstrain_rate, dkmstress);
571b55ac660SJames Wright     KMUnpack(dkmstress, dstress);
572b55ac660SJames Wright     KMUnpack(kmstress, stress);
573b55ac660SJames Wright     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
574b55ac660SJames Wright 
575b55ac660SJames Wright     StateConservative dF_inviscid[3];
576b55ac660SJames Wright     FluxInviscid_fwd(context, s, ds, dF_inviscid);
577b55ac660SJames Wright 
5785bce47c7SJames Wright     CeedScalar dFlux[5];
5795bce47c7SJames Wright     FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux);
580b55ac660SJames Wright 
5815bce47c7SJames Wright     for (int j=0; j<5; j++) v[j][i] = -wdetJb * dFlux[j];
582b55ac660SJames Wright   } // End Quadrature Point Loop
583b55ac660SJames Wright   return 0;
584b55ac660SJames Wright }
585b55ac660SJames Wright 
586*20840d50SJames Wright CEED_QFUNCTION(BoundaryIntegral_Jacobian_Conserv)(void *ctx, CeedInt Q,
587*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out) {
588*20840d50SJames Wright   return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd);
589*20840d50SJames Wright }
590*20840d50SJames Wright 
591*20840d50SJames Wright CEED_QFUNCTION(BoundaryIntegral_Jacobian_Prim)(void *ctx, CeedInt Q,
592*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out) {
593*20840d50SJames Wright   return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd);
594*20840d50SJames Wright }
595*20840d50SJames Wright 
5962b89d87eSLeila Ghaffari // *****************************************************************************
59730e9fa81SJames Wright // Outflow boundary condition, weakly setting a constant pressure
5982b89d87eSLeila Ghaffari // *****************************************************************************
599*20840d50SJames Wright CEED_QFUNCTION_HELPER int PressureOutflow(void *ctx, CeedInt Q,
600*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out,
601*20840d50SJames Wright     StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) {
60230e9fa81SJames Wright   // *INDENT-OFF*
60330e9fa81SJames Wright   // Inputs
60430e9fa81SJames Wright   const CeedScalar (*q)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[0],
605ce9b5c20SJames Wright                    (*Grad_q)[5][CEED_Q_VLA]  = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
606ce9b5c20SJames Wright                    (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
607ce9b5c20SJames Wright                    (*x)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[3];
60830e9fa81SJames Wright   // Outputs
60930e9fa81SJames Wright   CeedScalar (*v)[CEED_Q_VLA]            = (CeedScalar(*)[CEED_Q_VLA])out[0],
61030e9fa81SJames Wright              (*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1];
61130e9fa81SJames Wright   // *INDENT-ON*
61230e9fa81SJames Wright 
61330e9fa81SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
61430e9fa81SJames Wright   const bool       implicit = context->is_implicit;
61530e9fa81SJames Wright   const CeedScalar P0       = context->P0;
61630e9fa81SJames Wright 
61730e9fa81SJames Wright   CeedPragmaSIMD
61830e9fa81SJames Wright   // Quadrature Point Loop
61930e9fa81SJames Wright   for (CeedInt i=0; i<Q; i++) {
62030e9fa81SJames Wright     // Setup
62130e9fa81SJames Wright     // -- Interp in
622ce9b5c20SJames Wright     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
623efe9d856SJames Wright     const CeedScalar qi[5]  = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
624efe9d856SJames Wright     State s = StateFromQi(context, qi, x_i);
625ce9b5c20SJames Wright     s.Y.pressure = P0;
62630e9fa81SJames Wright 
62730e9fa81SJames Wright     // -- Interp-to-Interp q_data
62830e9fa81SJames Wright     // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q).
62930e9fa81SJames Wright     // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q).
63030e9fa81SJames Wright     // We can effect this by swapping the sign on this weight
63130e9fa81SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
63230e9fa81SJames Wright 
6335bce47c7SJames Wright     // ---- Normal vector
634*20840d50SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]};
63530e9fa81SJames Wright 
636ce9b5c20SJames Wright     const CeedScalar dXdx[2][3] = {
637ce9b5c20SJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
638ce9b5c20SJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
639ce9b5c20SJames Wright     };
64030e9fa81SJames Wright 
641ce9b5c20SJames Wright     State grad_s[3];
642ce9b5c20SJames Wright     for (CeedInt j=0; j<3; j++) {
643efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi[5];
644ce9b5c20SJames Wright       for (CeedInt k=0; k<5; k++)
645efe9d856SJames Wright         dqi[k] = Grad_q[0][k][i] * dXdx[0][j] +
646ce9b5c20SJames Wright                  Grad_q[1][k][i] * dXdx[1][j];
647ce9b5c20SJames Wright       dx_i[j] = 1.;
648efe9d856SJames Wright       grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
649ce9b5c20SJames Wright     }
650ce9b5c20SJames Wright 
651ce9b5c20SJames Wright     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
652ce9b5c20SJames Wright     KMStrainRate(grad_s, strain_rate);
653ce9b5c20SJames Wright     NewtonianStress(context, strain_rate, kmstress);
654ce9b5c20SJames Wright     KMUnpack(kmstress, stress);
655ce9b5c20SJames Wright     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
656ce9b5c20SJames Wright 
657ce9b5c20SJames Wright     StateConservative F_inviscid[3];
658ce9b5c20SJames Wright     FluxInviscid(context, s, F_inviscid);
659ce9b5c20SJames Wright 
6605bce47c7SJames Wright     CeedScalar Flux[5];
6615bce47c7SJames Wright     FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux);
66230e9fa81SJames Wright 
6635bce47c7SJames Wright     for (CeedInt j=0; j<5; j++) v[j][i] = -wdetJb * Flux[j];
66430e9fa81SJames Wright 
66530e9fa81SJames Wright     // Save values for Jacobian
6665bce47c7SJames Wright     for (int j=0; j<5; j++) jac_data_sur[j][i]   = qi[j];
6670ec2498eSJames Wright     for (int j=0; j<6; j++) jac_data_sur[5+j][i] = kmstress[j];
66830e9fa81SJames Wright   } // End Quadrature Point Loop
66930e9fa81SJames Wright   return 0;
67030e9fa81SJames Wright }
67130e9fa81SJames Wright 
672*20840d50SJames Wright CEED_QFUNCTION(PressureOutflow_Conserv)(void *ctx, CeedInt Q,
673*20840d50SJames Wright                                         const CeedScalar *const *in, CeedScalar *const *out) {
674*20840d50SJames Wright   return PressureOutflow(ctx, Q, in, out, StateFromU, StateFromU_fwd);
675*20840d50SJames Wright }
676*20840d50SJames Wright 
677*20840d50SJames Wright CEED_QFUNCTION(PressureOutflow_Prim)(void *ctx, CeedInt Q,
678*20840d50SJames Wright                                      const CeedScalar *const *in, CeedScalar *const *out) {
679*20840d50SJames Wright   return PressureOutflow(ctx, Q, in, out, StateFromY, StateFromY_fwd);
680*20840d50SJames Wright }
681*20840d50SJames Wright 
6822b89d87eSLeila Ghaffari // *****************************************************************************
68330e9fa81SJames Wright // Jacobian for weak-pressure outflow boundary condition
6842b89d87eSLeila Ghaffari // *****************************************************************************
685*20840d50SJames Wright CEED_QFUNCTION_HELPER int PressureOutflow_Jacobian(void *ctx, CeedInt Q,
686*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out,
687*20840d50SJames Wright     StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) {
68830e9fa81SJames Wright   // *INDENT-OFF*
68930e9fa81SJames Wright   // Inputs
69030e9fa81SJames Wright   const CeedScalar (*dq)[CEED_Q_VLA]           = (const CeedScalar(*)[CEED_Q_VLA])in[0],
6910ec2498eSJames Wright                    (*Grad_dq)[5][CEED_Q_VLA]   = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
6920ec2498eSJames Wright                    (*q_data_sur)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[2],
6930ec2498eSJames Wright                    (*x)[CEED_Q_VLA]            = (const CeedScalar(*)[CEED_Q_VLA])in[3],
6940ec2498eSJames Wright                    (*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
69530e9fa81SJames Wright   // Outputs
69630e9fa81SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
69730e9fa81SJames Wright   // *INDENT-ON*
69830e9fa81SJames Wright 
69930e9fa81SJames Wright   const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
70030e9fa81SJames Wright   const bool implicit     = context->is_implicit;
70130e9fa81SJames Wright 
70230e9fa81SJames Wright   CeedPragmaSIMD
70330e9fa81SJames Wright   // Quadrature Point Loop
70430e9fa81SJames Wright   for (CeedInt i=0; i<Q; i++) {
7050ec2498eSJames Wright     const CeedScalar x_i[3]  = {x[0][i], x[1][i], x[2][i]};
70630e9fa81SJames Wright     const CeedScalar wdetJb  = (implicit ? -1. : 1.) * q_data_sur[0][i];
707*20840d50SJames Wright     const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]};
7080ec2498eSJames Wright     const CeedScalar dXdx[2][3] = {
7090ec2498eSJames Wright       {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]},
7100ec2498eSJames Wright       {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]}
7110ec2498eSJames Wright     };
7120ec2498eSJames Wright 
713efe9d856SJames Wright     CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.};
714efe9d856SJames Wright     for (int j=0; j<5; j++) qi[j]       = jac_data_sur[j][i];
7150ec2498eSJames Wright     for (int j=0; j<6; j++) kmstress[j] = jac_data_sur[5+j][i];
716efe9d856SJames Wright     for (int j=0; j<5; j++) dqi[j]      = dq[j][i];
71757e55a1cSJames Wright 
718efe9d856SJames Wright     State s  = StateFromQi(context, qi, x_i);
719efe9d856SJames Wright     State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i);
7200ec2498eSJames Wright     s.Y.pressure  = context->P0;
7210ec2498eSJames Wright     ds.Y.pressure = 0.;
7220ec2498eSJames Wright 
7230ec2498eSJames Wright     State grad_ds[3];
7240ec2498eSJames Wright     for (CeedInt j=0; j<3; j++) {
725efe9d856SJames Wright       CeedScalar dx_i[3] = {0}, dqi_j[5];
7260ec2498eSJames Wright       for (CeedInt k=0; k<5; k++)
727efe9d856SJames Wright         dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] +
7280ec2498eSJames Wright                    Grad_dq[1][k][i] * dXdx[1][j];
7290ec2498eSJames Wright       dx_i[j] = 1.;
730efe9d856SJames Wright       grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i);
7310ec2498eSJames Wright     }
7320ec2498eSJames Wright 
7330ec2498eSJames Wright     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
7340ec2498eSJames Wright     KMStrainRate(grad_ds, dstrain_rate);
7350ec2498eSJames Wright     NewtonianStress(context, dstrain_rate, dkmstress);
7360ec2498eSJames Wright     KMUnpack(dkmstress, dstress);
7370ec2498eSJames Wright     KMUnpack(kmstress, stress);
7380ec2498eSJames Wright     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
73930e9fa81SJames Wright 
740b5d317f8SJames Wright     StateConservative dF_inviscid[3];
741b5d317f8SJames Wright     FluxInviscid_fwd(context, s, ds, dF_inviscid);
74230e9fa81SJames Wright 
7435bce47c7SJames Wright     CeedScalar dFlux[5];
7445bce47c7SJames Wright     FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux);
745b5d317f8SJames Wright 
7465bce47c7SJames Wright     for (int j=0; j<5; j++) v[j][i] = -wdetJb * dFlux[j];
74730e9fa81SJames Wright   } // End Quadrature Point Loop
74830e9fa81SJames Wright   return 0;
74930e9fa81SJames Wright }
75030e9fa81SJames Wright 
751*20840d50SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Conserv)(void *ctx, CeedInt Q,
752*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out) {
753*20840d50SJames Wright   return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd);
754*20840d50SJames Wright }
755*20840d50SJames Wright 
756*20840d50SJames Wright CEED_QFUNCTION(PressureOutflow_Jacobian_Prim)(void *ctx, CeedInt Q,
757*20840d50SJames Wright     const CeedScalar *const *in, CeedScalar *const *out) {
758*20840d50SJames Wright   return PressureOutflow_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd);
759*20840d50SJames Wright }
760*20840d50SJames Wright 
76188b783a1SJames Wright // *****************************************************************************
762dc805cc4SLeila Ghaffari // This QFunction implements the Navier-Stokes equations (mentioned above) in
763dc805cc4SLeila Ghaffari //   primitive variables and with implicit time stepping method
764dc805cc4SLeila Ghaffari //
765dc805cc4SLeila Ghaffari // *****************************************************************************
766dc805cc4SLeila Ghaffari CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q,
767dc805cc4SLeila Ghaffari     const CeedScalar *const *in, CeedScalar *const *out) {
768dc805cc4SLeila Ghaffari   // *INDENT-OFF*
769dc805cc4SLeila Ghaffari   // Inputs
770dc805cc4SLeila Ghaffari   const CeedScalar (*q)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[0],
771dc805cc4SLeila Ghaffari                    (*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
772dc805cc4SLeila Ghaffari                    (*q_dot)[CEED_Q_VLA]     = (const CeedScalar(*)[CEED_Q_VLA])in[2],
773dc805cc4SLeila Ghaffari                    (*q_data)[CEED_Q_VLA]    = (const CeedScalar(*)[CEED_Q_VLA])in[3],
774dc805cc4SLeila Ghaffari                    (*x)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[4];
775dc805cc4SLeila Ghaffari   // Outputs
776dc805cc4SLeila Ghaffari   CeedScalar (*v)[CEED_Q_VLA]         = (CeedScalar(*)[CEED_Q_VLA])out[0],
777dc805cc4SLeila Ghaffari              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1],
778dc805cc4SLeila Ghaffari              (*jac_data)[CEED_Q_VLA]  = (CeedScalar(*)[CEED_Q_VLA])out[2];
779dc805cc4SLeila Ghaffari   // *INDENT-ON*
780dc805cc4SLeila Ghaffari   // Context
781dc805cc4SLeila Ghaffari   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
782dc805cc4SLeila Ghaffari   const CeedScalar *g = context->g;
783dc805cc4SLeila Ghaffari   const CeedScalar dt = context->dt;
784dc805cc4SLeila Ghaffari 
785dc805cc4SLeila Ghaffari   CeedPragmaSIMD
786dc805cc4SLeila Ghaffari   // Quadrature Point Loop
787dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
788dc805cc4SLeila Ghaffari     CeedScalar Y[5];
789dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++) Y[j] = q[j][i];
790dc805cc4SLeila Ghaffari     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
791dc805cc4SLeila Ghaffari     State s = StateFromY(context, Y, x_i);
792dc805cc4SLeila Ghaffari 
793dc805cc4SLeila Ghaffari     // -- Interp-to-Interp q_data
794dc805cc4SLeila Ghaffari     const CeedScalar wdetJ      =   q_data[0][i];
795dc805cc4SLeila Ghaffari     // -- Interp-to-Grad q_data
796dc805cc4SLeila Ghaffari     // ---- Inverse of change of coordinate matrix: X_i,j
797dc805cc4SLeila Ghaffari     // *INDENT-OFF*
79823d6ba15SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i], q_data[2][i], q_data[3][i]},
79923d6ba15SJames Wright                                    {q_data[4][i], q_data[5][i], q_data[6][i]},
80023d6ba15SJames Wright                                    {q_data[7][i], q_data[8][i], q_data[9][i]}
801dc805cc4SLeila Ghaffari                                   };
802dc805cc4SLeila Ghaffari     // *INDENT-ON*
803dc805cc4SLeila Ghaffari     State grad_s[3];
804dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) {
805dc805cc4SLeila Ghaffari       CeedScalar dx_i[3] = {0}, dY[5];
806dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<5; k++)
807dc805cc4SLeila Ghaffari         dY[k] = Grad_q[0][k][i] * dXdx[0][j] +
808dc805cc4SLeila Ghaffari                 Grad_q[1][k][i] * dXdx[1][j] +
809dc805cc4SLeila Ghaffari                 Grad_q[2][k][i] * dXdx[2][j];
810dc805cc4SLeila Ghaffari       dx_i[j] = 1.;
811dc805cc4SLeila Ghaffari       grad_s[j] = StateFromY_fwd(context, s, dY, x_i, dx_i);
812dc805cc4SLeila Ghaffari     }
813dc805cc4SLeila Ghaffari 
814dc805cc4SLeila Ghaffari     CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3];
815dc805cc4SLeila Ghaffari     KMStrainRate(grad_s, strain_rate);
816dc805cc4SLeila Ghaffari     NewtonianStress(context, strain_rate, kmstress);
817dc805cc4SLeila Ghaffari     KMUnpack(kmstress, stress);
818dc805cc4SLeila Ghaffari     ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe);
819dc805cc4SLeila Ghaffari 
820dc805cc4SLeila Ghaffari     StateConservative F_inviscid[3];
821dc805cc4SLeila Ghaffari     FluxInviscid(context, s, F_inviscid);
822dc805cc4SLeila Ghaffari 
823dc805cc4SLeila Ghaffari     // Total flux
824dc805cc4SLeila Ghaffari     CeedScalar Flux[5][3];
8252b89d87eSLeila Ghaffari     FluxTotal(F_inviscid, stress, Fe, Flux);
826dc805cc4SLeila Ghaffari 
8272b89d87eSLeila Ghaffari     for (CeedInt j=0; j<3; j++)
8282b89d87eSLeila Ghaffari       for (CeedInt k=0; k<5; k++)
829dc805cc4SLeila Ghaffari         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * Flux[k][0] +
830dc805cc4SLeila Ghaffari                                     dXdx[j][1] * Flux[k][1] +
831dc805cc4SLeila Ghaffari                                     dXdx[j][2] * Flux[k][2]);
832dc805cc4SLeila Ghaffari 
833dc805cc4SLeila Ghaffari     const CeedScalar body_force[5] = {0, s.U.density *g[0], s.U.density *g[1], s.U.density *g[2], 0};
834dc805cc4SLeila Ghaffari 
835dc805cc4SLeila Ghaffari     CeedScalar Y_dot[5], dx0[3] = {0};
836dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) Y_dot[j] = q_dot[j][i];
837dc805cc4SLeila Ghaffari     State s_dot = StateFromY_fwd(context, s, Y_dot, x_i, dx0);
838dc805cc4SLeila Ghaffari 
839dc805cc4SLeila Ghaffari     CeedScalar U_dot[5] = {0.};
8402b89d87eSLeila Ghaffari     UnpackState_U(s_dot.U, U_dot);
841dc805cc4SLeila Ghaffari 
842dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
843dc805cc4SLeila Ghaffari       v[j][i] = wdetJ * (U_dot[j] - body_force[j]);
844dc805cc4SLeila Ghaffari 
8452b89d87eSLeila Ghaffari     // -- Stabilization method: none (Galerkin), SU, or SUPG
8462b89d87eSLeila Ghaffari     CeedScalar Tau_d[3], stab[5][3];
8472b89d87eSLeila Ghaffari     Tau_diagPrim(context, s, dXdx, dt, Tau_d);
8482b89d87eSLeila Ghaffari     Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab);
849dc805cc4SLeila Ghaffari 
850dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++)
851dc805cc4SLeila Ghaffari       for (CeedInt k=0; k<3; k++)
852dc805cc4SLeila Ghaffari         Grad_v[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
853dc805cc4SLeila Ghaffari                                   stab[j][1] * dXdx[k][1] +
854dc805cc4SLeila Ghaffari                                   stab[j][2] * dXdx[k][2]);
855dc805cc4SLeila Ghaffari 
856dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<5; j++) jac_data[j][i]     = Y[j];
857dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<6; j++) jac_data[5+j][i]   = kmstress[j];
858dc805cc4SLeila Ghaffari     for (CeedInt j=0; j<3; j++) jac_data[5+6+j][i] = Tau_d[j];
859dc805cc4SLeila Ghaffari 
860dc805cc4SLeila Ghaffari   } // End Quadrature Point Loop
861dc805cc4SLeila Ghaffari 
862dc805cc4SLeila Ghaffari   // Return
863dc805cc4SLeila Ghaffari   return 0;
864dc805cc4SLeila Ghaffari }
865dc805cc4SLeila Ghaffari 
866dc805cc4SLeila Ghaffari // *****************************************************************************
867dc805cc4SLeila Ghaffari // This QFunction implements the jacobean of the Navier-Stokes equations
868dc805cc4SLeila Ghaffari //   in primitive variables for implicit time stepping method.
869dc805cc4SLeila Ghaffari //
870dc805cc4SLeila Ghaffari // *****************************************************************************
871dc805cc4SLeila Ghaffari CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q,
872dc805cc4SLeila Ghaffari     const CeedScalar *const *in, CeedScalar *const *out) {
873dc805cc4SLeila Ghaffari   // *INDENT-OFF*
874dc805cc4SLeila Ghaffari   // Inputs
875dc805cc4SLeila Ghaffari   const CeedScalar (*dq)[CEED_Q_VLA]         = (const CeedScalar(*)[CEED_Q_VLA])in[0],
876dc805cc4SLeila Ghaffari                    (*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
877dc805cc4SLeila Ghaffari                    (*q_data)[CEED_Q_VLA]     = (const CeedScalar(*)[CEED_Q_VLA])in[2],
878dc805cc4SLeila Ghaffari                    (*x)[CEED_Q_VLA]          = (const CeedScalar(*)[CEED_Q_VLA])in[3],
879dc805cc4SLeila Ghaffari                    (*jac_data)[CEED_Q_VLA]   = (const CeedScalar(*)[CEED_Q_VLA])in[4];
880dc805cc4SLeila Ghaffari   // Outputs
881dc805cc4SLeila Ghaffari   CeedScalar (*v)[CEED_Q_VLA]         = (CeedScalar(*)[CEED_Q_VLA])out[0],
882dc805cc4SLeila Ghaffari              (*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
883dc805cc4SLeila Ghaffari   // *INDENT-ON*
884dc805cc4SLeila Ghaffari   // Context
885dc805cc4SLeila Ghaffari   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
886dc805cc4SLeila Ghaffari   const CeedScalar *g = context->g;
887dc805cc4SLeila Ghaffari 
888dc805cc4SLeila Ghaffari   CeedPragmaSIMD
889dc805cc4SLeila Ghaffari   // Quadrature Point Loop
890dc805cc4SLeila Ghaffari   for (CeedInt i=0; i<Q; i++) {
891dc805cc4SLeila Ghaffari     // -- Interp-to-Interp q_data
892dc805cc4SLeila Ghaffari     const CeedScalar wdetJ      =   q_data[0][i];
893dc805cc4SLeila Ghaffari     // -- Interp-to-Grad q_data
894dc805cc4SLeila Ghaffari     // ---- Inverse of change of coordinate matrix: X_i,j
895dc805cc4SLeila Ghaffari     // *INDENT-OFF*
89623d6ba15SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i], q_data[2][i], q_data[3][i]},
89723d6ba15SJames Wright                                    {q_data[4][i], q_data[5][i], q_data[6][i]},
89823d6ba15SJames Wright                                    {q_data[7][i], q_data[8][i], q_data[9][i]}
899dc805cc4SLeila Ghaffari                                   };
900dc805cc4SLeila Ghaffari     // *INDENT-ON*
901dc805cc4SLeila Ghaffari 
902dc805cc4SLeila Ghaffari     CeedScalar Y[5], kmstress[6], Tau_d[3] __attribute((unused));
903dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) Y[j]        = jac_data[j][i];
904dc805cc4SLeila Ghaffari     for (int j=0; j<6; j++) kmstress[j] = jac_data[5+j][i];
905dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) Tau_d[j]    = jac_data[5+6+j][i];
906dc805cc4SLeila Ghaffari     const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
907dc805cc4SLeila Ghaffari     State s = StateFromY(context, Y, x_i);
908dc805cc4SLeila Ghaffari 
909dc805cc4SLeila Ghaffari     CeedScalar dY[5], dx0[3] = {0};
910dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++) dY[j] = dq[j][i];
911dc805cc4SLeila Ghaffari     State ds = StateFromY_fwd(context, s, dY, x_i, dx0);
912dc805cc4SLeila Ghaffari 
913dc805cc4SLeila Ghaffari     State grad_ds[3];
914dc805cc4SLeila Ghaffari     for (int j=0; j<3; j++) {
915dc805cc4SLeila Ghaffari       CeedScalar dYj[5];
916dc805cc4SLeila Ghaffari       for (int k=0; k<5; k++)
917dc805cc4SLeila Ghaffari         dYj[k] = Grad_dq[0][k][i] * dXdx[0][j] +
918dc805cc4SLeila Ghaffari                  Grad_dq[1][k][i] * dXdx[1][j] +
919dc805cc4SLeila Ghaffari                  Grad_dq[2][k][i] * dXdx[2][j];
920dc805cc4SLeila Ghaffari       grad_ds[j] = StateFromY_fwd(context, s, dYj, x_i, dx0);
921dc805cc4SLeila Ghaffari     }
922dc805cc4SLeila Ghaffari 
923dc805cc4SLeila Ghaffari     CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3];
924dc805cc4SLeila Ghaffari     KMStrainRate(grad_ds, dstrain_rate);
925dc805cc4SLeila Ghaffari     NewtonianStress(context, dstrain_rate, dkmstress);
926dc805cc4SLeila Ghaffari     KMUnpack(dkmstress, dstress);
927dc805cc4SLeila Ghaffari     KMUnpack(kmstress, stress);
928dc805cc4SLeila Ghaffari     ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe);
929dc805cc4SLeila Ghaffari 
930dc805cc4SLeila Ghaffari     StateConservative dF_inviscid[3];
931dc805cc4SLeila Ghaffari     FluxInviscid_fwd(context, s, ds, dF_inviscid);
932dc805cc4SLeila Ghaffari 
933dc805cc4SLeila Ghaffari     // Total flux
934dc805cc4SLeila Ghaffari     CeedScalar dFlux[5][3];
9352b89d87eSLeila Ghaffari     FluxTotal(dF_inviscid, dstress, dFe, dFlux);
936dc805cc4SLeila Ghaffari 
9372b89d87eSLeila Ghaffari     for (int j=0; j<3; j++)
9382b89d87eSLeila Ghaffari       for (int k=0; k<5; k++)
939dc805cc4SLeila Ghaffari         Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * dFlux[k][0] +
940dc805cc4SLeila Ghaffari                                     dXdx[j][1] * dFlux[k][1] +
941dc805cc4SLeila Ghaffari                                     dXdx[j][2] * dFlux[k][2]);
942dc805cc4SLeila Ghaffari 
9432b89d87eSLeila Ghaffari     const CeedScalar dbody_force[5] = {0, ds.U.density *g[0], ds.U.density *g[1], ds.U.density *g[2], 0};
944dc805cc4SLeila Ghaffari     CeedScalar dU[5] = {0.};
9452b89d87eSLeila Ghaffari     UnpackState_U(ds.U, dU);
946dc805cc4SLeila Ghaffari 
947dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++)
948dc805cc4SLeila Ghaffari       v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]);
949dc805cc4SLeila Ghaffari 
9502b89d87eSLeila Ghaffari     // -- Stabilization method: none (Galerkin), SU, or SUPG
9512b89d87eSLeila Ghaffari     CeedScalar dstab[5][3], U_dot[5] = {0};
9522b89d87eSLeila Ghaffari     for (CeedInt j=0; j<5; j++) U_dot[j] = context->ijacobian_time_shift * dU[j];
9532b89d87eSLeila Ghaffari     Stabilization(context, s, Tau_d, grad_ds, U_dot, dbody_force, x_i, dstab);
954dc805cc4SLeila Ghaffari 
955dc805cc4SLeila Ghaffari     for (int j=0; j<5; j++)
956dc805cc4SLeila Ghaffari       for (int k=0; k<3; k++)
957dc805cc4SLeila Ghaffari         Grad_v[k][j][i] += wdetJ*(dstab[j][0] * dXdx[k][0] +
958dc805cc4SLeila Ghaffari                                   dstab[j][1] * dXdx[k][1] +
959dc805cc4SLeila Ghaffari                                   dstab[j][2] * dXdx[k][2]);
960dc805cc4SLeila Ghaffari 
961dc805cc4SLeila Ghaffari   } // End Quadrature Point Loop
962dc805cc4SLeila Ghaffari   return 0;
963dc805cc4SLeila Ghaffari }
964dc805cc4SLeila Ghaffari // *****************************************************************************
965dc805cc4SLeila Ghaffari 
96688b783a1SJames Wright #endif // newtonian_h
967