xref: /honee/qfunctions/newtonian.h (revision 2acc7cbc845d29aad343acf069e3661fb8b46259)
1727da7e7SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2727da7e7SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
33a8779fbSJames Wright //
4727da7e7SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
53a8779fbSJames Wright //
6727da7e7SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
73a8779fbSJames Wright 
83a8779fbSJames Wright /// @file
93a8779fbSJames Wright /// Operator for Navier-Stokes example using PETSc
103a8779fbSJames Wright 
113a8779fbSJames Wright 
123a8779fbSJames Wright #ifndef newtonian_h
133a8779fbSJames Wright #define newtonian_h
143a8779fbSJames Wright 
153a8779fbSJames Wright #include <math.h>
163a8779fbSJames Wright #include <ceed.h>
173a8779fbSJames Wright 
183a8779fbSJames Wright #ifndef M_PI
193a8779fbSJames Wright #define M_PI    3.14159265358979323846
203a8779fbSJames Wright #endif
213a8779fbSJames Wright 
223a8779fbSJames Wright #ifndef setup_context_struct
233a8779fbSJames Wright #define setup_context_struct
243a8779fbSJames Wright typedef struct SetupContext_ *SetupContext;
253a8779fbSJames Wright struct SetupContext_ {
263a8779fbSJames Wright   CeedScalar theta0;
273a8779fbSJames Wright   CeedScalar thetaC;
283a8779fbSJames Wright   CeedScalar P0;
293a8779fbSJames Wright   CeedScalar N;
303a8779fbSJames Wright   CeedScalar cv;
313a8779fbSJames Wright   CeedScalar cp;
32bb8a0c61SJames Wright   CeedScalar g[3];
333a8779fbSJames Wright   CeedScalar rc;
343a8779fbSJames Wright   CeedScalar lx;
353a8779fbSJames Wright   CeedScalar ly;
363a8779fbSJames Wright   CeedScalar lz;
373a8779fbSJames Wright   CeedScalar center[3];
383a8779fbSJames Wright   CeedScalar dc_axis[3];
393a8779fbSJames Wright   CeedScalar wind[3];
403a8779fbSJames Wright   CeedScalar time;
413a8779fbSJames Wright   int wind_type;              // See WindType: 0=ROTATION, 1=TRANSLATION
423a8779fbSJames Wright   int bubble_type;            // See BubbleType: 0=SPHERE, 1=CYLINDER
433a8779fbSJames Wright   int bubble_continuity_type; // See BubbleContinuityType: 0=SMOOTH, 1=BACK_SHARP 2=THICK
443a8779fbSJames Wright };
453a8779fbSJames Wright #endif
463a8779fbSJames Wright 
473a8779fbSJames Wright #ifndef newtonian_context_struct
483a8779fbSJames Wright #define newtonian_context_struct
493a8779fbSJames Wright typedef enum {
503a8779fbSJames Wright   STAB_NONE = 0,
513a8779fbSJames Wright   STAB_SU   = 1, // Streamline Upwind
523a8779fbSJames Wright   STAB_SUPG = 2, // Streamline Upwind Petrov-Galerkin
533a8779fbSJames Wright } StabilizationType;
543a8779fbSJames Wright 
553a8779fbSJames Wright typedef struct NewtonianIdealGasContext_ *NewtonianIdealGasContext;
563a8779fbSJames Wright struct NewtonianIdealGasContext_ {
573a8779fbSJames Wright   CeedScalar lambda;
583a8779fbSJames Wright   CeedScalar mu;
593a8779fbSJames Wright   CeedScalar k;
603a8779fbSJames Wright   CeedScalar cv;
613a8779fbSJames Wright   CeedScalar cp;
62bb8a0c61SJames Wright   CeedScalar g[3];
633a8779fbSJames Wright   CeedScalar c_tau;
64bb8a0c61SJames Wright   CeedScalar Ctau_t;
65bb8a0c61SJames Wright   CeedScalar Ctau_v;
66bb8a0c61SJames Wright   CeedScalar Ctau_C;
67bb8a0c61SJames Wright   CeedScalar Ctau_M;
68bb8a0c61SJames Wright   CeedScalar Ctau_E;
69bb8a0c61SJames Wright   CeedScalar dt;
703a8779fbSJames Wright   StabilizationType stabilization;
713a8779fbSJames Wright };
723a8779fbSJames Wright #endif
733a8779fbSJames Wright 
743a8779fbSJames Wright // *****************************************************************************
753a8779fbSJames Wright // Helper function for computing flux Jacobian
763a8779fbSJames Wright // *****************************************************************************
773a8779fbSJames Wright CEED_QFUNCTION_HELPER void computeFluxJacobian_NS(CeedScalar dF[3][5][5],
783a8779fbSJames Wright     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
79bb8a0c61SJames Wright     const CeedScalar gamma, const CeedScalar g[3], const CeedScalar x[3]) {
803a8779fbSJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
81bb8a0c61SJames Wright   CeedScalar e_potential = -(g[0]*x[0] + g[1]*x[1] + g[2]*x[2]);
823a8779fbSJames Wright   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
833a8779fbSJames Wright     for (CeedInt j=0; j<3; j++) { // Rows of each Jacobian matrix
84bb8a0c61SJames Wright       dF[i][j+1][0] = ((i==j) ? ((gamma-1.)*(u_sq/2. - e_potential)) : 0.) -
85bb8a0c61SJames Wright                       u[i]*u[j];
863a8779fbSJames Wright       for (CeedInt k=0; k<3; k++) { // Columns of each Jacobian matrix
873a8779fbSJames Wright         dF[i][0][k+1]   = ((i==k) ? 1. : 0.);
883a8779fbSJames Wright         dF[i][j+1][k+1] = ((j==k) ? u[i] : 0.) +
893a8779fbSJames Wright                           ((i==k) ? u[j] : 0.) -
903a8779fbSJames Wright                           ((i==j) ? u[k] : 0.) * (gamma-1.);
913a8779fbSJames Wright         dF[i][4][k+1]   = ((i==k) ? (E*gamma/rho - (gamma-1.)*u_sq/2.) : 0.) -
923a8779fbSJames Wright                           (gamma-1.)*u[i]*u[k];
933a8779fbSJames Wright       }
943a8779fbSJames Wright       dF[i][j+1][4] = ((i==j) ? (gamma-1.) : 0.);
953a8779fbSJames Wright     }
963a8779fbSJames Wright     dF[i][4][0] = u[i] * ((gamma-1.)*u_sq - E*gamma/rho);
973a8779fbSJames Wright     dF[i][4][4] = u[i] * gamma;
983a8779fbSJames Wright   }
993a8779fbSJames Wright }
1003a8779fbSJames Wright 
1013a8779fbSJames Wright // *****************************************************************************
102bb8a0c61SJames Wright // Helper function for computing flux Jacobian of Primitive variables
103bb8a0c61SJames Wright // *****************************************************************************
104bb8a0c61SJames Wright CEED_QFUNCTION_HELPER void computeFluxJacobian_NSp(CeedScalar dF[3][5][5],
105bb8a0c61SJames Wright     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
106bb8a0c61SJames Wright     const CeedScalar Rd, const CeedScalar cv) {
107bb8a0c61SJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
108bb8a0c61SJames Wright   // TODO Add in gravity's contribution
109bb8a0c61SJames Wright 
110bb8a0c61SJames Wright   CeedScalar T    = ( E / rho - u_sq / 2. ) / cv;
111bb8a0c61SJames Wright   CeedScalar drdT = -rho / T;
112bb8a0c61SJames Wright   CeedScalar drdP = 1. / ( Rd * T);
113bb8a0c61SJames Wright   CeedScalar etot =  E / rho ;
114bb8a0c61SJames Wright   CeedScalar e2p  = drdP * etot + 1. ;
115bb8a0c61SJames Wright   CeedScalar e3p  = ( E  + rho * Rd * T );
116bb8a0c61SJames Wright   CeedScalar e4p  = drdT * etot + rho * cv ;
117bb8a0c61SJames Wright 
118bb8a0c61SJames Wright   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
119bb8a0c61SJames Wright     for (CeedInt j=0; j<3; j++) { // j counts F^{m_j}
120bb8a0c61SJames Wright //        [row][col] of A_i
121bb8a0c61SJames Wright       dF[i][j+1][0] = drdP * u[i] * u[j] + ((i==j) ? 1. : 0.); // F^{{m_j} wrt p
122bb8a0c61SJames Wright       for (CeedInt k=0; k<3; k++) { // k counts the wrt vel_k
123*2acc7cbcSKenneth E. Jansen         dF[i][0][k+1]   =  ((i==k) ? rho  : 0.);   // F^c wrt u_k
124bb8a0c61SJames Wright         dF[i][j+1][k+1] = (((j==k) ? u[i] : 0.) +  // F^m_j wrt u_k
125bb8a0c61SJames Wright                            ((i==k) ? u[j] : 0.) ) * rho;
126bb8a0c61SJames Wright         dF[i][4][k+1]   = rho * u[i] * u[k]
127bb8a0c61SJames Wright                           + ((i==k) ? e3p  : 0.) ; // F^e wrt u_k
128bb8a0c61SJames Wright       }
129bb8a0c61SJames Wright       dF[i][j+1][4] = drdT * u[i] * u[j]; // F^{m_j} wrt T
130bb8a0c61SJames Wright     }
131bb8a0c61SJames Wright     dF[i][4][0] = u[i] * e2p; // F^e wrt p
132bb8a0c61SJames Wright     dF[i][4][4] = u[i] * e4p; // F^e wrt T
133bb8a0c61SJames Wright     dF[i][0][0] = u[i] * drdP; // F^c wrt p
134bb8a0c61SJames Wright     dF[i][0][4] = u[i] * drdT; // F^c wrt T
135bb8a0c61SJames Wright   }
136bb8a0c61SJames Wright }
137bb8a0c61SJames Wright 
138bb8a0c61SJames Wright CEED_QFUNCTION_HELPER void PrimitiveToConservative_fwd(const CeedScalar rho,
139bb8a0c61SJames Wright     const CeedScalar u[3], const CeedScalar E, const CeedScalar Rd,
140bb8a0c61SJames Wright     const CeedScalar cv, const CeedScalar dY[5], CeedScalar dU[5]) {
141bb8a0c61SJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
142bb8a0c61SJames Wright   CeedScalar T    = ( E / rho - u_sq / 2. ) / cv;
143bb8a0c61SJames Wright   CeedScalar drdT = -rho / T;
144bb8a0c61SJames Wright   CeedScalar drdP = 1. / ( Rd * T);
145bb8a0c61SJames Wright   dU[0] = drdP * dY[0] + drdT * dY[4];
146bb8a0c61SJames Wright   CeedScalar de_kinetic = 0;
147bb8a0c61SJames Wright   for (int i=0; i<3; i++) {
148bb8a0c61SJames Wright     dU[1+i] = dU[0] * u[i] + rho * dY[1+i];
149bb8a0c61SJames Wright     de_kinetic += u[i] * dY[1+i];
150bb8a0c61SJames Wright   }
151bb8a0c61SJames Wright   dU[4] = rho * cv * dY[4] + dU[0] * cv * T // internal energy: rho * e
152bb8a0c61SJames Wright           + rho * de_kinetic + .5 * dU[0] * u_sq; // kinetic energy: .5 * rho * |u|^2
153bb8a0c61SJames Wright }
154bb8a0c61SJames Wright 
155bb8a0c61SJames Wright // *****************************************************************************
156bb8a0c61SJames Wright // Helper function for computing Tau elements (stabilization constant)
157bb8a0c61SJames Wright //   Model from:
158bb8a0c61SJames Wright //     PHASTA
159bb8a0c61SJames Wright //
160bb8a0c61SJames Wright //   Tau[i] = itau=0 which is diagonal-Shakib (3 values still but not spatial)
161bb8a0c61SJames Wright //
162bb8a0c61SJames Wright // Where NOT UPDATED YET
163bb8a0c61SJames Wright // *****************************************************************************
164bb8a0c61SJames Wright CEED_QFUNCTION_HELPER void Tau_diagPrim(CeedScalar Tau_d[3],
165bb8a0c61SJames Wright                                         const CeedScalar dXdx[3][3], const CeedScalar u[3],
166bb8a0c61SJames Wright                                         const CeedScalar cv, const NewtonianIdealGasContext newt_ctx,
167bb8a0c61SJames Wright                                         const CeedScalar mu, const CeedScalar dt,
168bb8a0c61SJames Wright                                         const CeedScalar rho) {
169bb8a0c61SJames Wright   // Context
170bb8a0c61SJames Wright   const CeedScalar Ctau_t = newt_ctx->Ctau_t;
171bb8a0c61SJames Wright   const CeedScalar Ctau_v = newt_ctx->Ctau_v;
172bb8a0c61SJames Wright   const CeedScalar Ctau_C = newt_ctx->Ctau_C;
173bb8a0c61SJames Wright   const CeedScalar Ctau_M = newt_ctx->Ctau_M;
174bb8a0c61SJames Wright   const CeedScalar Ctau_E = newt_ctx->Ctau_E;
175bb8a0c61SJames Wright   CeedScalar gijd[6];
176bb8a0c61SJames Wright   CeedScalar tau;
177bb8a0c61SJames Wright   CeedScalar dts;
178bb8a0c61SJames Wright   CeedScalar fact;
179bb8a0c61SJames Wright 
180bb8a0c61SJames Wright   //*INDENT-OFF*
181bb8a0c61SJames Wright   gijd[0] =   dXdx[0][0] * dXdx[0][0]
182bb8a0c61SJames Wright             + dXdx[1][0] * dXdx[1][0]
183bb8a0c61SJames Wright             + dXdx[2][0] * dXdx[2][0];
184bb8a0c61SJames Wright 
185bb8a0c61SJames Wright   gijd[1] =   dXdx[0][0] * dXdx[0][1]
186bb8a0c61SJames Wright             + dXdx[1][0] * dXdx[1][1]
187bb8a0c61SJames Wright             + dXdx[2][0] * dXdx[2][1];
188bb8a0c61SJames Wright 
189bb8a0c61SJames Wright   gijd[2] =   dXdx[0][1] * dXdx[0][1]
190bb8a0c61SJames Wright             + dXdx[1][1] * dXdx[1][1]
191bb8a0c61SJames Wright             + dXdx[2][1] * dXdx[2][1];
192bb8a0c61SJames Wright 
193bb8a0c61SJames Wright   gijd[3] =   dXdx[0][0] * dXdx[0][2]
194bb8a0c61SJames Wright             + dXdx[1][0] * dXdx[1][2]
195bb8a0c61SJames Wright             + dXdx[2][0] * dXdx[2][2];
196bb8a0c61SJames Wright 
197bb8a0c61SJames Wright   gijd[4] =   dXdx[0][1] * dXdx[0][2]
198bb8a0c61SJames Wright             + dXdx[1][1] * dXdx[1][2]
199bb8a0c61SJames Wright             + dXdx[2][1] * dXdx[2][2];
200bb8a0c61SJames Wright 
201bb8a0c61SJames Wright   gijd[5] =   dXdx[0][2] * dXdx[0][2]
202bb8a0c61SJames Wright             + dXdx[1][2] * dXdx[1][2]
203bb8a0c61SJames Wright             + dXdx[2][2] * dXdx[2][2];
204bb8a0c61SJames Wright   //*INDENT-ON*
205bb8a0c61SJames Wright 
206bb8a0c61SJames Wright   dts = Ctau_t / dt ;
207bb8a0c61SJames Wright 
208bb8a0c61SJames Wright   tau = rho*rho*((4. * dts * dts)
209bb8a0c61SJames Wright                  + u[0] * ( u[0] * gijd[0] + 2. * ( u[1] * gijd[1] + u[2] * gijd[3]))
210bb8a0c61SJames Wright                  + u[1] * ( u[1] * gijd[2] + 2. *   u[2] * gijd[4])
211bb8a0c61SJames Wright                  + u[2] *   u[2] * gijd[5])
212bb8a0c61SJames Wright         + Ctau_v* mu * mu *
213bb8a0c61SJames Wright         (gijd[0]*gijd[0] + gijd[2]*gijd[2] + gijd[5]*gijd[5] +
214bb8a0c61SJames Wright          + 2. * (gijd[1]*gijd[1] + gijd[3]*gijd[3] + gijd[4]*gijd[4]));
215bb8a0c61SJames Wright 
216bb8a0c61SJames Wright   fact=sqrt(tau);
217bb8a0c61SJames Wright 
218bb8a0c61SJames Wright   Tau_d[0] = Ctau_C * fact / (rho*(gijd[0] + gijd[2] + gijd[5]))*0.125;
219bb8a0c61SJames Wright 
220bb8a0c61SJames Wright   Tau_d[1] = Ctau_M / fact;
221bb8a0c61SJames Wright   Tau_d[2] = Ctau_E / ( fact * cv );
222bb8a0c61SJames Wright 
223bb8a0c61SJames Wright // consider putting back the way I initially had it  Ctau_E * Tau_d[1] /cv
224bb8a0c61SJames Wright //  to avoid a division if the compiler is smart enough to see that cv IS
225bb8a0c61SJames Wright // a constant that it could invert once for all elements
226bb8a0c61SJames Wright // but in that case energy tau is scaled by the product of Ctau_E * Ctau_M
227bb8a0c61SJames Wright // OR we could absorb cv into Ctau_E but this puts more burden on user to
228bb8a0c61SJames Wright // know how to change constants with a change of fluid or units.  Same for
229bb8a0c61SJames Wright // Ctau_v * mu * mu IF AND ONLY IF we don't add viscosity law =f(T)
230bb8a0c61SJames Wright }
231bb8a0c61SJames Wright 
232bb8a0c61SJames Wright // *****************************************************************************
2333a8779fbSJames Wright // Helper function for computing Tau elements (stabilization constant)
2343a8779fbSJames Wright //   Model from:
2353a8779fbSJames Wright //     Stabilized Methods for Compressible Flows, Hughes et al 2010
2363a8779fbSJames Wright //
2373a8779fbSJames Wright //   Spatial criterion #2 - Tau is a 3x3 diagonal matrix
2383a8779fbSJames Wright //   Tau[i] = c_tau h[i] Xi(Pe) / rho(A[i]) (no sum)
2393a8779fbSJames Wright //
2403a8779fbSJames Wright // Where
2413a8779fbSJames Wright //   c_tau     = stabilization constant (0.5 is reported as "optimal")
2423a8779fbSJames Wright //   h[i]      = 2 length(dxdX[i])
2433a8779fbSJames Wright //   Pe        = Peclet number ( Pe = sqrt(u u) / dot(dXdx,u) diffusivity )
2443a8779fbSJames Wright //   Xi(Pe)    = coth Pe - 1. / Pe (1. at large local Peclet number )
2453a8779fbSJames Wright //   rho(A[i]) = spectral radius of the convective flux Jacobian i,
2463a8779fbSJames Wright //               wave speed in direction i
2473a8779fbSJames Wright // *****************************************************************************
2483a8779fbSJames Wright CEED_QFUNCTION_HELPER void Tau_spatial(CeedScalar Tau_x[3],
2493a8779fbSJames Wright                                        const CeedScalar dXdx[3][3], const CeedScalar u[3],
250bb8a0c61SJames Wright                                        /* const CeedScalar sound_speed, const CeedScalar c_tau) { */
251bb8a0c61SJames Wright                                        const CeedScalar sound_speed, const CeedScalar c_tau,
252bb8a0c61SJames Wright                                        const CeedScalar viscosity) {
253bb8a0c61SJames Wright   const CeedScalar mag_u_visc = sqrt(u[0]*u[0] +u[1]*u[1] +u[2]*u[2]) /
254bb8a0c61SJames Wright                                 (2*viscosity);
2553a8779fbSJames Wright   for (int i=0; i<3; i++) {
2563a8779fbSJames Wright     // length of element in direction i
2573a8779fbSJames Wright     CeedScalar h = 2 / sqrt(dXdx[0][i]*dXdx[0][i] + dXdx[1][i]*dXdx[1][i] +
2583a8779fbSJames Wright                             dXdx[2][i]*dXdx[2][i]);
259bb8a0c61SJames Wright     CeedScalar Pe = mag_u_visc*h;
260bb8a0c61SJames Wright     CeedScalar Xi = 1/tanh(Pe) - 1/Pe;
2613a8779fbSJames Wright     // fastest wave in direction i
2623a8779fbSJames Wright     CeedScalar fastest_wave = fabs(u[i]) + sound_speed;
263bb8a0c61SJames Wright     Tau_x[i] = c_tau * h * Xi / fastest_wave;
2643a8779fbSJames Wright   }
2653a8779fbSJames Wright }
2663a8779fbSJames Wright 
2673a8779fbSJames Wright // *****************************************************************************
2683a8779fbSJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems
2693a8779fbSJames Wright // *****************************************************************************
2703a8779fbSJames Wright CEED_QFUNCTION(ICsNewtonianIG)(void *ctx, CeedInt Q,
2713a8779fbSJames Wright                                const CeedScalar *const *in, CeedScalar *const *out) {
2723a8779fbSJames Wright   // Inputs
2733a8779fbSJames Wright   const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
2743a8779fbSJames Wright 
2753a8779fbSJames Wright   // Outputs
2763a8779fbSJames Wright   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
2773a8779fbSJames Wright 
278bb8a0c61SJames Wright   // Context
279bb8a0c61SJames Wright   const SetupContext context = (SetupContext)ctx;
280bb8a0c61SJames Wright   const CeedScalar theta0    = context->theta0;
281bb8a0c61SJames Wright   const CeedScalar P0        = context->P0;
282bb8a0c61SJames Wright   const CeedScalar cv        = context->cv;
283bb8a0c61SJames Wright   const CeedScalar cp        = context->cp;
284bb8a0c61SJames Wright   const CeedScalar *g        = context->g;
285bb8a0c61SJames Wright   const CeedScalar Rd        = cp - cv;
286bb8a0c61SJames Wright 
2873a8779fbSJames Wright   // Quadrature Point Loop
2883a8779fbSJames Wright   CeedPragmaSIMD
2893a8779fbSJames Wright   for (CeedInt i=0; i<Q; i++) {
2903a8779fbSJames Wright     CeedScalar q[5] = {0.};
2913a8779fbSJames Wright 
2923a8779fbSJames Wright     // Setup
2933a8779fbSJames Wright     // -- Coordinates
294bb8a0c61SJames Wright     const CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]};
295bb8a0c61SJames Wright     const CeedScalar e_potential = -(g[0]*x[0] + g[1]*x[1] + g[2]*x[2]);
2963a8779fbSJames Wright 
2973a8779fbSJames Wright     // -- Density
298bb8a0c61SJames Wright     const CeedScalar rho = P0 / (Rd*theta0);
2993a8779fbSJames Wright 
3003a8779fbSJames Wright     // Initial Conditions
3013a8779fbSJames Wright     q[0] = rho;
3023a8779fbSJames Wright     q[1] = 0.0;
3033a8779fbSJames Wright     q[2] = 0.0;
3043a8779fbSJames Wright     q[3] = 0.0;
305bb8a0c61SJames Wright     q[4] = rho * (cv*theta0 + e_potential);
3063a8779fbSJames Wright 
3073a8779fbSJames Wright     for (CeedInt j=0; j<5; j++)
3083a8779fbSJames Wright       q0[j][i] = q[j];
3093a8779fbSJames Wright   } // End of Quadrature Point Loop
3103a8779fbSJames Wright   return 0;
3113a8779fbSJames Wright }
3123a8779fbSJames Wright 
3133a8779fbSJames Wright // *****************************************************************************
3143a8779fbSJames Wright // This QFunction implements the following formulation of Navier-Stokes with
3153a8779fbSJames Wright //   explicit time stepping method
3163a8779fbSJames Wright //
3173a8779fbSJames Wright // This is 3D compressible Navier-Stokes in conservation form with state
3183a8779fbSJames Wright //   variables of density, momentum density, and total energy density.
3193a8779fbSJames Wright //
3203a8779fbSJames Wright // State Variables: q = ( rho, U1, U2, U3, E )
3213a8779fbSJames Wright //   rho - Mass Density
3223a8779fbSJames Wright //   Ui  - Momentum Density,      Ui = rho ui
3233a8779fbSJames Wright //   E   - Total Energy Density,  E  = rho (cv T + (u u)/2 + g z)
3243a8779fbSJames Wright //
3253a8779fbSJames Wright // Navier-Stokes Equations:
3263a8779fbSJames Wright //   drho/dt + div( U )                               = 0
3273a8779fbSJames Wright //   dU/dt   + div( rho (u x u) + P I3 ) + rho g khat = div( Fu )
3283a8779fbSJames Wright //   dE/dt   + div( (E + P) u )                       = div( Fe )
3293a8779fbSJames Wright //
3303a8779fbSJames Wright // Viscous Stress:
3313a8779fbSJames Wright //   Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3)
3323a8779fbSJames Wright //
3333a8779fbSJames Wright // Thermal Stress:
3343a8779fbSJames Wright //   Fe = u Fu + k grad( T )
335bb8a0c61SJames Wright // Equation of State
3363a8779fbSJames Wright //   P = (gamma - 1) (E - rho (u u) / 2 - rho g z)
3373a8779fbSJames Wright //
3383a8779fbSJames Wright // Stabilization:
3393a8779fbSJames Wright //   Tau = diag(TauC, TauM, TauM, TauM, TauE)
3403a8779fbSJames Wright //     f1 = rho  sqrt(ui uj gij)
3413a8779fbSJames Wright //     gij = dXi/dX * dXi/dX
3423a8779fbSJames Wright //     TauC = Cc f1 / (8 gii)
3433a8779fbSJames Wright //     TauM = min( 1 , 1 / f1 )
3443a8779fbSJames Wright //     TauE = TauM / (Ce cv)
3453a8779fbSJames Wright //
3463a8779fbSJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
3473a8779fbSJames Wright //
3483a8779fbSJames Wright // Constants:
3493a8779fbSJames Wright //   lambda = - 2 / 3,  From Stokes hypothesis
3503a8779fbSJames Wright //   mu              ,  Dynamic viscosity
3513a8779fbSJames Wright //   k               ,  Thermal conductivity
3523a8779fbSJames Wright //   cv              ,  Specific heat, constant volume
3533a8779fbSJames Wright //   cp              ,  Specific heat, constant pressure
3543a8779fbSJames Wright //   g               ,  Gravity
3553a8779fbSJames Wright //   gamma  = cp / cv,  Specific heat ratio
3563a8779fbSJames Wright //
3573a8779fbSJames Wright // We require the product of the inverse of the Jacobian (dXdx_j,k) and
3583a8779fbSJames Wright // its transpose (dXdx_k,j) to properly compute integrals of the form:
3593a8779fbSJames Wright // int( gradv gradu )
3603a8779fbSJames Wright //
3613a8779fbSJames Wright // *****************************************************************************
3623a8779fbSJames Wright CEED_QFUNCTION(Newtonian)(void *ctx, CeedInt Q,
3633a8779fbSJames Wright                           const CeedScalar *const *in, CeedScalar *const *out) {
3643a8779fbSJames Wright   // *INDENT-OFF*
3653a8779fbSJames Wright   // Inputs
3663a8779fbSJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
3673a8779fbSJames Wright                    (*dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
3683a8779fbSJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
3693a8779fbSJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3];
3703a8779fbSJames Wright   // Outputs
3713a8779fbSJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
3723a8779fbSJames Wright              (*dv)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
3733a8779fbSJames Wright   // *INDENT-ON*
3743a8779fbSJames Wright 
3753a8779fbSJames Wright   // Context
3763a8779fbSJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
3773a8779fbSJames Wright   const CeedScalar lambda = context->lambda;
3783a8779fbSJames Wright   const CeedScalar mu     = context->mu;
3793a8779fbSJames Wright   const CeedScalar k      = context->k;
3803a8779fbSJames Wright   const CeedScalar cv     = context->cv;
3813a8779fbSJames Wright   const CeedScalar cp     = context->cp;
382bb8a0c61SJames Wright   const CeedScalar *g     = context->g;
383bb8a0c61SJames Wright   const CeedScalar dt     = context->dt;
3843a8779fbSJames Wright   const CeedScalar gamma  = cp / cv;
385bb8a0c61SJames Wright   const CeedScalar Rd     = cp - cv;
3863a8779fbSJames Wright 
3873a8779fbSJames Wright   CeedPragmaSIMD
3883a8779fbSJames Wright   // Quadrature Point Loop
3893a8779fbSJames Wright   for (CeedInt i=0; i<Q; i++) {
3903a8779fbSJames Wright     // *INDENT-OFF*
3913a8779fbSJames Wright     // Setup
3923a8779fbSJames Wright     // -- Interp in
3933a8779fbSJames Wright     const CeedScalar rho        =   q[0][i];
3943a8779fbSJames Wright     const CeedScalar u[3]       =  {q[1][i] / rho,
3953a8779fbSJames Wright                                     q[2][i] / rho,
3963a8779fbSJames Wright                                     q[3][i] / rho
3973a8779fbSJames Wright                                    };
3983a8779fbSJames Wright     const CeedScalar E          =   q[4][i];
3993a8779fbSJames Wright     // -- Grad in
4003a8779fbSJames Wright     const CeedScalar drho[3]    =  {dq[0][0][i],
4013a8779fbSJames Wright                                     dq[1][0][i],
4023a8779fbSJames Wright                                     dq[2][0][i]
4033a8779fbSJames Wright                                    };
4043a8779fbSJames Wright     const CeedScalar dU[3][3]   = {{dq[0][1][i],
4053a8779fbSJames Wright                                     dq[1][1][i],
4063a8779fbSJames Wright                                     dq[2][1][i]},
4073a8779fbSJames Wright                                    {dq[0][2][i],
4083a8779fbSJames Wright                                     dq[1][2][i],
4093a8779fbSJames Wright                                     dq[2][2][i]},
4103a8779fbSJames Wright                                    {dq[0][3][i],
4113a8779fbSJames Wright                                     dq[1][3][i],
4123a8779fbSJames Wright                                     dq[2][3][i]}
4133a8779fbSJames Wright                                   };
4143a8779fbSJames Wright     const CeedScalar dE[3]      =  {dq[0][4][i],
4153a8779fbSJames Wright                                     dq[1][4][i],
4163a8779fbSJames Wright                                     dq[2][4][i]
4173a8779fbSJames Wright                                    };
4183a8779fbSJames Wright     // -- Interp-to-Interp q_data
4193a8779fbSJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
4203a8779fbSJames Wright     // -- Interp-to-Grad q_data
4213a8779fbSJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
4223a8779fbSJames Wright     // *INDENT-OFF*
4233a8779fbSJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
4243a8779fbSJames Wright                                     q_data[2][i],
4253a8779fbSJames Wright                                     q_data[3][i]},
4263a8779fbSJames Wright                                    {q_data[4][i],
4273a8779fbSJames Wright                                     q_data[5][i],
4283a8779fbSJames Wright                                     q_data[6][i]},
4293a8779fbSJames Wright                                    {q_data[7][i],
4303a8779fbSJames Wright                                     q_data[8][i],
4313a8779fbSJames Wright                                     q_data[9][i]}
4323a8779fbSJames Wright                                   };
433bb8a0c61SJames Wright     const CeedScalar x_i[3]       = {x[0][i], x[1][i], x[2][i]};
4343a8779fbSJames Wright     // *INDENT-ON*
4353a8779fbSJames Wright     // -- Grad-to-Grad q_data
4363a8779fbSJames Wright     // dU/dx
4373a8779fbSJames Wright     CeedScalar du[3][3] = {{0}};
4383a8779fbSJames Wright     CeedScalar drhodx[3] = {0};
4393a8779fbSJames Wright     CeedScalar dEdx[3] = {0};
4403a8779fbSJames Wright     CeedScalar dUdx[3][3] = {{0}};
4413a8779fbSJames Wright     CeedScalar dXdxdXdxT[3][3] = {{0}};
4423a8779fbSJames Wright     for (int j=0; j<3; j++) {
4433a8779fbSJames Wright       for (int k=0; k<3; k++) {
4443a8779fbSJames Wright         du[j][k] = (dU[j][k] - drho[k]*u[j]) / rho;
4453a8779fbSJames Wright         drhodx[j] += drho[k] * dXdx[k][j];
4463a8779fbSJames Wright         dEdx[j] += dE[k] * dXdx[k][j];
4473a8779fbSJames Wright         for (int l=0; l<3; l++) {
4483a8779fbSJames Wright           dUdx[j][k] += dU[j][l] * dXdx[l][k];
4493a8779fbSJames Wright           dXdxdXdxT[j][k] += dXdx[j][l]*dXdx[k][l];  //dXdx_j,k * dXdx_k,j
4503a8779fbSJames Wright         }
4513a8779fbSJames Wright       }
4523a8779fbSJames Wright     }
4533a8779fbSJames Wright     CeedScalar dudx[3][3] = {{0}};
4543a8779fbSJames Wright     for (int j=0; j<3; j++)
4553a8779fbSJames Wright       for (int k=0; k<3; k++)
4563a8779fbSJames Wright         for (int l=0; l<3; l++)
4573a8779fbSJames Wright           dudx[j][k] += du[j][l] * dXdx[l][k];
4583a8779fbSJames Wright     // -- grad_T
4593a8779fbSJames Wright     const CeedScalar grad_T[3]  = {(dEdx[0]/rho - E*drhodx[0]/(rho*rho) - /* *NOPAD* */
460bb8a0c61SJames Wright                                     (u[0]*dudx[0][0] + u[1]*dudx[1][0] + u[2]*dudx[2][0]) + g[0])/cv,
4613a8779fbSJames Wright                                    (dEdx[1]/rho - E*drhodx[1]/(rho*rho) - /* *NOPAD* */
462bb8a0c61SJames Wright                                     (u[0]*dudx[0][1] + u[1]*dudx[1][1] + u[2]*dudx[2][1]) + g[1])/cv,
4633a8779fbSJames Wright                                    (dEdx[2]/rho - E*drhodx[2]/(rho*rho) - /* *NOPAD* */
464bb8a0c61SJames Wright                                     (u[0]*dudx[0][2] + u[1]*dudx[1][2] + u[2]*dudx[2][2]) + g[2])/cv
4653a8779fbSJames Wright                                   };
4663a8779fbSJames Wright 
4673a8779fbSJames Wright     // -- Fuvisc
4683a8779fbSJames Wright     // ---- Symmetric 3x3 matrix
4693a8779fbSJames Wright     const CeedScalar Fu[6]     =  {mu*(dudx[0][0] * (2 + lambda) + /* *NOPAD* */
4703a8779fbSJames Wright                                        lambda * (dudx[1][1] + dudx[2][2])),
4713a8779fbSJames Wright                                    mu*(dudx[0][1] + dudx[1][0]), /* *NOPAD* */
4723a8779fbSJames Wright                                    mu*(dudx[0][2] + dudx[2][0]), /* *NOPAD* */
4733a8779fbSJames Wright                                    mu*(dudx[1][1] * (2 + lambda) + /* *NOPAD* */
4743a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[2][2])),
4753a8779fbSJames Wright                                    mu*(dudx[1][2] + dudx[2][1]), /* *NOPAD* */
4763a8779fbSJames Wright                                    mu*(dudx[2][2] * (2 + lambda) + /* *NOPAD* */
4773a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[1][1]))
4783a8779fbSJames Wright                                   };
4793a8779fbSJames Wright     // -- Fevisc
4803a8779fbSJames Wright     const CeedScalar Fe[3]     =  {u[0]*Fu[0] + u[1]*Fu[1] + u[2]*Fu[2] + /* *NOPAD* */
4813a8779fbSJames Wright                                    k*grad_T[0], /* *NOPAD* */
4823a8779fbSJames Wright                                    u[0]*Fu[1] + u[1]*Fu[3] + u[2]*Fu[4] + /* *NOPAD* */
4833a8779fbSJames Wright                                    k*grad_T[1], /* *NOPAD* */
4843a8779fbSJames Wright                                    u[0]*Fu[2] + u[1]*Fu[4] + u[2]*Fu[5] + /* *NOPAD* */
4853a8779fbSJames Wright                                    k*grad_T[2] /* *NOPAD* */
4863a8779fbSJames Wright                                   };
4873a8779fbSJames Wright     // Pressure
4883a8779fbSJames Wright     const CeedScalar
4893a8779fbSJames Wright     E_kinetic   = 0.5 * rho * (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]),
490bb8a0c61SJames Wright     E_potential = -rho*(g[0]*x_i[0] + g[1]*x_i[1] + g[2]*x_i[2]),
4913a8779fbSJames Wright     E_internal  = E - E_kinetic - E_potential,
4923a8779fbSJames Wright     P           = E_internal * (gamma - 1.); // P = pressure
4933a8779fbSJames Wright 
4943a8779fbSJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
4953a8779fbSJames Wright     CeedScalar jacob_F_conv[3][5][5] = {{{0.}}};
496bb8a0c61SJames Wright     computeFluxJacobian_NS(jacob_F_conv, rho, u, E, gamma, g, x_i);
4973a8779fbSJames Wright 
4983a8779fbSJames Wright     // dqdx collects drhodx, dUdx and dEdx in one vector
4993a8779fbSJames Wright     CeedScalar dqdx[5][3];
5003a8779fbSJames Wright     for (int j=0; j<3; j++) {
5013a8779fbSJames Wright       dqdx[0][j] = drhodx[j];
5023a8779fbSJames Wright       dqdx[4][j] = dEdx[j];
5033a8779fbSJames Wright       for (int k=0; k<3; k++)
5043a8779fbSJames Wright         dqdx[k+1][j] = dUdx[k][j];
5053a8779fbSJames Wright     }
5063a8779fbSJames Wright 
5073a8779fbSJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
5083a8779fbSJames Wright     CeedScalar strong_conv[5] = {0};
5093a8779fbSJames Wright     for (int j=0; j<3; j++)
5103a8779fbSJames Wright       for (int k=0; k<5; k++)
5113a8779fbSJames Wright         for (int l=0; l<5; l++)
5123a8779fbSJames Wright           strong_conv[k] += jacob_F_conv[j][k][l] * dqdx[l][j];
5133a8779fbSJames Wright 
5143a8779fbSJames Wright     // Body force
515bb8a0c61SJames Wright     const CeedScalar body_force[5] = {0, rho *g[0], rho *g[1], rho *g[2], 0};
5163a8779fbSJames Wright 
5173a8779fbSJames Wright     // The Physics
5183a8779fbSJames Wright     // Zero dv so all future terms can safely sum into it
5193a8779fbSJames Wright     for (int j=0; j<5; j++)
5203a8779fbSJames Wright       for (int k=0; k<3; k++)
5213a8779fbSJames Wright         dv[k][j][i] = 0;
5223a8779fbSJames Wright 
5233a8779fbSJames Wright     // -- Density
5243a8779fbSJames Wright     // ---- u rho
5253a8779fbSJames Wright     for (int j=0; j<3; j++)
5263a8779fbSJames Wright       dv[j][0][i]  += wdetJ*(rho*u[0]*dXdx[j][0] + rho*u[1]*dXdx[j][1] +
5273a8779fbSJames Wright                              rho*u[2]*dXdx[j][2]);
5283a8779fbSJames Wright     // -- Momentum
5293a8779fbSJames Wright     // ---- rho (u x u) + P I3
5303a8779fbSJames Wright     for (int j=0; j<3; j++)
5313a8779fbSJames Wright       for (int k=0; k<3; k++)
5323a8779fbSJames Wright         dv[k][j+1][i]  += wdetJ*((rho*u[j]*u[0] + (j==0?P:0))*dXdx[k][0] +
5333a8779fbSJames Wright                                  (rho*u[j]*u[1] + (j==1?P:0))*dXdx[k][1] +
5343a8779fbSJames Wright                                  (rho*u[j]*u[2] + (j==2?P:0))*dXdx[k][2]);
5353a8779fbSJames Wright     // ---- Fuvisc
5363a8779fbSJames Wright     const CeedInt Fuviscidx[3][3] = {{0, 1, 2}, {1, 3, 4}, {2, 4, 5}}; // symmetric matrix indices
5373a8779fbSJames Wright     for (int j=0; j<3; j++)
5383a8779fbSJames Wright       for (int k=0; k<3; k++)
5393a8779fbSJames Wright         dv[k][j+1][i] -= wdetJ*(Fu[Fuviscidx[j][0]]*dXdx[k][0] +
5403a8779fbSJames Wright                                 Fu[Fuviscidx[j][1]]*dXdx[k][1] +
5413a8779fbSJames Wright                                 Fu[Fuviscidx[j][2]]*dXdx[k][2]);
5423a8779fbSJames Wright     // -- Total Energy Density
5433a8779fbSJames Wright     // ---- (E + P) u
5443a8779fbSJames Wright     for (int j=0; j<3; j++)
5453a8779fbSJames Wright       dv[j][4][i]  += wdetJ * (E + P) * (u[0]*dXdx[j][0] + u[1]*dXdx[j][1] +
5463a8779fbSJames Wright                                          u[2]*dXdx[j][2]);
5473a8779fbSJames Wright     // ---- Fevisc
5483a8779fbSJames Wright     for (int j=0; j<3; j++)
5493a8779fbSJames Wright       dv[j][4][i] -= wdetJ * (Fe[0]*dXdx[j][0] + Fe[1]*dXdx[j][1] +
5503a8779fbSJames Wright                               Fe[2]*dXdx[j][2]);
5513a8779fbSJames Wright     // Body Force
5523a8779fbSJames Wright     for (int j=0; j<5; j++)
5533a8779fbSJames Wright       v[j][i] = wdetJ * body_force[j];
5543a8779fbSJames Wright 
555bb8a0c61SJames Wright     // Spatial Stabilization
556bb8a0c61SJames Wright     // -- Not used in favor of diagonal tau. Kept for future testing
557bb8a0c61SJames Wright     // const CeedScalar sound_speed = sqrt(gamma * P / rho);
558bb8a0c61SJames Wright     // CeedScalar Tau_x[3] = {0.};
559bb8a0c61SJames Wright     // Tau_spatial(Tau_x, dXdx, u, sound_speed, context->c_tau, mu);
5603a8779fbSJames Wright 
561bb8a0c61SJames Wright     // -- Stabilization method: none, SU, or SUPG
562bb8a0c61SJames Wright     CeedScalar stab[5][3] = {{0.}};
563bb8a0c61SJames Wright     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
564bb8a0c61SJames Wright     CeedScalar Tau_d[3] = {0.};
5653a8779fbSJames Wright     switch (context->stabilization) {
5663a8779fbSJames Wright     case STAB_NONE:        // Galerkin
5673a8779fbSJames Wright       break;
5683a8779fbSJames Wright     case STAB_SU:        // SU
569bb8a0c61SJames Wright       Tau_diagPrim(Tau_d, dXdx, u, cv, context, mu, dt, rho);
570bb8a0c61SJames Wright       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
571bb8a0c61SJames Wright       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
572bb8a0c61SJames Wright       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
573bb8a0c61SJames Wright       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
574bb8a0c61SJames Wright       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
575bb8a0c61SJames Wright       PrimitiveToConservative_fwd(rho, u, E, Rd, cv, tau_strong_conv,
576bb8a0c61SJames Wright                                   tau_strong_conv_conservative);
5773a8779fbSJames Wright       for (int j=0; j<3; j++)
5783a8779fbSJames Wright         for (int k=0; k<5; k++)
5793a8779fbSJames Wright           for (int l=0; l<5; l++)
580bb8a0c61SJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
5813a8779fbSJames Wright 
5823a8779fbSJames Wright       for (int j=0; j<5; j++)
5833a8779fbSJames Wright         for (int k=0; k<3; k++)
5843a8779fbSJames Wright           dv[k][j][i] -= wdetJ*(stab[j][0] * dXdx[k][0] +
5853a8779fbSJames Wright                                 stab[j][1] * dXdx[k][1] +
5863a8779fbSJames Wright                                 stab[j][2] * dXdx[k][2]);
5873a8779fbSJames Wright       break;
5883a8779fbSJames Wright     case STAB_SUPG:        // SUPG is not implemented for explicit scheme
5893a8779fbSJames Wright       break;
5903a8779fbSJames Wright     }
5913a8779fbSJames Wright 
5923a8779fbSJames Wright   } // End Quadrature Point Loop
5933a8779fbSJames Wright 
5943a8779fbSJames Wright   // Return
5953a8779fbSJames Wright   return 0;
5963a8779fbSJames Wright }
5973a8779fbSJames Wright 
5983a8779fbSJames Wright // *****************************************************************************
5993a8779fbSJames Wright // This QFunction implements the Navier-Stokes equations (mentioned above) with
6003a8779fbSJames Wright //   implicit time stepping method
6013a8779fbSJames Wright //
6023a8779fbSJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
6033a8779fbSJames Wright //  SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) )
6043a8779fbSJames Wright //                                       (diffussive terms will be added later)
6053a8779fbSJames Wright //
6063a8779fbSJames Wright // *****************************************************************************
6073a8779fbSJames Wright CEED_QFUNCTION(IFunction_Newtonian)(void *ctx, CeedInt Q,
6083a8779fbSJames Wright                                     const CeedScalar *const *in,
6093a8779fbSJames Wright                                     CeedScalar *const *out) {
6103a8779fbSJames Wright   // *INDENT-OFF*
6113a8779fbSJames Wright   // Inputs
6123a8779fbSJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
6133a8779fbSJames Wright                    (*dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
6143a8779fbSJames Wright                    (*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
6153a8779fbSJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
6163a8779fbSJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
6173a8779fbSJames Wright   // Outputs
6183a8779fbSJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
6193a8779fbSJames Wright              (*dv)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
6203a8779fbSJames Wright   // *INDENT-ON*
6213a8779fbSJames Wright   // Context
6223a8779fbSJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
6233a8779fbSJames Wright   const CeedScalar lambda = context->lambda;
6243a8779fbSJames Wright   const CeedScalar mu     = context->mu;
6253a8779fbSJames Wright   const CeedScalar k      = context->k;
6263a8779fbSJames Wright   const CeedScalar cv     = context->cv;
6273a8779fbSJames Wright   const CeedScalar cp     = context->cp;
628bb8a0c61SJames Wright   const CeedScalar *g     = context->g;
629bb8a0c61SJames Wright   const CeedScalar dt     = context->dt;
6303a8779fbSJames Wright   const CeedScalar gamma  = cp / cv;
631bb8a0c61SJames Wright   const CeedScalar Rd     = cp-cv;
6323a8779fbSJames Wright 
6333a8779fbSJames Wright   CeedPragmaSIMD
6343a8779fbSJames Wright   // Quadrature Point Loop
6353a8779fbSJames Wright   for (CeedInt i=0; i<Q; i++) {
6363a8779fbSJames Wright     // Setup
6373a8779fbSJames Wright     // -- Interp in
6383a8779fbSJames Wright     const CeedScalar rho        =   q[0][i];
6393a8779fbSJames Wright     const CeedScalar u[3]       =  {q[1][i] / rho,
6403a8779fbSJames Wright                                     q[2][i] / rho,
6413a8779fbSJames Wright                                     q[3][i] / rho
6423a8779fbSJames Wright                                    };
6433a8779fbSJames Wright     const CeedScalar E          =   q[4][i];
6443a8779fbSJames Wright     // -- Grad in
6453a8779fbSJames Wright     const CeedScalar drho[3]    =  {dq[0][0][i],
6463a8779fbSJames Wright                                     dq[1][0][i],
6473a8779fbSJames Wright                                     dq[2][0][i]
6483a8779fbSJames Wright                                    };
6493a8779fbSJames Wright     // *INDENT-OFF*
6503a8779fbSJames Wright     const CeedScalar dU[3][3]   = {{dq[0][1][i],
6513a8779fbSJames Wright                                     dq[1][1][i],
6523a8779fbSJames Wright                                     dq[2][1][i]},
6533a8779fbSJames Wright                                    {dq[0][2][i],
6543a8779fbSJames Wright                                     dq[1][2][i],
6553a8779fbSJames Wright                                     dq[2][2][i]},
6563a8779fbSJames Wright                                    {dq[0][3][i],
6573a8779fbSJames Wright                                     dq[1][3][i],
6583a8779fbSJames Wright                                     dq[2][3][i]}
6593a8779fbSJames Wright                                   };
6603a8779fbSJames Wright     // *INDENT-ON*
6613a8779fbSJames Wright     const CeedScalar dE[3]      =  {dq[0][4][i],
6623a8779fbSJames Wright                                     dq[1][4][i],
6633a8779fbSJames Wright                                     dq[2][4][i]
6643a8779fbSJames Wright                                    };
6653a8779fbSJames Wright     // -- Interp-to-Interp q_data
6663a8779fbSJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
6673a8779fbSJames Wright     // -- Interp-to-Grad q_data
6683a8779fbSJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
6693a8779fbSJames Wright     // *INDENT-OFF*
6703a8779fbSJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
6713a8779fbSJames Wright                                     q_data[2][i],
6723a8779fbSJames Wright                                     q_data[3][i]},
6733a8779fbSJames Wright                                    {q_data[4][i],
6743a8779fbSJames Wright                                     q_data[5][i],
6753a8779fbSJames Wright                                     q_data[6][i]},
6763a8779fbSJames Wright                                    {q_data[7][i],
6773a8779fbSJames Wright                                     q_data[8][i],
6783a8779fbSJames Wright                                     q_data[9][i]}
6793a8779fbSJames Wright                                   };
680bb8a0c61SJames Wright     const CeedScalar x_i[3]     = {x[0][i], x[1][i], x[2][i]};
6813a8779fbSJames Wright     // *INDENT-ON*
6823a8779fbSJames Wright     // -- Grad-to-Grad q_data
6833a8779fbSJames Wright     // dU/dx
6843a8779fbSJames Wright     CeedScalar du[3][3] = {{0}};
6853a8779fbSJames Wright     CeedScalar drhodx[3] = {0};
6863a8779fbSJames Wright     CeedScalar dEdx[3] = {0};
6873a8779fbSJames Wright     CeedScalar dUdx[3][3] = {{0}};
6883a8779fbSJames Wright     CeedScalar dXdxdXdxT[3][3] = {{0}};
6893a8779fbSJames Wright     for (int j=0; j<3; j++) {
6903a8779fbSJames Wright       for (int k=0; k<3; k++) {
6913a8779fbSJames Wright         du[j][k] = (dU[j][k] - drho[k]*u[j]) / rho;
6923a8779fbSJames Wright         drhodx[j] += drho[k] * dXdx[k][j];
6933a8779fbSJames Wright         dEdx[j] += dE[k] * dXdx[k][j];
6943a8779fbSJames Wright         for (int l=0; l<3; l++) {
6953a8779fbSJames Wright           dUdx[j][k] += dU[j][l] * dXdx[l][k];
6963a8779fbSJames Wright           dXdxdXdxT[j][k] += dXdx[j][l]*dXdx[k][l];  //dXdx_j,k * dXdx_k,j
6973a8779fbSJames Wright         }
6983a8779fbSJames Wright       }
6993a8779fbSJames Wright     }
7003a8779fbSJames Wright     CeedScalar dudx[3][3] = {{0}};
7013a8779fbSJames Wright     for (int j=0; j<3; j++)
7023a8779fbSJames Wright       for (int k=0; k<3; k++)
7033a8779fbSJames Wright         for (int l=0; l<3; l++)
7043a8779fbSJames Wright           dudx[j][k] += du[j][l] * dXdx[l][k];
7053a8779fbSJames Wright     // -- grad_T
7063a8779fbSJames Wright     const CeedScalar grad_T[3]  = {(dEdx[0]/rho - E*drhodx[0]/(rho*rho) - /* *NOPAD* */
707bb8a0c61SJames Wright                                     (u[0]*dudx[0][0] + u[1]*dudx[1][0] + u[2]*dudx[2][0]) + g[0])/cv,
7083a8779fbSJames Wright                                    (dEdx[1]/rho - E*drhodx[1]/(rho*rho) - /* *NOPAD* */
709bb8a0c61SJames Wright                                     (u[0]*dudx[0][1] + u[1]*dudx[1][1] + u[2]*dudx[2][1]) + g[1])/cv,
7103a8779fbSJames Wright                                    (dEdx[2]/rho - E*drhodx[2]/(rho*rho) - /* *NOPAD* */
711bb8a0c61SJames Wright                                     (u[0]*dudx[0][2] + u[1]*dudx[1][2] + u[2]*dudx[2][2]) + g[2])/cv
7123a8779fbSJames Wright                                   };
7133a8779fbSJames Wright     // -- Fuvisc
7143a8779fbSJames Wright     // ---- Symmetric 3x3 matrix
7153a8779fbSJames Wright     const CeedScalar Fu[6]     =  {mu*(dudx[0][0] * (2 + lambda) + /* *NOPAD* */
7163a8779fbSJames Wright                                        lambda * (dudx[1][1] + dudx[2][2])),
7173a8779fbSJames Wright                                    mu*(dudx[0][1] + dudx[1][0]), /* *NOPAD* */
7183a8779fbSJames Wright                                    mu*(dudx[0][2] + dudx[2][0]), /* *NOPAD* */
7193a8779fbSJames Wright                                    mu*(dudx[1][1] * (2 + lambda) + /* *NOPAD* */
7203a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[2][2])),
7213a8779fbSJames Wright                                    mu*(dudx[1][2] + dudx[2][1]), /* *NOPAD* */
7223a8779fbSJames Wright                                    mu*(dudx[2][2] * (2 + lambda) + /* *NOPAD* */
7233a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[1][1]))
7243a8779fbSJames Wright                                   };
7253a8779fbSJames Wright     // -- Fevisc
7263a8779fbSJames Wright     const CeedScalar Fe[3]     =  {u[0]*Fu[0] + u[1]*Fu[1] + u[2]*Fu[2] + /* *NOPAD* */
7273a8779fbSJames Wright                                    k*grad_T[0], /* *NOPAD* */
7283a8779fbSJames Wright                                    u[0]*Fu[1] + u[1]*Fu[3] + u[2]*Fu[4] + /* *NOPAD* */
7293a8779fbSJames Wright                                    k*grad_T[1], /* *NOPAD* */
7303a8779fbSJames Wright                                    u[0]*Fu[2] + u[1]*Fu[4] + u[2]*Fu[5] + /* *NOPAD* */
7313a8779fbSJames Wright                                    k*grad_T[2] /* *NOPAD* */
7323a8779fbSJames Wright                                   };
7333a8779fbSJames Wright     // Pressure
7343a8779fbSJames Wright     const CeedScalar
7353a8779fbSJames Wright     E_kinetic   = 0.5 * rho * (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]),
736bb8a0c61SJames Wright     E_potential = -rho*(g[0]*x_i[0] + g[1]*x_i[1] + g[2]*x_i[2]),
7373a8779fbSJames Wright     E_internal  = E - E_kinetic - E_potential,
7383a8779fbSJames Wright     P           = E_internal * (gamma - 1.); // P = pressure
7393a8779fbSJames Wright 
7403a8779fbSJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
7413a8779fbSJames Wright     CeedScalar jacob_F_conv[3][5][5] = {{{0.}}};
742bb8a0c61SJames Wright     computeFluxJacobian_NS(jacob_F_conv, rho, u, E, gamma, g, x_i);
7433a8779fbSJames Wright 
7443a8779fbSJames Wright     // dqdx collects drhodx, dUdx and dEdx in one vector
7453a8779fbSJames Wright     CeedScalar dqdx[5][3];
7463a8779fbSJames Wright     for (int j=0; j<3; j++) {
7473a8779fbSJames Wright       dqdx[0][j] = drhodx[j];
7483a8779fbSJames Wright       dqdx[4][j] = dEdx[j];
7493a8779fbSJames Wright       for (int k=0; k<3; k++)
7503a8779fbSJames Wright         dqdx[k+1][j] = dUdx[k][j];
7513a8779fbSJames Wright     }
7523a8779fbSJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
7533a8779fbSJames Wright     CeedScalar strong_conv[5] = {0};
7543a8779fbSJames Wright     for (int j=0; j<3; j++)
7553a8779fbSJames Wright       for (int k=0; k<5; k++)
7563a8779fbSJames Wright         for (int l=0; l<5; l++)
7573a8779fbSJames Wright           strong_conv[k] += jacob_F_conv[j][k][l] * dqdx[l][j];
7583a8779fbSJames Wright 
7593a8779fbSJames Wright     // Body force
760bb8a0c61SJames Wright     const CeedScalar body_force[5] = {0, rho *g[0], rho *g[1], rho *g[2], 0};
7613a8779fbSJames Wright 
7623a8779fbSJames Wright     // Strong residual
7633a8779fbSJames Wright     CeedScalar strong_res[5];
7643a8779fbSJames Wright     for (int j=0; j<5; j++)
7653a8779fbSJames Wright       strong_res[j] = q_dot[j][i] + strong_conv[j] - body_force[j];
7663a8779fbSJames Wright 
7673a8779fbSJames Wright     // The Physics
7683a8779fbSJames Wright     //-----mass matrix
7693a8779fbSJames Wright     for (int j=0; j<5; j++)
7703a8779fbSJames Wright       v[j][i] = wdetJ*q_dot[j][i];
7713a8779fbSJames Wright 
7723a8779fbSJames Wright     // Zero dv so all future terms can safely sum into it
7733a8779fbSJames Wright     for (int j=0; j<5; j++)
7743a8779fbSJames Wright       for (int k=0; k<3; k++)
7753a8779fbSJames Wright         dv[k][j][i] = 0;
7763a8779fbSJames Wright 
7773a8779fbSJames Wright     // -- Density
7783a8779fbSJames Wright     // ---- u rho
7793a8779fbSJames Wright     for (int j=0; j<3; j++)
7803a8779fbSJames Wright       dv[j][0][i]  -= wdetJ*(rho*u[0]*dXdx[j][0] + rho*u[1]*dXdx[j][1] +
7813a8779fbSJames Wright                              rho*u[2]*dXdx[j][2]);
7823a8779fbSJames Wright     // -- Momentum
7833a8779fbSJames Wright     // ---- rho (u x u) + P I3
7843a8779fbSJames Wright     for (int j=0; j<3; j++)
7853a8779fbSJames Wright       for (int k=0; k<3; k++)
7863a8779fbSJames Wright         dv[k][j+1][i]  -= wdetJ*((rho*u[j]*u[0] + (j==0?P:0))*dXdx[k][0] +
7873a8779fbSJames Wright                                  (rho*u[j]*u[1] + (j==1?P:0))*dXdx[k][1] +
7883a8779fbSJames Wright                                  (rho*u[j]*u[2] + (j==2?P:0))*dXdx[k][2]);
7893a8779fbSJames Wright     // ---- Fuvisc
7903a8779fbSJames Wright     const CeedInt Fuviscidx[3][3] = {{0, 1, 2}, {1, 3, 4}, {2, 4, 5}}; // symmetric matrix indices
7913a8779fbSJames Wright     for (int j=0; j<3; j++)
7923a8779fbSJames Wright       for (int k=0; k<3; k++)
7933a8779fbSJames Wright         dv[k][j+1][i] += wdetJ*(Fu[Fuviscidx[j][0]]*dXdx[k][0] +
7943a8779fbSJames Wright                                 Fu[Fuviscidx[j][1]]*dXdx[k][1] +
7953a8779fbSJames Wright                                 Fu[Fuviscidx[j][2]]*dXdx[k][2]);
7963a8779fbSJames Wright     // -- Total Energy Density
7973a8779fbSJames Wright     // ---- (E + P) u
7983a8779fbSJames Wright     for (int j=0; j<3; j++)
7993a8779fbSJames Wright       dv[j][4][i]  -= wdetJ * (E + P) * (u[0]*dXdx[j][0] + u[1]*dXdx[j][1] +
8003a8779fbSJames Wright                                          u[2]*dXdx[j][2]);
8013a8779fbSJames Wright     // ---- Fevisc
8023a8779fbSJames Wright     for (int j=0; j<3; j++)
8033a8779fbSJames Wright       dv[j][4][i] += wdetJ * (Fe[0]*dXdx[j][0] + Fe[1]*dXdx[j][1] +
8043a8779fbSJames Wright                               Fe[2]*dXdx[j][2]);
8053a8779fbSJames Wright     // Body Force
8063a8779fbSJames Wright     for (int j=0; j<5; j++)
8073a8779fbSJames Wright       v[j][i] -= wdetJ*body_force[j];
8083a8779fbSJames Wright 
809bb8a0c61SJames Wright     // Spatial Stabilization
810bb8a0c61SJames Wright     // -- Not used in favor of diagonal tau. Kept for future testing
811bb8a0c61SJames Wright     // const CeedScalar sound_speed = sqrt(gamma * P / rho);
812bb8a0c61SJames Wright     // CeedScalar Tau_x[3] = {0.};
813bb8a0c61SJames Wright     // Tau_spatial(Tau_x, dXdx, u, sound_speed, c_tau, mu);
8143a8779fbSJames Wright 
8153a8779fbSJames Wright     // -- Stabilization method: none, SU, or SUPG
816bb8a0c61SJames Wright     CeedScalar stab[5][3] = {{0.}};
817bb8a0c61SJames Wright     CeedScalar tau_strong_res[5] = {0.}, tau_strong_res_conservative[5] = {0};
818bb8a0c61SJames Wright     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
819bb8a0c61SJames Wright     CeedScalar Tau_d[3] = {0.};
8203a8779fbSJames Wright     switch (context->stabilization) {
8213a8779fbSJames Wright     case STAB_NONE:        // Galerkin
8223a8779fbSJames Wright       break;
8233a8779fbSJames Wright     case STAB_SU:        // SU
824bb8a0c61SJames Wright       Tau_diagPrim(Tau_d, dXdx, u, cv, context, mu, dt, rho);
825bb8a0c61SJames Wright       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
826bb8a0c61SJames Wright       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
827bb8a0c61SJames Wright       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
828bb8a0c61SJames Wright       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
829bb8a0c61SJames Wright       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
830bb8a0c61SJames Wright       PrimitiveToConservative_fwd(rho, u, E, Rd, cv, tau_strong_conv,
831bb8a0c61SJames Wright                                   tau_strong_conv_conservative);
8323a8779fbSJames Wright       for (int j=0; j<3; j++)
8333a8779fbSJames Wright         for (int k=0; k<5; k++)
8343a8779fbSJames Wright           for (int l=0; l<5; l++)
835bb8a0c61SJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
8363a8779fbSJames Wright 
8373a8779fbSJames Wright       for (int j=0; j<5; j++)
8383a8779fbSJames Wright         for (int k=0; k<3; k++)
8393a8779fbSJames Wright           dv[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
8403a8779fbSJames Wright                                 stab[j][1] * dXdx[k][1] +
8413a8779fbSJames Wright                                 stab[j][2] * dXdx[k][2]);
8423a8779fbSJames Wright       break;
8433a8779fbSJames Wright     case STAB_SUPG:        // SUPG
844bb8a0c61SJames Wright       Tau_diagPrim(Tau_d, dXdx, u, cv, context, mu, dt, rho);
845bb8a0c61SJames Wright       tau_strong_res[0] = Tau_d[0] * strong_res[0];
846bb8a0c61SJames Wright       tau_strong_res[1] = Tau_d[1] * strong_res[1];
847bb8a0c61SJames Wright       tau_strong_res[2] = Tau_d[1] * strong_res[2];
848bb8a0c61SJames Wright       tau_strong_res[3] = Tau_d[1] * strong_res[3];
849bb8a0c61SJames Wright       tau_strong_res[4] = Tau_d[2] * strong_res[4];
850bb8a0c61SJames Wright // Alternate route (useful later with primitive variable code)
851bb8a0c61SJames Wright // this function was verified against PHASTA for as IC that was as close as possible
852bb8a0c61SJames Wright //    computeFluxJacobian_NSp(jacob_F_conv_p, rho, u, E, Rd, cv);
853bb8a0c61SJames Wright // it has also been verified to compute a correct through the following
854bb8a0c61SJames Wright //   stab[k][j] += jacob_F_conv_p[j][k][l] * tau_strong_res[l] // flux Jacobian wrt primitive
855bb8a0c61SJames Wright // applied in the triple loop below
856bb8a0c61SJames Wright //  However, it is more flops than using the existing Jacobian wrt q after q_{,Y} viz
857bb8a0c61SJames Wright       PrimitiveToConservative_fwd(rho, u, E, Rd, cv, tau_strong_res,
858bb8a0c61SJames Wright                                   tau_strong_res_conservative);
8593a8779fbSJames Wright       for (int j=0; j<3; j++)
8603a8779fbSJames Wright         for (int k=0; k<5; k++)
8613a8779fbSJames Wright           for (int l=0; l<5; l++)
862bb8a0c61SJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_res_conservative[l];
8633a8779fbSJames Wright 
8643a8779fbSJames Wright       for (int j=0; j<5; j++)
8653a8779fbSJames Wright         for (int k=0; k<3; k++)
8663a8779fbSJames Wright           dv[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
8673a8779fbSJames Wright                                 stab[j][1] * dXdx[k][1] +
8683a8779fbSJames Wright                                 stab[j][2] * dXdx[k][2]);
8693a8779fbSJames Wright       break;
8703a8779fbSJames Wright     }
8713a8779fbSJames Wright 
8723a8779fbSJames Wright   } // End Quadrature Point Loop
8733a8779fbSJames Wright 
8743a8779fbSJames Wright   // Return
8753a8779fbSJames Wright   return 0;
8763a8779fbSJames Wright }
8773a8779fbSJames Wright // *****************************************************************************
8783a8779fbSJames Wright #endif // newtonian_h
879