xref: /libCEED/examples/fluids/qfunctions/newtonian.h (revision 88b783a108a0e7f73f6a4b1c66ee7b6d1a268995)
1*88b783a1SJames Wright // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2*88b783a1SJames Wright // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3*88b783a1SJames Wright // reserved. See files LICENSE and NOTICE for details.
4*88b783a1SJames Wright //
5*88b783a1SJames Wright // This file is part of CEED, a collection of benchmarks, miniapps, software
6*88b783a1SJames Wright // libraries and APIs for efficient high-order finite element and spectral
7*88b783a1SJames Wright // element discretizations for exascale applications. For more information and
8*88b783a1SJames Wright // source code availability see http://github.com/ceed.
9*88b783a1SJames Wright //
10*88b783a1SJames Wright // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11*88b783a1SJames Wright // a collaborative effort of two U.S. Department of Energy organizations (Office
12*88b783a1SJames Wright // of Science and the National Nuclear Security Administration) responsible for
13*88b783a1SJames Wright // the planning and preparation of a capable exascale ecosystem, including
14*88b783a1SJames Wright // software, applications, hardware, advanced system engineering and early
15*88b783a1SJames Wright // testbed platforms, in support of the nation's exascale computing imperative.
16*88b783a1SJames Wright 
17*88b783a1SJames Wright /// @file
18*88b783a1SJames Wright /// Operator for Navier-Stokes example using PETSc
19*88b783a1SJames Wright 
20*88b783a1SJames Wright 
21*88b783a1SJames Wright #ifndef newtonian_h
22*88b783a1SJames Wright #define newtonian_h
23*88b783a1SJames Wright 
24*88b783a1SJames Wright #include <math.h>
25*88b783a1SJames Wright #include <ceed.h>
26*88b783a1SJames Wright 
27*88b783a1SJames Wright #ifndef M_PI
28*88b783a1SJames Wright #define M_PI    3.14159265358979323846
29*88b783a1SJames Wright #endif
30*88b783a1SJames Wright 
31*88b783a1SJames Wright #ifndef setup_context_struct
32*88b783a1SJames Wright #define setup_context_struct
33*88b783a1SJames Wright typedef struct SetupContext_ *SetupContext;
34*88b783a1SJames Wright struct SetupContext_ {
35*88b783a1SJames Wright   CeedScalar theta0;
36*88b783a1SJames Wright   CeedScalar thetaC;
37*88b783a1SJames Wright   CeedScalar P0;
38*88b783a1SJames Wright   CeedScalar N;
39*88b783a1SJames Wright   CeedScalar cv;
40*88b783a1SJames Wright   CeedScalar cp;
41*88b783a1SJames Wright   CeedScalar g;
42*88b783a1SJames Wright   CeedScalar rc;
43*88b783a1SJames Wright   CeedScalar lx;
44*88b783a1SJames Wright   CeedScalar ly;
45*88b783a1SJames Wright   CeedScalar lz;
46*88b783a1SJames Wright   CeedScalar center[3];
47*88b783a1SJames Wright   CeedScalar dc_axis[3];
48*88b783a1SJames Wright   CeedScalar wind[3];
49*88b783a1SJames Wright   CeedScalar time;
50*88b783a1SJames Wright   int wind_type;              // See WindType: 0=ROTATION, 1=TRANSLATION
51*88b783a1SJames Wright   int bubble_type;            // See BubbleType: 0=SPHERE, 1=CYLINDER
52*88b783a1SJames Wright   int bubble_continuity_type; // See BubbleContinuityType: 0=SMOOTH, 1=BACK_SHARP 2=THICK
53*88b783a1SJames Wright };
54*88b783a1SJames Wright #endif
55*88b783a1SJames Wright 
56*88b783a1SJames Wright #ifndef newtonian_context_struct
57*88b783a1SJames Wright #define newtonian_context_struct
58*88b783a1SJames Wright typedef enum {
59*88b783a1SJames Wright   STAB_NONE = 0,
60*88b783a1SJames Wright   STAB_SU   = 1, // Streamline Upwind
61*88b783a1SJames Wright   STAB_SUPG = 2, // Streamline Upwind Petrov-Galerkin
62*88b783a1SJames Wright } StabilizationType;
63*88b783a1SJames Wright 
64*88b783a1SJames Wright typedef struct NewtonianIdealGasContext_ *NewtonianIdealGasContext;
65*88b783a1SJames Wright struct NewtonianIdealGasContext_ {
66*88b783a1SJames Wright   CeedScalar lambda;
67*88b783a1SJames Wright   CeedScalar mu;
68*88b783a1SJames Wright   CeedScalar k;
69*88b783a1SJames Wright   CeedScalar cv;
70*88b783a1SJames Wright   CeedScalar cp;
71*88b783a1SJames Wright   CeedScalar g;
72*88b783a1SJames Wright   CeedScalar c_tau;
73*88b783a1SJames Wright   StabilizationType stabilization;
74*88b783a1SJames Wright };
75*88b783a1SJames Wright #endif
76*88b783a1SJames Wright 
77*88b783a1SJames Wright // *****************************************************************************
78*88b783a1SJames Wright // Helper function for computing flux Jacobian
79*88b783a1SJames Wright // *****************************************************************************
80*88b783a1SJames Wright CEED_QFUNCTION_HELPER void computeFluxJacobian_NS(CeedScalar dF[3][5][5],
81*88b783a1SJames Wright     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
82*88b783a1SJames Wright     const CeedScalar gamma, const CeedScalar g, CeedScalar z) {
83*88b783a1SJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
84*88b783a1SJames Wright   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
85*88b783a1SJames Wright     for (CeedInt j=0; j<3; j++) { // Rows of each Jacobian matrix
86*88b783a1SJames Wright       dF[i][j+1][0] = ((i==j) ? ((gamma-1.)*(u_sq/2. - g*z)) : 0.) - u[i]*u[j];
87*88b783a1SJames Wright       for (CeedInt k=0; k<3; k++) { // Columns of each Jacobian matrix
88*88b783a1SJames Wright         dF[i][0][k+1]   = ((i==k) ? 1. : 0.);
89*88b783a1SJames Wright         dF[i][j+1][k+1] = ((j==k) ? u[i] : 0.) +
90*88b783a1SJames Wright                           ((i==k) ? u[j] : 0.) -
91*88b783a1SJames Wright                           ((i==j) ? u[k] : 0.) * (gamma-1.);
92*88b783a1SJames Wright         dF[i][4][k+1]   = ((i==k) ? (E*gamma/rho - (gamma-1.)*u_sq/2.) : 0.) -
93*88b783a1SJames Wright                           (gamma-1.)*u[i]*u[k];
94*88b783a1SJames Wright       }
95*88b783a1SJames Wright       dF[i][j+1][4] = ((i==j) ? (gamma-1.) : 0.);
96*88b783a1SJames Wright     }
97*88b783a1SJames Wright     dF[i][4][0] = u[i] * ((gamma-1.)*u_sq - E*gamma/rho);
98*88b783a1SJames Wright     dF[i][4][4] = u[i] * gamma;
99*88b783a1SJames Wright   }
100*88b783a1SJames Wright }
101*88b783a1SJames Wright 
102*88b783a1SJames Wright // *****************************************************************************
103*88b783a1SJames Wright // Helper function for computing Tau elements (stabilization constant)
104*88b783a1SJames Wright //   Model from:
105*88b783a1SJames Wright //     Stabilized Methods for Compressible Flows, Hughes et al 2010
106*88b783a1SJames Wright //
107*88b783a1SJames Wright //   Spatial criterion #2 - Tau is a 3x3 diagonal matrix
108*88b783a1SJames Wright //   Tau[i] = c_tau h[i] Xi(Pe) / rho(A[i]) (no sum)
109*88b783a1SJames Wright //
110*88b783a1SJames Wright // Where
111*88b783a1SJames Wright //   c_tau     = stabilization constant (0.5 is reported as "optimal")
112*88b783a1SJames Wright //   h[i]      = 2 length(dxdX[i])
113*88b783a1SJames Wright //   Pe        = Peclet number ( Pe = sqrt(u u) / dot(dXdx,u) diffusivity )
114*88b783a1SJames Wright //   Xi(Pe)    = coth Pe - 1. / Pe (1. at large local Peclet number )
115*88b783a1SJames Wright //   rho(A[i]) = spectral radius of the convective flux Jacobian i,
116*88b783a1SJames Wright //               wave speed in direction i
117*88b783a1SJames Wright // *****************************************************************************
118*88b783a1SJames Wright CEED_QFUNCTION_HELPER void Tau_spatial(CeedScalar Tau_x[3],
119*88b783a1SJames Wright                                        const CeedScalar dXdx[3][3], const CeedScalar u[3],
120*88b783a1SJames Wright                                        const CeedScalar sound_speed, const CeedScalar c_tau) {
121*88b783a1SJames Wright   for (int i=0; i<3; i++) {
122*88b783a1SJames Wright     // length of element in direction i
123*88b783a1SJames Wright     CeedScalar h = 2 / sqrt(dXdx[0][i]*dXdx[0][i] + dXdx[1][i]*dXdx[1][i] +
124*88b783a1SJames Wright                             dXdx[2][i]*dXdx[2][i]);
125*88b783a1SJames Wright     // fastest wave in direction i
126*88b783a1SJames Wright     CeedScalar fastest_wave = fabs(u[i]) + sound_speed;
127*88b783a1SJames Wright     Tau_x[i] = c_tau * h / fastest_wave;
128*88b783a1SJames Wright   }
129*88b783a1SJames Wright }
130*88b783a1SJames Wright 
131*88b783a1SJames Wright // *****************************************************************************
132*88b783a1SJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems
133*88b783a1SJames Wright // *****************************************************************************
134*88b783a1SJames Wright CEED_QFUNCTION(ICsNewtonianIG)(void *ctx, CeedInt Q,
135*88b783a1SJames Wright                                const CeedScalar *const *in, CeedScalar *const *out) {
136*88b783a1SJames Wright   // Inputs
137*88b783a1SJames Wright   const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
138*88b783a1SJames Wright 
139*88b783a1SJames Wright   // Outputs
140*88b783a1SJames Wright   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
141*88b783a1SJames Wright 
142*88b783a1SJames Wright   // Quadrature Point Loop
143*88b783a1SJames Wright   CeedPragmaSIMD
144*88b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
145*88b783a1SJames Wright     CeedScalar q[5] = {0.};
146*88b783a1SJames Wright 
147*88b783a1SJames Wright     // Context
148*88b783a1SJames Wright     const SetupContext context = (SetupContext)ctx;
149*88b783a1SJames Wright     const CeedScalar theta0    = context->theta0;
150*88b783a1SJames Wright     const CeedScalar P0        = context->P0;
151*88b783a1SJames Wright     const CeedScalar N         = context->N;
152*88b783a1SJames Wright     const CeedScalar cv        = context->cv;
153*88b783a1SJames Wright     const CeedScalar cp        = context->cp;
154*88b783a1SJames Wright     const CeedScalar g         = context->g;
155*88b783a1SJames Wright     const CeedScalar Rd        = cp - cv;
156*88b783a1SJames Wright 
157*88b783a1SJames Wright     // Setup
158*88b783a1SJames Wright     // -- Coordinates
159*88b783a1SJames Wright     const CeedScalar z = X[2][i];
160*88b783a1SJames Wright 
161*88b783a1SJames Wright     // -- Exner pressure, hydrostatic balance
162*88b783a1SJames Wright     const CeedScalar Pi = 1. + g*g*(exp(-N*N*z/g) - 1.) / (cp*theta0*N*N);
163*88b783a1SJames Wright 
164*88b783a1SJames Wright     // -- Density
165*88b783a1SJames Wright     const CeedScalar rho = P0 * pow(Pi, cv/Rd) / (Rd*theta0);
166*88b783a1SJames Wright 
167*88b783a1SJames Wright     // Initial Conditions
168*88b783a1SJames Wright     q[0] = rho;
169*88b783a1SJames Wright     q[1] = 0.0;
170*88b783a1SJames Wright     q[2] = 0.0;
171*88b783a1SJames Wright     q[3] = 0.0;
172*88b783a1SJames Wright     q[4] = rho * (cv*theta0*Pi + g*z);
173*88b783a1SJames Wright 
174*88b783a1SJames Wright     for (CeedInt j=0; j<5; j++)
175*88b783a1SJames Wright       q0[j][i] = q[j];
176*88b783a1SJames Wright   } // End of Quadrature Point Loop
177*88b783a1SJames Wright   return 0;
178*88b783a1SJames Wright }
179*88b783a1SJames Wright 
180*88b783a1SJames Wright // *****************************************************************************
181*88b783a1SJames Wright // This QFunction implements the following formulation of Navier-Stokes with
182*88b783a1SJames Wright //   explicit time stepping method
183*88b783a1SJames Wright //
184*88b783a1SJames Wright // This is 3D compressible Navier-Stokes in conservation form with state
185*88b783a1SJames Wright //   variables of density, momentum density, and total energy density.
186*88b783a1SJames Wright //
187*88b783a1SJames Wright // State Variables: q = ( rho, U1, U2, U3, E )
188*88b783a1SJames Wright //   rho - Mass Density
189*88b783a1SJames Wright //   Ui  - Momentum Density,      Ui = rho ui
190*88b783a1SJames Wright //   E   - Total Energy Density,  E  = rho (cv T + (u u)/2 + g z)
191*88b783a1SJames Wright //
192*88b783a1SJames Wright // Navier-Stokes Equations:
193*88b783a1SJames Wright //   drho/dt + div( U )                               = 0
194*88b783a1SJames Wright //   dU/dt   + div( rho (u x u) + P I3 ) + rho g khat = div( Fu )
195*88b783a1SJames Wright //   dE/dt   + div( (E + P) u )                       = div( Fe )
196*88b783a1SJames Wright //
197*88b783a1SJames Wright // Viscous Stress:
198*88b783a1SJames Wright //   Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3)
199*88b783a1SJames Wright //
200*88b783a1SJames Wright // Thermal Stress:
201*88b783a1SJames Wright //   Fe = u Fu + k grad( T )
202*88b783a1SJames Wright //
203*88b783a1SJames Wright // Equation of State:
204*88b783a1SJames Wright //   P = (gamma - 1) (E - rho (u u) / 2 - rho g z)
205*88b783a1SJames Wright //
206*88b783a1SJames Wright // Stabilization:
207*88b783a1SJames Wright //   Tau = diag(TauC, TauM, TauM, TauM, TauE)
208*88b783a1SJames Wright //     f1 = rho  sqrt(ui uj gij)
209*88b783a1SJames Wright //     gij = dXi/dX * dXi/dX
210*88b783a1SJames Wright //     TauC = Cc f1 / (8 gii)
211*88b783a1SJames Wright //     TauM = min( 1 , 1 / f1 )
212*88b783a1SJames Wright //     TauE = TauM / (Ce cv)
213*88b783a1SJames Wright //
214*88b783a1SJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
215*88b783a1SJames Wright //
216*88b783a1SJames Wright // Constants:
217*88b783a1SJames Wright //   lambda = - 2 / 3,  From Stokes hypothesis
218*88b783a1SJames Wright //   mu              ,  Dynamic viscosity
219*88b783a1SJames Wright //   k               ,  Thermal conductivity
220*88b783a1SJames Wright //   cv              ,  Specific heat, constant volume
221*88b783a1SJames Wright //   cp              ,  Specific heat, constant pressure
222*88b783a1SJames Wright //   g               ,  Gravity
223*88b783a1SJames Wright //   gamma  = cp / cv,  Specific heat ratio
224*88b783a1SJames Wright //
225*88b783a1SJames Wright // We require the product of the inverse of the Jacobian (dXdx_j,k) and
226*88b783a1SJames Wright // its transpose (dXdx_k,j) to properly compute integrals of the form:
227*88b783a1SJames Wright // int( gradv gradu )
228*88b783a1SJames Wright //
229*88b783a1SJames Wright // *****************************************************************************
230*88b783a1SJames Wright CEED_QFUNCTION(Newtonian)(void *ctx, CeedInt Q,
231*88b783a1SJames Wright                           const CeedScalar *const *in, CeedScalar *const *out) {
232*88b783a1SJames Wright   // *INDENT-OFF*
233*88b783a1SJames Wright   // Inputs
234*88b783a1SJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
235*88b783a1SJames Wright                    (*dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
236*88b783a1SJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
237*88b783a1SJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3];
238*88b783a1SJames Wright   // Outputs
239*88b783a1SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
240*88b783a1SJames Wright              (*dv)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
241*88b783a1SJames Wright   // *INDENT-ON*
242*88b783a1SJames Wright 
243*88b783a1SJames Wright   // Context
244*88b783a1SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
245*88b783a1SJames Wright   const CeedScalar lambda = context->lambda;
246*88b783a1SJames Wright   const CeedScalar mu     = context->mu;
247*88b783a1SJames Wright   const CeedScalar k      = context->k;
248*88b783a1SJames Wright   const CeedScalar cv     = context->cv;
249*88b783a1SJames Wright   const CeedScalar cp     = context->cp;
250*88b783a1SJames Wright   const CeedScalar g      = context->g;
251*88b783a1SJames Wright   const CeedScalar c_tau  = context->c_tau;
252*88b783a1SJames Wright   const CeedScalar gamma  = cp / cv;
253*88b783a1SJames Wright 
254*88b783a1SJames Wright   CeedPragmaSIMD
255*88b783a1SJames Wright   // Quadrature Point Loop
256*88b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
257*88b783a1SJames Wright     // *INDENT-OFF*
258*88b783a1SJames Wright     // Setup
259*88b783a1SJames Wright     // -- Interp in
260*88b783a1SJames Wright     const CeedScalar rho        =   q[0][i];
261*88b783a1SJames Wright     const CeedScalar u[3]       =  {q[1][i] / rho,
262*88b783a1SJames Wright                                     q[2][i] / rho,
263*88b783a1SJames Wright                                     q[3][i] / rho
264*88b783a1SJames Wright                                    };
265*88b783a1SJames Wright     const CeedScalar E          =   q[4][i];
266*88b783a1SJames Wright     // -- Grad in
267*88b783a1SJames Wright     const CeedScalar drho[3]    =  {dq[0][0][i],
268*88b783a1SJames Wright                                     dq[1][0][i],
269*88b783a1SJames Wright                                     dq[2][0][i]
270*88b783a1SJames Wright                                    };
271*88b783a1SJames Wright     const CeedScalar dU[3][3]   = {{dq[0][1][i],
272*88b783a1SJames Wright                                     dq[1][1][i],
273*88b783a1SJames Wright                                     dq[2][1][i]},
274*88b783a1SJames Wright                                    {dq[0][2][i],
275*88b783a1SJames Wright                                     dq[1][2][i],
276*88b783a1SJames Wright                                     dq[2][2][i]},
277*88b783a1SJames Wright                                    {dq[0][3][i],
278*88b783a1SJames Wright                                     dq[1][3][i],
279*88b783a1SJames Wright                                     dq[2][3][i]}
280*88b783a1SJames Wright                                   };
281*88b783a1SJames Wright     const CeedScalar dE[3]      =  {dq[0][4][i],
282*88b783a1SJames Wright                                     dq[1][4][i],
283*88b783a1SJames Wright                                     dq[2][4][i]
284*88b783a1SJames Wright                                    };
285*88b783a1SJames Wright     // -- Interp-to-Interp q_data
286*88b783a1SJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
287*88b783a1SJames Wright     // -- Interp-to-Grad q_data
288*88b783a1SJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
289*88b783a1SJames Wright     // *INDENT-OFF*
290*88b783a1SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
291*88b783a1SJames Wright                                     q_data[2][i],
292*88b783a1SJames Wright                                     q_data[3][i]},
293*88b783a1SJames Wright                                    {q_data[4][i],
294*88b783a1SJames Wright                                     q_data[5][i],
295*88b783a1SJames Wright                                     q_data[6][i]},
296*88b783a1SJames Wright                                    {q_data[7][i],
297*88b783a1SJames Wright                                     q_data[8][i],
298*88b783a1SJames Wright                                     q_data[9][i]}
299*88b783a1SJames Wright                                   };
300*88b783a1SJames Wright     // *INDENT-ON*
301*88b783a1SJames Wright     // -- Grad-to-Grad q_data
302*88b783a1SJames Wright     // dU/dx
303*88b783a1SJames Wright     CeedScalar du[3][3] = {{0}};
304*88b783a1SJames Wright     CeedScalar drhodx[3] = {0};
305*88b783a1SJames Wright     CeedScalar dEdx[3] = {0};
306*88b783a1SJames Wright     CeedScalar dUdx[3][3] = {{0}};
307*88b783a1SJames Wright     CeedScalar dXdxdXdxT[3][3] = {{0}};
308*88b783a1SJames Wright     for (int j=0; j<3; j++) {
309*88b783a1SJames Wright       for (int k=0; k<3; k++) {
310*88b783a1SJames Wright         du[j][k] = (dU[j][k] - drho[k]*u[j]) / rho;
311*88b783a1SJames Wright         drhodx[j] += drho[k] * dXdx[k][j];
312*88b783a1SJames Wright         dEdx[j] += dE[k] * dXdx[k][j];
313*88b783a1SJames Wright         for (int l=0; l<3; l++) {
314*88b783a1SJames Wright           dUdx[j][k] += dU[j][l] * dXdx[l][k];
315*88b783a1SJames Wright           dXdxdXdxT[j][k] += dXdx[j][l]*dXdx[k][l];  //dXdx_j,k * dXdx_k,j
316*88b783a1SJames Wright         }
317*88b783a1SJames Wright       }
318*88b783a1SJames Wright     }
319*88b783a1SJames Wright     CeedScalar dudx[3][3] = {{0}};
320*88b783a1SJames Wright     for (int j=0; j<3; j++)
321*88b783a1SJames Wright       for (int k=0; k<3; k++)
322*88b783a1SJames Wright         for (int l=0; l<3; l++)
323*88b783a1SJames Wright           dudx[j][k] += du[j][l] * dXdx[l][k];
324*88b783a1SJames Wright     // -- grad_T
325*88b783a1SJames Wright     const CeedScalar grad_T[3]  = {(dEdx[0]/rho - E*drhodx[0]/(rho*rho) - /* *NOPAD* */
326*88b783a1SJames Wright                                     (u[0]*dudx[0][0] + u[1]*dudx[1][0] + u[2]*dudx[2][0]))/cv,
327*88b783a1SJames Wright                                    (dEdx[1]/rho - E*drhodx[1]/(rho*rho) - /* *NOPAD* */
328*88b783a1SJames Wright                                     (u[0]*dudx[0][1] + u[1]*dudx[1][1] + u[2]*dudx[2][1]))/cv,
329*88b783a1SJames Wright                                    (dEdx[2]/rho - E*drhodx[2]/(rho*rho) - /* *NOPAD* */
330*88b783a1SJames Wright                                     (u[0]*dudx[0][2] + u[1]*dudx[1][2] + u[2]*dudx[2][2]) - g)/cv
331*88b783a1SJames Wright                                   };
332*88b783a1SJames Wright 
333*88b783a1SJames Wright     // -- Fuvisc
334*88b783a1SJames Wright     // ---- Symmetric 3x3 matrix
335*88b783a1SJames Wright     const CeedScalar Fu[6]     =  {mu*(dudx[0][0] * (2 + lambda) + /* *NOPAD* */
336*88b783a1SJames Wright                                        lambda * (dudx[1][1] + dudx[2][2])),
337*88b783a1SJames Wright                                    mu*(dudx[0][1] + dudx[1][0]), /* *NOPAD* */
338*88b783a1SJames Wright                                    mu*(dudx[0][2] + dudx[2][0]), /* *NOPAD* */
339*88b783a1SJames Wright                                    mu*(dudx[1][1] * (2 + lambda) + /* *NOPAD* */
340*88b783a1SJames Wright                                        lambda * (dudx[0][0] + dudx[2][2])),
341*88b783a1SJames Wright                                    mu*(dudx[1][2] + dudx[2][1]), /* *NOPAD* */
342*88b783a1SJames Wright                                    mu*(dudx[2][2] * (2 + lambda) + /* *NOPAD* */
343*88b783a1SJames Wright                                        lambda * (dudx[0][0] + dudx[1][1]))
344*88b783a1SJames Wright                                   };
345*88b783a1SJames Wright     // -- Fevisc
346*88b783a1SJames Wright     const CeedScalar Fe[3]     =  {u[0]*Fu[0] + u[1]*Fu[1] + u[2]*Fu[2] + /* *NOPAD* */
347*88b783a1SJames Wright                                    k*grad_T[0], /* *NOPAD* */
348*88b783a1SJames Wright                                    u[0]*Fu[1] + u[1]*Fu[3] + u[2]*Fu[4] + /* *NOPAD* */
349*88b783a1SJames Wright                                    k*grad_T[1], /* *NOPAD* */
350*88b783a1SJames Wright                                    u[0]*Fu[2] + u[1]*Fu[4] + u[2]*Fu[5] + /* *NOPAD* */
351*88b783a1SJames Wright                                    k*grad_T[2] /* *NOPAD* */
352*88b783a1SJames Wright                                   };
353*88b783a1SJames Wright     // Pressure
354*88b783a1SJames Wright     const CeedScalar
355*88b783a1SJames Wright     E_kinetic   = 0.5 * rho * (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]),
356*88b783a1SJames Wright     E_potential = rho*g*x[2][i],
357*88b783a1SJames Wright     E_internal  = E - E_kinetic - E_potential,
358*88b783a1SJames Wright     P           = E_internal * (gamma - 1.); // P = pressure
359*88b783a1SJames Wright 
360*88b783a1SJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
361*88b783a1SJames Wright     CeedScalar jacob_F_conv[3][5][5] = {{{0.}}};
362*88b783a1SJames Wright     computeFluxJacobian_NS(jacob_F_conv, rho, u, E, gamma, g, x[2][i]);
363*88b783a1SJames Wright 
364*88b783a1SJames Wright     // jacob_F_conv_T = jacob_F_conv^T
365*88b783a1SJames Wright     CeedScalar jacob_F_conv_T[3][5][5];
366*88b783a1SJames Wright     for (int j=0; j<3; j++)
367*88b783a1SJames Wright       for (int k=0; k<5; k++)
368*88b783a1SJames Wright         for (int l=0; l<5; l++)
369*88b783a1SJames Wright           jacob_F_conv_T[j][k][l] = jacob_F_conv[j][l][k];
370*88b783a1SJames Wright 
371*88b783a1SJames Wright     // dqdx collects drhodx, dUdx and dEdx in one vector
372*88b783a1SJames Wright     CeedScalar dqdx[5][3];
373*88b783a1SJames Wright     for (int j=0; j<3; j++) {
374*88b783a1SJames Wright       dqdx[0][j] = drhodx[j];
375*88b783a1SJames Wright       dqdx[4][j] = dEdx[j];
376*88b783a1SJames Wright       for (int k=0; k<3; k++)
377*88b783a1SJames Wright         dqdx[k+1][j] = dUdx[k][j];
378*88b783a1SJames Wright     }
379*88b783a1SJames Wright 
380*88b783a1SJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
381*88b783a1SJames Wright     CeedScalar strong_conv[5] = {0};
382*88b783a1SJames Wright     for (int j=0; j<3; j++)
383*88b783a1SJames Wright       for (int k=0; k<5; k++)
384*88b783a1SJames Wright         for (int l=0; l<5; l++)
385*88b783a1SJames Wright           strong_conv[k] += jacob_F_conv[j][k][l] * dqdx[l][j];
386*88b783a1SJames Wright 
387*88b783a1SJames Wright     // Body force
388*88b783a1SJames Wright     const CeedScalar body_force[5] = {0, 0, 0, -rho*g, 0};
389*88b783a1SJames Wright 
390*88b783a1SJames Wright     // The Physics
391*88b783a1SJames Wright     // Zero dv so all future terms can safely sum into it
392*88b783a1SJames Wright     for (int j=0; j<5; j++)
393*88b783a1SJames Wright       for (int k=0; k<3; k++)
394*88b783a1SJames Wright         dv[k][j][i] = 0;
395*88b783a1SJames Wright 
396*88b783a1SJames Wright     // -- Density
397*88b783a1SJames Wright     // ---- u rho
398*88b783a1SJames Wright     for (int j=0; j<3; j++)
399*88b783a1SJames Wright       dv[j][0][i]  += wdetJ*(rho*u[0]*dXdx[j][0] + rho*u[1]*dXdx[j][1] +
400*88b783a1SJames Wright                              rho*u[2]*dXdx[j][2]);
401*88b783a1SJames Wright     // -- Momentum
402*88b783a1SJames Wright     // ---- rho (u x u) + P I3
403*88b783a1SJames Wright     for (int j=0; j<3; j++)
404*88b783a1SJames Wright       for (int k=0; k<3; k++)
405*88b783a1SJames Wright         dv[k][j+1][i]  += wdetJ*((rho*u[j]*u[0] + (j==0?P:0))*dXdx[k][0] +
406*88b783a1SJames Wright                                  (rho*u[j]*u[1] + (j==1?P:0))*dXdx[k][1] +
407*88b783a1SJames Wright                                  (rho*u[j]*u[2] + (j==2?P:0))*dXdx[k][2]);
408*88b783a1SJames Wright     // ---- Fuvisc
409*88b783a1SJames Wright     const CeedInt Fuviscidx[3][3] = {{0, 1, 2}, {1, 3, 4}, {2, 4, 5}}; // symmetric matrix indices
410*88b783a1SJames Wright     for (int j=0; j<3; j++)
411*88b783a1SJames Wright       for (int k=0; k<3; k++)
412*88b783a1SJames Wright         dv[k][j+1][i] -= wdetJ*(Fu[Fuviscidx[j][0]]*dXdx[k][0] +
413*88b783a1SJames Wright                                 Fu[Fuviscidx[j][1]]*dXdx[k][1] +
414*88b783a1SJames Wright                                 Fu[Fuviscidx[j][2]]*dXdx[k][2]);
415*88b783a1SJames Wright     // -- Total Energy Density
416*88b783a1SJames Wright     // ---- (E + P) u
417*88b783a1SJames Wright     for (int j=0; j<3; j++)
418*88b783a1SJames Wright       dv[j][4][i]  += wdetJ * (E + P) * (u[0]*dXdx[j][0] + u[1]*dXdx[j][1] +
419*88b783a1SJames Wright                                          u[2]*dXdx[j][2]);
420*88b783a1SJames Wright     // ---- Fevisc
421*88b783a1SJames Wright     for (int j=0; j<3; j++)
422*88b783a1SJames Wright       dv[j][4][i] -= wdetJ * (Fe[0]*dXdx[j][0] + Fe[1]*dXdx[j][1] +
423*88b783a1SJames Wright                               Fe[2]*dXdx[j][2]);
424*88b783a1SJames Wright     // Body Force
425*88b783a1SJames Wright     for (int j=0; j<5; j++)
426*88b783a1SJames Wright       v[j][i] = wdetJ * body_force[j];
427*88b783a1SJames Wright 
428*88b783a1SJames Wright     // Stabilization
429*88b783a1SJames Wright     // -- Tau elements
430*88b783a1SJames Wright     const CeedScalar sound_speed = sqrt(gamma * P / rho);
431*88b783a1SJames Wright     CeedScalar Tau_x[3] = {0.};
432*88b783a1SJames Wright     Tau_spatial(Tau_x, dXdx, u, sound_speed, c_tau);
433*88b783a1SJames Wright 
434*88b783a1SJames Wright     // -- Stabilization method: none or SU
435*88b783a1SJames Wright     CeedScalar stab[5][3];
436*88b783a1SJames Wright     switch (context->stabilization) {
437*88b783a1SJames Wright     case STAB_NONE:        // Galerkin
438*88b783a1SJames Wright       break;
439*88b783a1SJames Wright     case STAB_SU:        // SU
440*88b783a1SJames Wright       for (int j=0; j<3; j++)
441*88b783a1SJames Wright         for (int k=0; k<5; k++)
442*88b783a1SJames Wright           for (int l=0; l<5; l++)
443*88b783a1SJames Wright             stab[k][j] = jacob_F_conv_T[j][k][l] * Tau_x[j] * strong_conv[l];
444*88b783a1SJames Wright 
445*88b783a1SJames Wright       for (int j=0; j<5; j++)
446*88b783a1SJames Wright         for (int k=0; k<3; k++)
447*88b783a1SJames Wright           dv[k][j][i] -= wdetJ*(stab[j][0] * dXdx[k][0] +
448*88b783a1SJames Wright                                 stab[j][1] * dXdx[k][1] +
449*88b783a1SJames Wright                                 stab[j][2] * dXdx[k][2]);
450*88b783a1SJames Wright       break;
451*88b783a1SJames Wright     case STAB_SUPG:        // SUPG is not implemented for explicit scheme
452*88b783a1SJames Wright       break;
453*88b783a1SJames Wright     }
454*88b783a1SJames Wright 
455*88b783a1SJames Wright   } // End Quadrature Point Loop
456*88b783a1SJames Wright 
457*88b783a1SJames Wright   // Return
458*88b783a1SJames Wright   return 0;
459*88b783a1SJames Wright }
460*88b783a1SJames Wright 
461*88b783a1SJames Wright // *****************************************************************************
462*88b783a1SJames Wright // This QFunction implements the Navier-Stokes equations (mentioned above) with
463*88b783a1SJames Wright //   implicit time stepping method
464*88b783a1SJames Wright //
465*88b783a1SJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
466*88b783a1SJames Wright //  SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) )
467*88b783a1SJames Wright //                                       (diffussive terms will be added later)
468*88b783a1SJames Wright //
469*88b783a1SJames Wright // *****************************************************************************
470*88b783a1SJames Wright CEED_QFUNCTION(IFunction_Newtonian)(void *ctx, CeedInt Q,
471*88b783a1SJames Wright                                     const CeedScalar *const *in,
472*88b783a1SJames Wright                                     CeedScalar *const *out) {
473*88b783a1SJames Wright   // *INDENT-OFF*
474*88b783a1SJames Wright   // Inputs
475*88b783a1SJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
476*88b783a1SJames Wright                    (*dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
477*88b783a1SJames Wright                    (*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
478*88b783a1SJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
479*88b783a1SJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
480*88b783a1SJames Wright   // Outputs
481*88b783a1SJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
482*88b783a1SJames Wright              (*dv)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
483*88b783a1SJames Wright   // *INDENT-ON*
484*88b783a1SJames Wright   // Context
485*88b783a1SJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
486*88b783a1SJames Wright   const CeedScalar lambda = context->lambda;
487*88b783a1SJames Wright   const CeedScalar mu     = context->mu;
488*88b783a1SJames Wright   const CeedScalar k      = context->k;
489*88b783a1SJames Wright   const CeedScalar cv     = context->cv;
490*88b783a1SJames Wright   const CeedScalar cp     = context->cp;
491*88b783a1SJames Wright   const CeedScalar g      = context->g;
492*88b783a1SJames Wright   const CeedScalar c_tau  = context->c_tau;
493*88b783a1SJames Wright   const CeedScalar gamma  = cp / cv;
494*88b783a1SJames Wright 
495*88b783a1SJames Wright   CeedPragmaSIMD
496*88b783a1SJames Wright   // Quadrature Point Loop
497*88b783a1SJames Wright   for (CeedInt i=0; i<Q; i++) {
498*88b783a1SJames Wright     // Setup
499*88b783a1SJames Wright     // -- Interp in
500*88b783a1SJames Wright     const CeedScalar rho        =   q[0][i];
501*88b783a1SJames Wright     const CeedScalar u[3]       =  {q[1][i] / rho,
502*88b783a1SJames Wright                                     q[2][i] / rho,
503*88b783a1SJames Wright                                     q[3][i] / rho
504*88b783a1SJames Wright                                    };
505*88b783a1SJames Wright     const CeedScalar E          =   q[4][i];
506*88b783a1SJames Wright     // -- Grad in
507*88b783a1SJames Wright     const CeedScalar drho[3]    =  {dq[0][0][i],
508*88b783a1SJames Wright                                     dq[1][0][i],
509*88b783a1SJames Wright                                     dq[2][0][i]
510*88b783a1SJames Wright                                    };
511*88b783a1SJames Wright     // *INDENT-OFF*
512*88b783a1SJames Wright     const CeedScalar dU[3][3]   = {{dq[0][1][i],
513*88b783a1SJames Wright                                     dq[1][1][i],
514*88b783a1SJames Wright                                     dq[2][1][i]},
515*88b783a1SJames Wright                                    {dq[0][2][i],
516*88b783a1SJames Wright                                     dq[1][2][i],
517*88b783a1SJames Wright                                     dq[2][2][i]},
518*88b783a1SJames Wright                                    {dq[0][3][i],
519*88b783a1SJames Wright                                     dq[1][3][i],
520*88b783a1SJames Wright                                     dq[2][3][i]}
521*88b783a1SJames Wright                                   };
522*88b783a1SJames Wright     // *INDENT-ON*
523*88b783a1SJames Wright     const CeedScalar dE[3]      =  {dq[0][4][i],
524*88b783a1SJames Wright                                     dq[1][4][i],
525*88b783a1SJames Wright                                     dq[2][4][i]
526*88b783a1SJames Wright                                    };
527*88b783a1SJames Wright     // -- Interp-to-Interp q_data
528*88b783a1SJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
529*88b783a1SJames Wright     // -- Interp-to-Grad q_data
530*88b783a1SJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
531*88b783a1SJames Wright     // *INDENT-OFF*
532*88b783a1SJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
533*88b783a1SJames Wright                                     q_data[2][i],
534*88b783a1SJames Wright                                     q_data[3][i]},
535*88b783a1SJames Wright                                    {q_data[4][i],
536*88b783a1SJames Wright                                     q_data[5][i],
537*88b783a1SJames Wright                                     q_data[6][i]},
538*88b783a1SJames Wright                                    {q_data[7][i],
539*88b783a1SJames Wright                                     q_data[8][i],
540*88b783a1SJames Wright                                     q_data[9][i]}
541*88b783a1SJames Wright                                   };
542*88b783a1SJames Wright     // *INDENT-ON*
543*88b783a1SJames Wright     // -- Grad-to-Grad q_data
544*88b783a1SJames Wright     // dU/dx
545*88b783a1SJames Wright     CeedScalar du[3][3] = {{0}};
546*88b783a1SJames Wright     CeedScalar drhodx[3] = {0};
547*88b783a1SJames Wright     CeedScalar dEdx[3] = {0};
548*88b783a1SJames Wright     CeedScalar dUdx[3][3] = {{0}};
549*88b783a1SJames Wright     CeedScalar dXdxdXdxT[3][3] = {{0}};
550*88b783a1SJames Wright     for (int j=0; j<3; j++) {
551*88b783a1SJames Wright       for (int k=0; k<3; k++) {
552*88b783a1SJames Wright         du[j][k] = (dU[j][k] - drho[k]*u[j]) / rho;
553*88b783a1SJames Wright         drhodx[j] += drho[k] * dXdx[k][j];
554*88b783a1SJames Wright         dEdx[j] += dE[k] * dXdx[k][j];
555*88b783a1SJames Wright         for (int l=0; l<3; l++) {
556*88b783a1SJames Wright           dUdx[j][k] += dU[j][l] * dXdx[l][k];
557*88b783a1SJames Wright           dXdxdXdxT[j][k] += dXdx[j][l]*dXdx[k][l];  //dXdx_j,k * dXdx_k,j
558*88b783a1SJames Wright         }
559*88b783a1SJames Wright       }
560*88b783a1SJames Wright     }
561*88b783a1SJames Wright     CeedScalar dudx[3][3] = {{0}};
562*88b783a1SJames Wright     for (int j=0; j<3; j++)
563*88b783a1SJames Wright       for (int k=0; k<3; k++)
564*88b783a1SJames Wright         for (int l=0; l<3; l++)
565*88b783a1SJames Wright           dudx[j][k] += du[j][l] * dXdx[l][k];
566*88b783a1SJames Wright     // -- grad_T
567*88b783a1SJames Wright     const CeedScalar grad_T[3]  = {(dEdx[0]/rho - E*drhodx[0]/(rho*rho) - /* *NOPAD* */
568*88b783a1SJames Wright                                     (u[0]*dudx[0][0] + u[1]*dudx[1][0] + u[2]*dudx[2][0]))/cv,
569*88b783a1SJames Wright                                    (dEdx[1]/rho - E*drhodx[1]/(rho*rho) - /* *NOPAD* */
570*88b783a1SJames Wright                                     (u[0]*dudx[0][1] + u[1]*dudx[1][1] + u[2]*dudx[2][1]))/cv,
571*88b783a1SJames Wright                                    (dEdx[2]/rho - E*drhodx[2]/(rho*rho) - /* *NOPAD* */
572*88b783a1SJames Wright                                     (u[0]*dudx[0][2] + u[1]*dudx[1][2] + u[2]*dudx[2][2]) - g)/cv
573*88b783a1SJames Wright                                   };
574*88b783a1SJames Wright     // -- Fuvisc
575*88b783a1SJames Wright     // ---- Symmetric 3x3 matrix
576*88b783a1SJames Wright     const CeedScalar Fu[6]     =  {mu*(dudx[0][0] * (2 + lambda) + /* *NOPAD* */
577*88b783a1SJames Wright                                        lambda * (dudx[1][1] + dudx[2][2])),
578*88b783a1SJames Wright                                    mu*(dudx[0][1] + dudx[1][0]), /* *NOPAD* */
579*88b783a1SJames Wright                                    mu*(dudx[0][2] + dudx[2][0]), /* *NOPAD* */
580*88b783a1SJames Wright                                    mu*(dudx[1][1] * (2 + lambda) + /* *NOPAD* */
581*88b783a1SJames Wright                                        lambda * (dudx[0][0] + dudx[2][2])),
582*88b783a1SJames Wright                                    mu*(dudx[1][2] + dudx[2][1]), /* *NOPAD* */
583*88b783a1SJames Wright                                    mu*(dudx[2][2] * (2 + lambda) + /* *NOPAD* */
584*88b783a1SJames Wright                                        lambda * (dudx[0][0] + dudx[1][1]))
585*88b783a1SJames Wright                                   };
586*88b783a1SJames Wright     // -- Fevisc
587*88b783a1SJames Wright     const CeedScalar Fe[3]     =  {u[0]*Fu[0] + u[1]*Fu[1] + u[2]*Fu[2] + /* *NOPAD* */
588*88b783a1SJames Wright                                    k*grad_T[0], /* *NOPAD* */
589*88b783a1SJames Wright                                    u[0]*Fu[1] + u[1]*Fu[3] + u[2]*Fu[4] + /* *NOPAD* */
590*88b783a1SJames Wright                                    k*grad_T[1], /* *NOPAD* */
591*88b783a1SJames Wright                                    u[0]*Fu[2] + u[1]*Fu[4] + u[2]*Fu[5] + /* *NOPAD* */
592*88b783a1SJames Wright                                    k*grad_T[2] /* *NOPAD* */
593*88b783a1SJames Wright                                   };
594*88b783a1SJames Wright     // Pressure
595*88b783a1SJames Wright     const CeedScalar
596*88b783a1SJames Wright     E_kinetic   = 0.5 * rho * (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]),
597*88b783a1SJames Wright     E_potential = rho*g*x[2][i],
598*88b783a1SJames Wright     E_internal  = E - E_kinetic - E_potential,
599*88b783a1SJames Wright     P           = E_internal * (gamma - 1.); // P = pressure
600*88b783a1SJames Wright 
601*88b783a1SJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
602*88b783a1SJames Wright     CeedScalar jacob_F_conv[3][5][5] = {{{0.}}};
603*88b783a1SJames Wright     computeFluxJacobian_NS(jacob_F_conv, rho, u, E, gamma, g, x[2][i]);
604*88b783a1SJames Wright 
605*88b783a1SJames Wright     // jacob_F_conv_T = jacob_F_conv^T
606*88b783a1SJames Wright     CeedScalar jacob_F_conv_T[3][5][5];
607*88b783a1SJames Wright     for (int j=0; j<3; j++)
608*88b783a1SJames Wright       for (int k=0; k<5; k++)
609*88b783a1SJames Wright         for (int l=0; l<5; l++)
610*88b783a1SJames Wright           jacob_F_conv_T[j][k][l] = jacob_F_conv[j][l][k];
611*88b783a1SJames Wright     // dqdx collects drhodx, dUdx and dEdx in one vector
612*88b783a1SJames Wright     CeedScalar dqdx[5][3];
613*88b783a1SJames Wright     for (int j=0; j<3; j++) {
614*88b783a1SJames Wright       dqdx[0][j] = drhodx[j];
615*88b783a1SJames Wright       dqdx[4][j] = dEdx[j];
616*88b783a1SJames Wright       for (int k=0; k<3; k++)
617*88b783a1SJames Wright         dqdx[k+1][j] = dUdx[k][j];
618*88b783a1SJames Wright     }
619*88b783a1SJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
620*88b783a1SJames Wright     CeedScalar strong_conv[5] = {0};
621*88b783a1SJames Wright     for (int j=0; j<3; j++)
622*88b783a1SJames Wright       for (int k=0; k<5; k++)
623*88b783a1SJames Wright         for (int l=0; l<5; l++)
624*88b783a1SJames Wright           strong_conv[k] += jacob_F_conv[j][k][l] * dqdx[l][j];
625*88b783a1SJames Wright 
626*88b783a1SJames Wright     // Body force
627*88b783a1SJames Wright     const CeedScalar body_force[5] = {0, 0, 0, -rho*g, 0};
628*88b783a1SJames Wright 
629*88b783a1SJames Wright     // Strong residual
630*88b783a1SJames Wright     CeedScalar strong_res[5];
631*88b783a1SJames Wright     for (int j=0; j<5; j++)
632*88b783a1SJames Wright       strong_res[j] = q_dot[j][i] + strong_conv[j] - body_force[j];
633*88b783a1SJames Wright 
634*88b783a1SJames Wright     // The Physics
635*88b783a1SJames Wright     //-----mass matrix
636*88b783a1SJames Wright     for (int j=0; j<5; j++)
637*88b783a1SJames Wright       v[j][i] = wdetJ*q_dot[j][i];
638*88b783a1SJames Wright 
639*88b783a1SJames Wright     // Zero dv so all future terms can safely sum into it
640*88b783a1SJames Wright     for (int j=0; j<5; j++)
641*88b783a1SJames Wright       for (int k=0; k<3; k++)
642*88b783a1SJames Wright         dv[k][j][i] = 0;
643*88b783a1SJames Wright 
644*88b783a1SJames Wright     // -- Density
645*88b783a1SJames Wright     // ---- u rho
646*88b783a1SJames Wright     for (int j=0; j<3; j++)
647*88b783a1SJames Wright       dv[j][0][i]  -= wdetJ*(rho*u[0]*dXdx[j][0] + rho*u[1]*dXdx[j][1] +
648*88b783a1SJames Wright                              rho*u[2]*dXdx[j][2]);
649*88b783a1SJames Wright     // -- Momentum
650*88b783a1SJames Wright     // ---- rho (u x u) + P I3
651*88b783a1SJames Wright     for (int j=0; j<3; j++)
652*88b783a1SJames Wright       for (int k=0; k<3; k++)
653*88b783a1SJames Wright         dv[k][j+1][i]  -= wdetJ*((rho*u[j]*u[0] + (j==0?P:0))*dXdx[k][0] +
654*88b783a1SJames Wright                                  (rho*u[j]*u[1] + (j==1?P:0))*dXdx[k][1] +
655*88b783a1SJames Wright                                  (rho*u[j]*u[2] + (j==2?P:0))*dXdx[k][2]);
656*88b783a1SJames Wright     // ---- Fuvisc
657*88b783a1SJames Wright     const CeedInt Fuviscidx[3][3] = {{0, 1, 2}, {1, 3, 4}, {2, 4, 5}}; // symmetric matrix indices
658*88b783a1SJames Wright     for (int j=0; j<3; j++)
659*88b783a1SJames Wright       for (int k=0; k<3; k++)
660*88b783a1SJames Wright         dv[k][j+1][i] += wdetJ*(Fu[Fuviscidx[j][0]]*dXdx[k][0] +
661*88b783a1SJames Wright                                 Fu[Fuviscidx[j][1]]*dXdx[k][1] +
662*88b783a1SJames Wright                                 Fu[Fuviscidx[j][2]]*dXdx[k][2]);
663*88b783a1SJames Wright     // -- Total Energy Density
664*88b783a1SJames Wright     // ---- (E + P) u
665*88b783a1SJames Wright     for (int j=0; j<3; j++)
666*88b783a1SJames Wright       dv[j][4][i]  -= wdetJ * (E + P) * (u[0]*dXdx[j][0] + u[1]*dXdx[j][1] +
667*88b783a1SJames Wright                                          u[2]*dXdx[j][2]);
668*88b783a1SJames Wright     // ---- Fevisc
669*88b783a1SJames Wright     for (int j=0; j<3; j++)
670*88b783a1SJames Wright       dv[j][4][i] += wdetJ * (Fe[0]*dXdx[j][0] + Fe[1]*dXdx[j][1] +
671*88b783a1SJames Wright                               Fe[2]*dXdx[j][2]);
672*88b783a1SJames Wright     // Body Force
673*88b783a1SJames Wright     for (int j=0; j<5; j++)
674*88b783a1SJames Wright       v[j][i] -= wdetJ*body_force[j];
675*88b783a1SJames Wright 
676*88b783a1SJames Wright     // Stabilization
677*88b783a1SJames Wright     // -- Tau elements
678*88b783a1SJames Wright     const CeedScalar sound_speed = sqrt(gamma * P / rho);
679*88b783a1SJames Wright     CeedScalar Tau_x[3] = {0.};
680*88b783a1SJames Wright     Tau_spatial(Tau_x, dXdx, u, sound_speed, c_tau);
681*88b783a1SJames Wright 
682*88b783a1SJames Wright     // -- Stabilization method: none, SU, or SUPG
683*88b783a1SJames Wright     CeedScalar stab[5][3];
684*88b783a1SJames Wright     switch (context->stabilization) {
685*88b783a1SJames Wright     case STAB_NONE:        // Galerkin
686*88b783a1SJames Wright       break;
687*88b783a1SJames Wright     case STAB_SU:        // SU
688*88b783a1SJames Wright       for (int j=0; j<3; j++)
689*88b783a1SJames Wright         for (int k=0; k<5; k++)
690*88b783a1SJames Wright           for (int l=0; l<5; l++)
691*88b783a1SJames Wright             stab[k][j] = jacob_F_conv_T[j][k][l] * Tau_x[j] * strong_conv[l];
692*88b783a1SJames Wright 
693*88b783a1SJames Wright       for (int j=0; j<5; j++)
694*88b783a1SJames Wright         for (int k=0; k<3; k++)
695*88b783a1SJames Wright           dv[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
696*88b783a1SJames Wright                                 stab[j][1] * dXdx[k][1] +
697*88b783a1SJames Wright                                 stab[j][2] * dXdx[k][2]);
698*88b783a1SJames Wright       break;
699*88b783a1SJames Wright     case STAB_SUPG:        // SUPG
700*88b783a1SJames Wright       for (int j=0; j<3; j++)
701*88b783a1SJames Wright         for (int k=0; k<5; k++)
702*88b783a1SJames Wright           for (int l=0; l<5; l++)
703*88b783a1SJames Wright             stab[k][j] = jacob_F_conv_T[j][k][l] * Tau_x[j] * strong_res[l];
704*88b783a1SJames Wright 
705*88b783a1SJames Wright       for (int j=0; j<5; j++)
706*88b783a1SJames Wright         for (int k=0; k<3; k++)
707*88b783a1SJames Wright           dv[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
708*88b783a1SJames Wright                                 stab[j][1] * dXdx[k][1] +
709*88b783a1SJames Wright                                 stab[j][2] * dXdx[k][2]);
710*88b783a1SJames Wright       break;
711*88b783a1SJames Wright     }
712*88b783a1SJames Wright 
713*88b783a1SJames Wright   } // End Quadrature Point Loop
714*88b783a1SJames Wright 
715*88b783a1SJames Wright   // Return
716*88b783a1SJames Wright   return 0;
717*88b783a1SJames Wright }
718*88b783a1SJames Wright // *****************************************************************************
719*88b783a1SJames Wright #endif // newtonian_h
720