xref: /honee/qfunctions/newtonian.h (revision 15a3537e9964f372164f639b6e497665c63d4d0c)
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>
17*15a3537eSJed Brown #include "newtonian_types.h"
183a8779fbSJames Wright 
193a8779fbSJames Wright #ifndef M_PI
203a8779fbSJames Wright #define M_PI    3.14159265358979323846
213a8779fbSJames Wright #endif
223a8779fbSJames Wright 
233a8779fbSJames Wright #ifndef setup_context_struct
243a8779fbSJames Wright #define setup_context_struct
253a8779fbSJames Wright typedef struct SetupContext_ *SetupContext;
263a8779fbSJames Wright struct SetupContext_ {
273a8779fbSJames Wright   CeedScalar theta0;
283a8779fbSJames Wright   CeedScalar thetaC;
293a8779fbSJames Wright   CeedScalar P0;
303a8779fbSJames Wright   CeedScalar N;
313a8779fbSJames Wright   CeedScalar cv;
323a8779fbSJames Wright   CeedScalar cp;
33bb8a0c61SJames Wright   CeedScalar g[3];
343a8779fbSJames Wright   CeedScalar rc;
353a8779fbSJames Wright   CeedScalar lx;
363a8779fbSJames Wright   CeedScalar ly;
373a8779fbSJames Wright   CeedScalar lz;
383a8779fbSJames Wright   CeedScalar center[3];
393a8779fbSJames Wright   CeedScalar dc_axis[3];
403a8779fbSJames Wright   CeedScalar wind[3];
413a8779fbSJames Wright   CeedScalar time;
423a8779fbSJames Wright   int wind_type;              // See WindType: 0=ROTATION, 1=TRANSLATION
433a8779fbSJames Wright   int bubble_type;            // See BubbleType: 0=SPHERE, 1=CYLINDER
443a8779fbSJames Wright   int bubble_continuity_type; // See BubbleContinuityType: 0=SMOOTH, 1=BACK_SHARP 2=THICK
453a8779fbSJames Wright };
463a8779fbSJames Wright #endif
473a8779fbSJames Wright 
483a8779fbSJames Wright // *****************************************************************************
493a8779fbSJames Wright // Helper function for computing flux Jacobian
503a8779fbSJames Wright // *****************************************************************************
513a8779fbSJames Wright CEED_QFUNCTION_HELPER void computeFluxJacobian_NS(CeedScalar dF[3][5][5],
523a8779fbSJames Wright     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
53bb8a0c61SJames Wright     const CeedScalar gamma, const CeedScalar g[3], const CeedScalar x[3]) {
543a8779fbSJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
55bb8a0c61SJames Wright   CeedScalar e_potential = -(g[0]*x[0] + g[1]*x[1] + g[2]*x[2]);
563a8779fbSJames Wright   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
573a8779fbSJames Wright     for (CeedInt j=0; j<3; j++) { // Rows of each Jacobian matrix
58bb8a0c61SJames Wright       dF[i][j+1][0] = ((i==j) ? ((gamma-1.)*(u_sq/2. - e_potential)) : 0.) -
59bb8a0c61SJames Wright                       u[i]*u[j];
603a8779fbSJames Wright       for (CeedInt k=0; k<3; k++) { // Columns of each Jacobian matrix
613a8779fbSJames Wright         dF[i][0][k+1]   = ((i==k) ? 1. : 0.);
623a8779fbSJames Wright         dF[i][j+1][k+1] = ((j==k) ? u[i] : 0.) +
633a8779fbSJames Wright                           ((i==k) ? u[j] : 0.) -
643a8779fbSJames Wright                           ((i==j) ? u[k] : 0.) * (gamma-1.);
653a8779fbSJames Wright         dF[i][4][k+1]   = ((i==k) ? (E*gamma/rho - (gamma-1.)*u_sq/2.) : 0.) -
663a8779fbSJames Wright                           (gamma-1.)*u[i]*u[k];
673a8779fbSJames Wright       }
683a8779fbSJames Wright       dF[i][j+1][4] = ((i==j) ? (gamma-1.) : 0.);
693a8779fbSJames Wright     }
703a8779fbSJames Wright     dF[i][4][0] = u[i] * ((gamma-1.)*u_sq - E*gamma/rho);
713a8779fbSJames Wright     dF[i][4][4] = u[i] * gamma;
723a8779fbSJames Wright   }
733a8779fbSJames Wright }
743a8779fbSJames Wright 
753a8779fbSJames Wright // *****************************************************************************
76bb8a0c61SJames Wright // Helper function for computing flux Jacobian of Primitive variables
77bb8a0c61SJames Wright // *****************************************************************************
78bb8a0c61SJames Wright CEED_QFUNCTION_HELPER void computeFluxJacobian_NSp(CeedScalar dF[3][5][5],
79bb8a0c61SJames Wright     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
80bb8a0c61SJames Wright     const CeedScalar Rd, const CeedScalar cv) {
81bb8a0c61SJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
82bb8a0c61SJames Wright   // TODO Add in gravity's contribution
83bb8a0c61SJames Wright 
84bb8a0c61SJames Wright   CeedScalar T    = ( E / rho - u_sq / 2. ) / cv;
85bb8a0c61SJames Wright   CeedScalar drdT = -rho / T;
86bb8a0c61SJames Wright   CeedScalar drdP = 1. / ( Rd * T);
87bb8a0c61SJames Wright   CeedScalar etot =  E / rho ;
88bb8a0c61SJames Wright   CeedScalar e2p  = drdP * etot + 1. ;
89bb8a0c61SJames Wright   CeedScalar e3p  = ( E  + rho * Rd * T );
90bb8a0c61SJames Wright   CeedScalar e4p  = drdT * etot + rho * cv ;
91bb8a0c61SJames Wright 
92bb8a0c61SJames Wright   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
93bb8a0c61SJames Wright     for (CeedInt j=0; j<3; j++) { // j counts F^{m_j}
94bb8a0c61SJames Wright //        [row][col] of A_i
95bb8a0c61SJames Wright       dF[i][j+1][0] = drdP * u[i] * u[j] + ((i==j) ? 1. : 0.); // F^{{m_j} wrt p
96bb8a0c61SJames Wright       for (CeedInt k=0; k<3; k++) { // k counts the wrt vel_k
972acc7cbcSKenneth E. Jansen         dF[i][0][k+1]   =  ((i==k) ? rho  : 0.);   // F^c wrt u_k
98bb8a0c61SJames Wright         dF[i][j+1][k+1] = (((j==k) ? u[i] : 0.) +  // F^m_j wrt u_k
99bb8a0c61SJames Wright                            ((i==k) ? u[j] : 0.) ) * rho;
100bb8a0c61SJames Wright         dF[i][4][k+1]   = rho * u[i] * u[k]
101bb8a0c61SJames Wright                           + ((i==k) ? e3p  : 0.) ; // F^e wrt u_k
102bb8a0c61SJames Wright       }
103bb8a0c61SJames Wright       dF[i][j+1][4] = drdT * u[i] * u[j]; // F^{m_j} wrt T
104bb8a0c61SJames Wright     }
105bb8a0c61SJames Wright     dF[i][4][0] = u[i] * e2p; // F^e wrt p
106bb8a0c61SJames Wright     dF[i][4][4] = u[i] * e4p; // F^e wrt T
107bb8a0c61SJames Wright     dF[i][0][0] = u[i] * drdP; // F^c wrt p
108bb8a0c61SJames Wright     dF[i][0][4] = u[i] * drdT; // F^c wrt T
109bb8a0c61SJames Wright   }
110bb8a0c61SJames Wright }
111bb8a0c61SJames Wright 
112bb8a0c61SJames Wright CEED_QFUNCTION_HELPER void PrimitiveToConservative_fwd(const CeedScalar rho,
113bb8a0c61SJames Wright     const CeedScalar u[3], const CeedScalar E, const CeedScalar Rd,
114bb8a0c61SJames Wright     const CeedScalar cv, const CeedScalar dY[5], CeedScalar dU[5]) {
115bb8a0c61SJames Wright   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
116bb8a0c61SJames Wright   CeedScalar T    = ( E / rho - u_sq / 2. ) / cv;
117bb8a0c61SJames Wright   CeedScalar drdT = -rho / T;
118bb8a0c61SJames Wright   CeedScalar drdP = 1. / ( Rd * T);
119bb8a0c61SJames Wright   dU[0] = drdP * dY[0] + drdT * dY[4];
120bb8a0c61SJames Wright   CeedScalar de_kinetic = 0;
121bb8a0c61SJames Wright   for (int i=0; i<3; i++) {
122bb8a0c61SJames Wright     dU[1+i] = dU[0] * u[i] + rho * dY[1+i];
123bb8a0c61SJames Wright     de_kinetic += u[i] * dY[1+i];
124bb8a0c61SJames Wright   }
125bb8a0c61SJames Wright   dU[4] = rho * cv * dY[4] + dU[0] * cv * T // internal energy: rho * e
126bb8a0c61SJames Wright           + rho * de_kinetic + .5 * dU[0] * u_sq; // kinetic energy: .5 * rho * |u|^2
127bb8a0c61SJames Wright }
128bb8a0c61SJames Wright 
129bb8a0c61SJames Wright // *****************************************************************************
130bb8a0c61SJames Wright // Helper function for computing Tau elements (stabilization constant)
131bb8a0c61SJames Wright //   Model from:
132bb8a0c61SJames Wright //     PHASTA
133bb8a0c61SJames Wright //
134bb8a0c61SJames Wright //   Tau[i] = itau=0 which is diagonal-Shakib (3 values still but not spatial)
135bb8a0c61SJames Wright //
136bb8a0c61SJames Wright // Where NOT UPDATED YET
137bb8a0c61SJames Wright // *****************************************************************************
138bb8a0c61SJames Wright CEED_QFUNCTION_HELPER void Tau_diagPrim(CeedScalar Tau_d[3],
139bb8a0c61SJames Wright                                         const CeedScalar dXdx[3][3], const CeedScalar u[3],
140bb8a0c61SJames Wright                                         const CeedScalar cv, const NewtonianIdealGasContext newt_ctx,
141bb8a0c61SJames Wright                                         const CeedScalar mu, const CeedScalar dt,
142bb8a0c61SJames Wright                                         const CeedScalar rho) {
143bb8a0c61SJames Wright   // Context
144bb8a0c61SJames Wright   const CeedScalar Ctau_t = newt_ctx->Ctau_t;
145bb8a0c61SJames Wright   const CeedScalar Ctau_v = newt_ctx->Ctau_v;
146bb8a0c61SJames Wright   const CeedScalar Ctau_C = newt_ctx->Ctau_C;
147bb8a0c61SJames Wright   const CeedScalar Ctau_M = newt_ctx->Ctau_M;
148bb8a0c61SJames Wright   const CeedScalar Ctau_E = newt_ctx->Ctau_E;
149bb8a0c61SJames Wright   CeedScalar gijd[6];
150bb8a0c61SJames Wright   CeedScalar tau;
151bb8a0c61SJames Wright   CeedScalar dts;
152bb8a0c61SJames Wright   CeedScalar fact;
153bb8a0c61SJames Wright 
154bb8a0c61SJames Wright   //*INDENT-OFF*
155bb8a0c61SJames Wright   gijd[0] =   dXdx[0][0] * dXdx[0][0]
156bb8a0c61SJames Wright             + dXdx[1][0] * dXdx[1][0]
157bb8a0c61SJames Wright             + dXdx[2][0] * dXdx[2][0];
158bb8a0c61SJames Wright 
159bb8a0c61SJames Wright   gijd[1] =   dXdx[0][0] * dXdx[0][1]
160bb8a0c61SJames Wright             + dXdx[1][0] * dXdx[1][1]
161bb8a0c61SJames Wright             + dXdx[2][0] * dXdx[2][1];
162bb8a0c61SJames Wright 
163bb8a0c61SJames Wright   gijd[2] =   dXdx[0][1] * dXdx[0][1]
164bb8a0c61SJames Wright             + dXdx[1][1] * dXdx[1][1]
165bb8a0c61SJames Wright             + dXdx[2][1] * dXdx[2][1];
166bb8a0c61SJames Wright 
167bb8a0c61SJames Wright   gijd[3] =   dXdx[0][0] * dXdx[0][2]
168bb8a0c61SJames Wright             + dXdx[1][0] * dXdx[1][2]
169bb8a0c61SJames Wright             + dXdx[2][0] * dXdx[2][2];
170bb8a0c61SJames Wright 
171bb8a0c61SJames Wright   gijd[4] =   dXdx[0][1] * dXdx[0][2]
172bb8a0c61SJames Wright             + dXdx[1][1] * dXdx[1][2]
173bb8a0c61SJames Wright             + dXdx[2][1] * dXdx[2][2];
174bb8a0c61SJames Wright 
175bb8a0c61SJames Wright   gijd[5] =   dXdx[0][2] * dXdx[0][2]
176bb8a0c61SJames Wright             + dXdx[1][2] * dXdx[1][2]
177bb8a0c61SJames Wright             + dXdx[2][2] * dXdx[2][2];
178bb8a0c61SJames Wright   //*INDENT-ON*
179bb8a0c61SJames Wright 
180bb8a0c61SJames Wright   dts = Ctau_t / dt ;
181bb8a0c61SJames Wright 
182bb8a0c61SJames Wright   tau = rho*rho*((4. * dts * dts)
183bb8a0c61SJames Wright                  + u[0] * ( u[0] * gijd[0] + 2. * ( u[1] * gijd[1] + u[2] * gijd[3]))
184bb8a0c61SJames Wright                  + u[1] * ( u[1] * gijd[2] + 2. *   u[2] * gijd[4])
185bb8a0c61SJames Wright                  + u[2] *   u[2] * gijd[5])
186bb8a0c61SJames Wright         + Ctau_v* mu * mu *
187bb8a0c61SJames Wright         (gijd[0]*gijd[0] + gijd[2]*gijd[2] + gijd[5]*gijd[5] +
188bb8a0c61SJames Wright          + 2. * (gijd[1]*gijd[1] + gijd[3]*gijd[3] + gijd[4]*gijd[4]));
189bb8a0c61SJames Wright 
190bb8a0c61SJames Wright   fact=sqrt(tau);
191bb8a0c61SJames Wright 
192bb8a0c61SJames Wright   Tau_d[0] = Ctau_C * fact / (rho*(gijd[0] + gijd[2] + gijd[5]))*0.125;
193bb8a0c61SJames Wright 
194bb8a0c61SJames Wright   Tau_d[1] = Ctau_M / fact;
195bb8a0c61SJames Wright   Tau_d[2] = Ctau_E / ( fact * cv );
196bb8a0c61SJames Wright 
197bb8a0c61SJames Wright // consider putting back the way I initially had it  Ctau_E * Tau_d[1] /cv
198bb8a0c61SJames Wright //  to avoid a division if the compiler is smart enough to see that cv IS
199bb8a0c61SJames Wright // a constant that it could invert once for all elements
200bb8a0c61SJames Wright // but in that case energy tau is scaled by the product of Ctau_E * Ctau_M
201bb8a0c61SJames Wright // OR we could absorb cv into Ctau_E but this puts more burden on user to
202bb8a0c61SJames Wright // know how to change constants with a change of fluid or units.  Same for
203bb8a0c61SJames Wright // Ctau_v * mu * mu IF AND ONLY IF we don't add viscosity law =f(T)
204bb8a0c61SJames Wright }
205bb8a0c61SJames Wright 
206bb8a0c61SJames Wright // *****************************************************************************
2073a8779fbSJames Wright // Helper function for computing Tau elements (stabilization constant)
2083a8779fbSJames Wright //   Model from:
2093a8779fbSJames Wright //     Stabilized Methods for Compressible Flows, Hughes et al 2010
2103a8779fbSJames Wright //
2113a8779fbSJames Wright //   Spatial criterion #2 - Tau is a 3x3 diagonal matrix
2123a8779fbSJames Wright //   Tau[i] = c_tau h[i] Xi(Pe) / rho(A[i]) (no sum)
2133a8779fbSJames Wright //
2143a8779fbSJames Wright // Where
2153a8779fbSJames Wright //   c_tau     = stabilization constant (0.5 is reported as "optimal")
2163a8779fbSJames Wright //   h[i]      = 2 length(dxdX[i])
2173a8779fbSJames Wright //   Pe        = Peclet number ( Pe = sqrt(u u) / dot(dXdx,u) diffusivity )
2183a8779fbSJames Wright //   Xi(Pe)    = coth Pe - 1. / Pe (1. at large local Peclet number )
2193a8779fbSJames Wright //   rho(A[i]) = spectral radius of the convective flux Jacobian i,
2203a8779fbSJames Wright //               wave speed in direction i
2213a8779fbSJames Wright // *****************************************************************************
2223a8779fbSJames Wright CEED_QFUNCTION_HELPER void Tau_spatial(CeedScalar Tau_x[3],
2233a8779fbSJames Wright                                        const CeedScalar dXdx[3][3], const CeedScalar u[3],
224bb8a0c61SJames Wright                                        /* const CeedScalar sound_speed, const CeedScalar c_tau) { */
225bb8a0c61SJames Wright                                        const CeedScalar sound_speed, const CeedScalar c_tau,
226bb8a0c61SJames Wright                                        const CeedScalar viscosity) {
227bb8a0c61SJames Wright   const CeedScalar mag_u_visc = sqrt(u[0]*u[0] +u[1]*u[1] +u[2]*u[2]) /
228bb8a0c61SJames Wright                                 (2*viscosity);
2293a8779fbSJames Wright   for (int i=0; i<3; i++) {
2303a8779fbSJames Wright     // length of element in direction i
2313a8779fbSJames Wright     CeedScalar h = 2 / sqrt(dXdx[0][i]*dXdx[0][i] + dXdx[1][i]*dXdx[1][i] +
2323a8779fbSJames Wright                             dXdx[2][i]*dXdx[2][i]);
233bb8a0c61SJames Wright     CeedScalar Pe = mag_u_visc*h;
234bb8a0c61SJames Wright     CeedScalar Xi = 1/tanh(Pe) - 1/Pe;
2353a8779fbSJames Wright     // fastest wave in direction i
2363a8779fbSJames Wright     CeedScalar fastest_wave = fabs(u[i]) + sound_speed;
237bb8a0c61SJames Wright     Tau_x[i] = c_tau * h * Xi / fastest_wave;
2383a8779fbSJames Wright   }
2393a8779fbSJames Wright }
2403a8779fbSJames Wright 
2413a8779fbSJames Wright // *****************************************************************************
2423a8779fbSJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems
2433a8779fbSJames Wright // *****************************************************************************
2443a8779fbSJames Wright CEED_QFUNCTION(ICsNewtonianIG)(void *ctx, CeedInt Q,
2453a8779fbSJames Wright                                const CeedScalar *const *in, CeedScalar *const *out) {
2463a8779fbSJames Wright   // Inputs
2473a8779fbSJames Wright   const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
2483a8779fbSJames Wright 
2493a8779fbSJames Wright   // Outputs
2503a8779fbSJames Wright   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
2513a8779fbSJames Wright 
252bb8a0c61SJames Wright   // Context
253bb8a0c61SJames Wright   const SetupContext context = (SetupContext)ctx;
254bb8a0c61SJames Wright   const CeedScalar theta0    = context->theta0;
255bb8a0c61SJames Wright   const CeedScalar P0        = context->P0;
256bb8a0c61SJames Wright   const CeedScalar cv        = context->cv;
257bb8a0c61SJames Wright   const CeedScalar cp        = context->cp;
258bb8a0c61SJames Wright   const CeedScalar *g        = context->g;
259bb8a0c61SJames Wright   const CeedScalar Rd        = cp - cv;
260bb8a0c61SJames Wright 
2613a8779fbSJames Wright   // Quadrature Point Loop
2623a8779fbSJames Wright   CeedPragmaSIMD
2633a8779fbSJames Wright   for (CeedInt i=0; i<Q; i++) {
2643a8779fbSJames Wright     CeedScalar q[5] = {0.};
2653a8779fbSJames Wright 
2663a8779fbSJames Wright     // Setup
2673a8779fbSJames Wright     // -- Coordinates
268bb8a0c61SJames Wright     const CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]};
269bb8a0c61SJames Wright     const CeedScalar e_potential = -(g[0]*x[0] + g[1]*x[1] + g[2]*x[2]);
2703a8779fbSJames Wright 
2713a8779fbSJames Wright     // -- Density
272bb8a0c61SJames Wright     const CeedScalar rho = P0 / (Rd*theta0);
2733a8779fbSJames Wright 
2743a8779fbSJames Wright     // Initial Conditions
2753a8779fbSJames Wright     q[0] = rho;
2763a8779fbSJames Wright     q[1] = 0.0;
2773a8779fbSJames Wright     q[2] = 0.0;
2783a8779fbSJames Wright     q[3] = 0.0;
279bb8a0c61SJames Wright     q[4] = rho * (cv*theta0 + e_potential);
2803a8779fbSJames Wright 
2813a8779fbSJames Wright     for (CeedInt j=0; j<5; j++)
2823a8779fbSJames Wright       q0[j][i] = q[j];
2833a8779fbSJames Wright   } // End of Quadrature Point Loop
2843a8779fbSJames Wright   return 0;
2853a8779fbSJames Wright }
2863a8779fbSJames Wright 
2873a8779fbSJames Wright // *****************************************************************************
2883a8779fbSJames Wright // This QFunction implements the following formulation of Navier-Stokes with
2893a8779fbSJames Wright //   explicit time stepping method
2903a8779fbSJames Wright //
2913a8779fbSJames Wright // This is 3D compressible Navier-Stokes in conservation form with state
2923a8779fbSJames Wright //   variables of density, momentum density, and total energy density.
2933a8779fbSJames Wright //
2943a8779fbSJames Wright // State Variables: q = ( rho, U1, U2, U3, E )
2953a8779fbSJames Wright //   rho - Mass Density
2963a8779fbSJames Wright //   Ui  - Momentum Density,      Ui = rho ui
2973a8779fbSJames Wright //   E   - Total Energy Density,  E  = rho (cv T + (u u)/2 + g z)
2983a8779fbSJames Wright //
2993a8779fbSJames Wright // Navier-Stokes Equations:
3003a8779fbSJames Wright //   drho/dt + div( U )                               = 0
3013a8779fbSJames Wright //   dU/dt   + div( rho (u x u) + P I3 ) + rho g khat = div( Fu )
3023a8779fbSJames Wright //   dE/dt   + div( (E + P) u )                       = div( Fe )
3033a8779fbSJames Wright //
3043a8779fbSJames Wright // Viscous Stress:
3053a8779fbSJames Wright //   Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3)
3063a8779fbSJames Wright //
3073a8779fbSJames Wright // Thermal Stress:
3083a8779fbSJames Wright //   Fe = u Fu + k grad( T )
309bb8a0c61SJames Wright // Equation of State
3103a8779fbSJames Wright //   P = (gamma - 1) (E - rho (u u) / 2 - rho g z)
3113a8779fbSJames Wright //
3123a8779fbSJames Wright // Stabilization:
3133a8779fbSJames Wright //   Tau = diag(TauC, TauM, TauM, TauM, TauE)
3143a8779fbSJames Wright //     f1 = rho  sqrt(ui uj gij)
3153a8779fbSJames Wright //     gij = dXi/dX * dXi/dX
3163a8779fbSJames Wright //     TauC = Cc f1 / (8 gii)
3173a8779fbSJames Wright //     TauM = min( 1 , 1 / f1 )
3183a8779fbSJames Wright //     TauE = TauM / (Ce cv)
3193a8779fbSJames Wright //
3203a8779fbSJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
3213a8779fbSJames Wright //
3223a8779fbSJames Wright // Constants:
3233a8779fbSJames Wright //   lambda = - 2 / 3,  From Stokes hypothesis
3243a8779fbSJames Wright //   mu              ,  Dynamic viscosity
3253a8779fbSJames Wright //   k               ,  Thermal conductivity
3263a8779fbSJames Wright //   cv              ,  Specific heat, constant volume
3273a8779fbSJames Wright //   cp              ,  Specific heat, constant pressure
3283a8779fbSJames Wright //   g               ,  Gravity
3293a8779fbSJames Wright //   gamma  = cp / cv,  Specific heat ratio
3303a8779fbSJames Wright //
3313a8779fbSJames Wright // We require the product of the inverse of the Jacobian (dXdx_j,k) and
3323a8779fbSJames Wright // its transpose (dXdx_k,j) to properly compute integrals of the form:
3333a8779fbSJames Wright // int( gradv gradu )
3343a8779fbSJames Wright //
3353a8779fbSJames Wright // *****************************************************************************
3363a8779fbSJames Wright CEED_QFUNCTION(Newtonian)(void *ctx, CeedInt Q,
3373a8779fbSJames Wright                           const CeedScalar *const *in, CeedScalar *const *out) {
3383a8779fbSJames Wright   // *INDENT-OFF*
3393a8779fbSJames Wright   // Inputs
3403a8779fbSJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
3413a8779fbSJames Wright                    (*dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
3423a8779fbSJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
3433a8779fbSJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3];
3443a8779fbSJames Wright   // Outputs
3453a8779fbSJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
3463a8779fbSJames Wright              (*dv)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
3473a8779fbSJames Wright   // *INDENT-ON*
3483a8779fbSJames Wright 
3493a8779fbSJames Wright   // Context
3503a8779fbSJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
3513a8779fbSJames Wright   const CeedScalar lambda = context->lambda;
3523a8779fbSJames Wright   const CeedScalar mu     = context->mu;
3533a8779fbSJames Wright   const CeedScalar k      = context->k;
3543a8779fbSJames Wright   const CeedScalar cv     = context->cv;
3553a8779fbSJames Wright   const CeedScalar cp     = context->cp;
356bb8a0c61SJames Wright   const CeedScalar *g     = context->g;
357bb8a0c61SJames Wright   const CeedScalar dt     = context->dt;
3583a8779fbSJames Wright   const CeedScalar gamma  = cp / cv;
359bb8a0c61SJames Wright   const CeedScalar Rd     = cp - cv;
3603a8779fbSJames Wright 
3613a8779fbSJames Wright   CeedPragmaSIMD
3623a8779fbSJames Wright   // Quadrature Point Loop
3633a8779fbSJames Wright   for (CeedInt i=0; i<Q; i++) {
3643a8779fbSJames Wright     // *INDENT-OFF*
3653a8779fbSJames Wright     // Setup
3663a8779fbSJames Wright     // -- Interp in
3673a8779fbSJames Wright     const CeedScalar rho        =   q[0][i];
3683a8779fbSJames Wright     const CeedScalar u[3]       =  {q[1][i] / rho,
3693a8779fbSJames Wright                                     q[2][i] / rho,
3703a8779fbSJames Wright                                     q[3][i] / rho
3713a8779fbSJames Wright                                    };
3723a8779fbSJames Wright     const CeedScalar E          =   q[4][i];
3733a8779fbSJames Wright     // -- Grad in
3743a8779fbSJames Wright     const CeedScalar drho[3]    =  {dq[0][0][i],
3753a8779fbSJames Wright                                     dq[1][0][i],
3763a8779fbSJames Wright                                     dq[2][0][i]
3773a8779fbSJames Wright                                    };
3783a8779fbSJames Wright     const CeedScalar dU[3][3]   = {{dq[0][1][i],
3793a8779fbSJames Wright                                     dq[1][1][i],
3803a8779fbSJames Wright                                     dq[2][1][i]},
3813a8779fbSJames Wright                                    {dq[0][2][i],
3823a8779fbSJames Wright                                     dq[1][2][i],
3833a8779fbSJames Wright                                     dq[2][2][i]},
3843a8779fbSJames Wright                                    {dq[0][3][i],
3853a8779fbSJames Wright                                     dq[1][3][i],
3863a8779fbSJames Wright                                     dq[2][3][i]}
3873a8779fbSJames Wright                                   };
3883a8779fbSJames Wright     const CeedScalar dE[3]      =  {dq[0][4][i],
3893a8779fbSJames Wright                                     dq[1][4][i],
3903a8779fbSJames Wright                                     dq[2][4][i]
3913a8779fbSJames Wright                                    };
3923a8779fbSJames Wright     // -- Interp-to-Interp q_data
3933a8779fbSJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
3943a8779fbSJames Wright     // -- Interp-to-Grad q_data
3953a8779fbSJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
3963a8779fbSJames Wright     // *INDENT-OFF*
3973a8779fbSJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
3983a8779fbSJames Wright                                     q_data[2][i],
3993a8779fbSJames Wright                                     q_data[3][i]},
4003a8779fbSJames Wright                                    {q_data[4][i],
4013a8779fbSJames Wright                                     q_data[5][i],
4023a8779fbSJames Wright                                     q_data[6][i]},
4033a8779fbSJames Wright                                    {q_data[7][i],
4043a8779fbSJames Wright                                     q_data[8][i],
4053a8779fbSJames Wright                                     q_data[9][i]}
4063a8779fbSJames Wright                                   };
407bb8a0c61SJames Wright     const CeedScalar x_i[3]       = {x[0][i], x[1][i], x[2][i]};
4083a8779fbSJames Wright     // *INDENT-ON*
4093a8779fbSJames Wright     // -- Grad-to-Grad q_data
4103a8779fbSJames Wright     // dU/dx
4113a8779fbSJames Wright     CeedScalar du[3][3] = {{0}};
4123a8779fbSJames Wright     CeedScalar drhodx[3] = {0};
4133a8779fbSJames Wright     CeedScalar dEdx[3] = {0};
4143a8779fbSJames Wright     CeedScalar dUdx[3][3] = {{0}};
4153a8779fbSJames Wright     CeedScalar dXdxdXdxT[3][3] = {{0}};
4163a8779fbSJames Wright     for (int j=0; j<3; j++) {
4173a8779fbSJames Wright       for (int k=0; k<3; k++) {
4183a8779fbSJames Wright         du[j][k] = (dU[j][k] - drho[k]*u[j]) / rho;
4193a8779fbSJames Wright         drhodx[j] += drho[k] * dXdx[k][j];
4203a8779fbSJames Wright         dEdx[j] += dE[k] * dXdx[k][j];
4213a8779fbSJames Wright         for (int l=0; l<3; l++) {
4223a8779fbSJames Wright           dUdx[j][k] += dU[j][l] * dXdx[l][k];
4233a8779fbSJames Wright           dXdxdXdxT[j][k] += dXdx[j][l]*dXdx[k][l];  //dXdx_j,k * dXdx_k,j
4243a8779fbSJames Wright         }
4253a8779fbSJames Wright       }
4263a8779fbSJames Wright     }
4273a8779fbSJames Wright     CeedScalar dudx[3][3] = {{0}};
4283a8779fbSJames Wright     for (int j=0; j<3; j++)
4293a8779fbSJames Wright       for (int k=0; k<3; k++)
4303a8779fbSJames Wright         for (int l=0; l<3; l++)
4313a8779fbSJames Wright           dudx[j][k] += du[j][l] * dXdx[l][k];
4323a8779fbSJames Wright     // -- grad_T
4333a8779fbSJames Wright     const CeedScalar grad_T[3]  = {(dEdx[0]/rho - E*drhodx[0]/(rho*rho) - /* *NOPAD* */
434bb8a0c61SJames Wright                                     (u[0]*dudx[0][0] + u[1]*dudx[1][0] + u[2]*dudx[2][0]) + g[0])/cv,
4353a8779fbSJames Wright                                    (dEdx[1]/rho - E*drhodx[1]/(rho*rho) - /* *NOPAD* */
436bb8a0c61SJames Wright                                     (u[0]*dudx[0][1] + u[1]*dudx[1][1] + u[2]*dudx[2][1]) + g[1])/cv,
4373a8779fbSJames Wright                                    (dEdx[2]/rho - E*drhodx[2]/(rho*rho) - /* *NOPAD* */
438bb8a0c61SJames Wright                                     (u[0]*dudx[0][2] + u[1]*dudx[1][2] + u[2]*dudx[2][2]) + g[2])/cv
4393a8779fbSJames Wright                                   };
4403a8779fbSJames Wright 
4413a8779fbSJames Wright     // -- Fuvisc
4423a8779fbSJames Wright     // ---- Symmetric 3x3 matrix
4433a8779fbSJames Wright     const CeedScalar Fu[6]     =  {mu*(dudx[0][0] * (2 + lambda) + /* *NOPAD* */
4443a8779fbSJames Wright                                        lambda * (dudx[1][1] + dudx[2][2])),
4453a8779fbSJames Wright                                    mu*(dudx[0][1] + dudx[1][0]), /* *NOPAD* */
4463a8779fbSJames Wright                                    mu*(dudx[0][2] + dudx[2][0]), /* *NOPAD* */
4473a8779fbSJames Wright                                    mu*(dudx[1][1] * (2 + lambda) + /* *NOPAD* */
4483a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[2][2])),
4493a8779fbSJames Wright                                    mu*(dudx[1][2] + dudx[2][1]), /* *NOPAD* */
4503a8779fbSJames Wright                                    mu*(dudx[2][2] * (2 + lambda) + /* *NOPAD* */
4513a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[1][1]))
4523a8779fbSJames Wright                                   };
4533a8779fbSJames Wright     // -- Fevisc
4543a8779fbSJames Wright     const CeedScalar Fe[3]     =  {u[0]*Fu[0] + u[1]*Fu[1] + u[2]*Fu[2] + /* *NOPAD* */
4553a8779fbSJames Wright                                    k*grad_T[0], /* *NOPAD* */
4563a8779fbSJames Wright                                    u[0]*Fu[1] + u[1]*Fu[3] + u[2]*Fu[4] + /* *NOPAD* */
4573a8779fbSJames Wright                                    k*grad_T[1], /* *NOPAD* */
4583a8779fbSJames Wright                                    u[0]*Fu[2] + u[1]*Fu[4] + u[2]*Fu[5] + /* *NOPAD* */
4593a8779fbSJames Wright                                    k*grad_T[2] /* *NOPAD* */
4603a8779fbSJames Wright                                   };
4613a8779fbSJames Wright     // Pressure
4623a8779fbSJames Wright     const CeedScalar
4633a8779fbSJames Wright     E_kinetic   = 0.5 * rho * (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]),
464bb8a0c61SJames Wright     E_potential = -rho*(g[0]*x_i[0] + g[1]*x_i[1] + g[2]*x_i[2]),
4653a8779fbSJames Wright     E_internal  = E - E_kinetic - E_potential,
4663a8779fbSJames Wright     P           = E_internal * (gamma - 1.); // P = pressure
4673a8779fbSJames Wright 
4683a8779fbSJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
4693a8779fbSJames Wright     CeedScalar jacob_F_conv[3][5][5] = {{{0.}}};
470bb8a0c61SJames Wright     computeFluxJacobian_NS(jacob_F_conv, rho, u, E, gamma, g, x_i);
4713a8779fbSJames Wright 
4723a8779fbSJames Wright     // dqdx collects drhodx, dUdx and dEdx in one vector
4733a8779fbSJames Wright     CeedScalar dqdx[5][3];
4743a8779fbSJames Wright     for (int j=0; j<3; j++) {
4753a8779fbSJames Wright       dqdx[0][j] = drhodx[j];
4763a8779fbSJames Wright       dqdx[4][j] = dEdx[j];
4773a8779fbSJames Wright       for (int k=0; k<3; k++)
4783a8779fbSJames Wright         dqdx[k+1][j] = dUdx[k][j];
4793a8779fbSJames Wright     }
4803a8779fbSJames Wright 
4813a8779fbSJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
4823a8779fbSJames Wright     CeedScalar strong_conv[5] = {0};
4833a8779fbSJames Wright     for (int j=0; j<3; j++)
4843a8779fbSJames Wright       for (int k=0; k<5; k++)
4853a8779fbSJames Wright         for (int l=0; l<5; l++)
4863a8779fbSJames Wright           strong_conv[k] += jacob_F_conv[j][k][l] * dqdx[l][j];
4873a8779fbSJames Wright 
4883a8779fbSJames Wright     // Body force
489bb8a0c61SJames Wright     const CeedScalar body_force[5] = {0, rho *g[0], rho *g[1], rho *g[2], 0};
4903a8779fbSJames Wright 
4913a8779fbSJames Wright     // The Physics
4923a8779fbSJames Wright     // Zero dv so all future terms can safely sum into it
4933a8779fbSJames Wright     for (int j=0; j<5; j++)
4943a8779fbSJames Wright       for (int k=0; k<3; k++)
4953a8779fbSJames Wright         dv[k][j][i] = 0;
4963a8779fbSJames Wright 
4973a8779fbSJames Wright     // -- Density
4983a8779fbSJames Wright     // ---- u rho
4993a8779fbSJames Wright     for (int j=0; j<3; j++)
5003a8779fbSJames Wright       dv[j][0][i]  += wdetJ*(rho*u[0]*dXdx[j][0] + rho*u[1]*dXdx[j][1] +
5013a8779fbSJames Wright                              rho*u[2]*dXdx[j][2]);
5023a8779fbSJames Wright     // -- Momentum
5033a8779fbSJames Wright     // ---- rho (u x u) + P I3
5043a8779fbSJames Wright     for (int j=0; j<3; j++)
5053a8779fbSJames Wright       for (int k=0; k<3; k++)
5063a8779fbSJames Wright         dv[k][j+1][i]  += wdetJ*((rho*u[j]*u[0] + (j==0?P:0))*dXdx[k][0] +
5073a8779fbSJames Wright                                  (rho*u[j]*u[1] + (j==1?P:0))*dXdx[k][1] +
5083a8779fbSJames Wright                                  (rho*u[j]*u[2] + (j==2?P:0))*dXdx[k][2]);
5093a8779fbSJames Wright     // ---- Fuvisc
5103a8779fbSJames Wright     const CeedInt Fuviscidx[3][3] = {{0, 1, 2}, {1, 3, 4}, {2, 4, 5}}; // symmetric matrix indices
5113a8779fbSJames Wright     for (int j=0; j<3; j++)
5123a8779fbSJames Wright       for (int k=0; k<3; k++)
5133a8779fbSJames Wright         dv[k][j+1][i] -= wdetJ*(Fu[Fuviscidx[j][0]]*dXdx[k][0] +
5143a8779fbSJames Wright                                 Fu[Fuviscidx[j][1]]*dXdx[k][1] +
5153a8779fbSJames Wright                                 Fu[Fuviscidx[j][2]]*dXdx[k][2]);
5163a8779fbSJames Wright     // -- Total Energy Density
5173a8779fbSJames Wright     // ---- (E + P) u
5183a8779fbSJames Wright     for (int j=0; j<3; j++)
5193a8779fbSJames Wright       dv[j][4][i]  += wdetJ * (E + P) * (u[0]*dXdx[j][0] + u[1]*dXdx[j][1] +
5203a8779fbSJames Wright                                          u[2]*dXdx[j][2]);
5213a8779fbSJames Wright     // ---- Fevisc
5223a8779fbSJames Wright     for (int j=0; j<3; j++)
5233a8779fbSJames Wright       dv[j][4][i] -= wdetJ * (Fe[0]*dXdx[j][0] + Fe[1]*dXdx[j][1] +
5243a8779fbSJames Wright                               Fe[2]*dXdx[j][2]);
5253a8779fbSJames Wright     // Body Force
5263a8779fbSJames Wright     for (int j=0; j<5; j++)
5273a8779fbSJames Wright       v[j][i] = wdetJ * body_force[j];
5283a8779fbSJames Wright 
529bb8a0c61SJames Wright     // Spatial Stabilization
530bb8a0c61SJames Wright     // -- Not used in favor of diagonal tau. Kept for future testing
531bb8a0c61SJames Wright     // const CeedScalar sound_speed = sqrt(gamma * P / rho);
532bb8a0c61SJames Wright     // CeedScalar Tau_x[3] = {0.};
533bb8a0c61SJames Wright     // Tau_spatial(Tau_x, dXdx, u, sound_speed, context->c_tau, mu);
5343a8779fbSJames Wright 
535bb8a0c61SJames Wright     // -- Stabilization method: none, SU, or SUPG
536bb8a0c61SJames Wright     CeedScalar stab[5][3] = {{0.}};
537bb8a0c61SJames Wright     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
538bb8a0c61SJames Wright     CeedScalar Tau_d[3] = {0.};
5393a8779fbSJames Wright     switch (context->stabilization) {
5403a8779fbSJames Wright     case STAB_NONE:        // Galerkin
5413a8779fbSJames Wright       break;
5423a8779fbSJames Wright     case STAB_SU:        // SU
543bb8a0c61SJames Wright       Tau_diagPrim(Tau_d, dXdx, u, cv, context, mu, dt, rho);
544bb8a0c61SJames Wright       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
545bb8a0c61SJames Wright       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
546bb8a0c61SJames Wright       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
547bb8a0c61SJames Wright       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
548bb8a0c61SJames Wright       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
549bb8a0c61SJames Wright       PrimitiveToConservative_fwd(rho, u, E, Rd, cv, tau_strong_conv,
550bb8a0c61SJames Wright                                   tau_strong_conv_conservative);
5513a8779fbSJames Wright       for (int j=0; j<3; j++)
5523a8779fbSJames Wright         for (int k=0; k<5; k++)
5533a8779fbSJames Wright           for (int l=0; l<5; l++)
554bb8a0c61SJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
5553a8779fbSJames Wright 
5563a8779fbSJames Wright       for (int j=0; j<5; j++)
5573a8779fbSJames Wright         for (int k=0; k<3; k++)
5583a8779fbSJames Wright           dv[k][j][i] -= wdetJ*(stab[j][0] * dXdx[k][0] +
5593a8779fbSJames Wright                                 stab[j][1] * dXdx[k][1] +
5603a8779fbSJames Wright                                 stab[j][2] * dXdx[k][2]);
5613a8779fbSJames Wright       break;
5623a8779fbSJames Wright     case STAB_SUPG:        // SUPG is not implemented for explicit scheme
5633a8779fbSJames Wright       break;
5643a8779fbSJames Wright     }
5653a8779fbSJames Wright 
5663a8779fbSJames Wright   } // End Quadrature Point Loop
5673a8779fbSJames Wright 
5683a8779fbSJames Wright   // Return
5693a8779fbSJames Wright   return 0;
5703a8779fbSJames Wright }
5713a8779fbSJames Wright 
5723a8779fbSJames Wright // *****************************************************************************
5733a8779fbSJames Wright // This QFunction implements the Navier-Stokes equations (mentioned above) with
5743a8779fbSJames Wright //   implicit time stepping method
5753a8779fbSJames Wright //
5763a8779fbSJames Wright //  SU   = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) )
5773a8779fbSJames Wright //  SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) )
5783a8779fbSJames Wright //                                       (diffussive terms will be added later)
5793a8779fbSJames Wright //
5803a8779fbSJames Wright // *****************************************************************************
5813a8779fbSJames Wright CEED_QFUNCTION(IFunction_Newtonian)(void *ctx, CeedInt Q,
5823a8779fbSJames Wright                                     const CeedScalar *const *in,
5833a8779fbSJames Wright                                     CeedScalar *const *out) {
5843a8779fbSJames Wright   // *INDENT-OFF*
5853a8779fbSJames Wright   // Inputs
5863a8779fbSJames Wright   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
5873a8779fbSJames Wright                    (*dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
5883a8779fbSJames Wright                    (*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2],
5893a8779fbSJames Wright                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3],
5903a8779fbSJames Wright                    (*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4];
5913a8779fbSJames Wright   // Outputs
5923a8779fbSJames Wright   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
5933a8779fbSJames Wright              (*dv)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
5943a8779fbSJames Wright   // *INDENT-ON*
5953a8779fbSJames Wright   // Context
5963a8779fbSJames Wright   NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx;
5973a8779fbSJames Wright   const CeedScalar lambda = context->lambda;
5983a8779fbSJames Wright   const CeedScalar mu     = context->mu;
5993a8779fbSJames Wright   const CeedScalar k      = context->k;
6003a8779fbSJames Wright   const CeedScalar cv     = context->cv;
6013a8779fbSJames Wright   const CeedScalar cp     = context->cp;
602bb8a0c61SJames Wright   const CeedScalar *g     = context->g;
603bb8a0c61SJames Wright   const CeedScalar dt     = context->dt;
6043a8779fbSJames Wright   const CeedScalar gamma  = cp / cv;
605bb8a0c61SJames Wright   const CeedScalar Rd     = cp-cv;
6063a8779fbSJames Wright 
6073a8779fbSJames Wright   CeedPragmaSIMD
6083a8779fbSJames Wright   // Quadrature Point Loop
6093a8779fbSJames Wright   for (CeedInt i=0; i<Q; i++) {
6103a8779fbSJames Wright     // Setup
6113a8779fbSJames Wright     // -- Interp in
6123a8779fbSJames Wright     const CeedScalar rho        =   q[0][i];
6133a8779fbSJames Wright     const CeedScalar u[3]       =  {q[1][i] / rho,
6143a8779fbSJames Wright                                     q[2][i] / rho,
6153a8779fbSJames Wright                                     q[3][i] / rho
6163a8779fbSJames Wright                                    };
6173a8779fbSJames Wright     const CeedScalar E          =   q[4][i];
6183a8779fbSJames Wright     // -- Grad in
6193a8779fbSJames Wright     const CeedScalar drho[3]    =  {dq[0][0][i],
6203a8779fbSJames Wright                                     dq[1][0][i],
6213a8779fbSJames Wright                                     dq[2][0][i]
6223a8779fbSJames Wright                                    };
6233a8779fbSJames Wright     // *INDENT-OFF*
6243a8779fbSJames Wright     const CeedScalar dU[3][3]   = {{dq[0][1][i],
6253a8779fbSJames Wright                                     dq[1][1][i],
6263a8779fbSJames Wright                                     dq[2][1][i]},
6273a8779fbSJames Wright                                    {dq[0][2][i],
6283a8779fbSJames Wright                                     dq[1][2][i],
6293a8779fbSJames Wright                                     dq[2][2][i]},
6303a8779fbSJames Wright                                    {dq[0][3][i],
6313a8779fbSJames Wright                                     dq[1][3][i],
6323a8779fbSJames Wright                                     dq[2][3][i]}
6333a8779fbSJames Wright                                   };
6343a8779fbSJames Wright     // *INDENT-ON*
6353a8779fbSJames Wright     const CeedScalar dE[3]      =  {dq[0][4][i],
6363a8779fbSJames Wright                                     dq[1][4][i],
6373a8779fbSJames Wright                                     dq[2][4][i]
6383a8779fbSJames Wright                                    };
6393a8779fbSJames Wright     // -- Interp-to-Interp q_data
6403a8779fbSJames Wright     const CeedScalar wdetJ      =   q_data[0][i];
6413a8779fbSJames Wright     // -- Interp-to-Grad q_data
6423a8779fbSJames Wright     // ---- Inverse of change of coordinate matrix: X_i,j
6433a8779fbSJames Wright     // *INDENT-OFF*
6443a8779fbSJames Wright     const CeedScalar dXdx[3][3] = {{q_data[1][i],
6453a8779fbSJames Wright                                     q_data[2][i],
6463a8779fbSJames Wright                                     q_data[3][i]},
6473a8779fbSJames Wright                                    {q_data[4][i],
6483a8779fbSJames Wright                                     q_data[5][i],
6493a8779fbSJames Wright                                     q_data[6][i]},
6503a8779fbSJames Wright                                    {q_data[7][i],
6513a8779fbSJames Wright                                     q_data[8][i],
6523a8779fbSJames Wright                                     q_data[9][i]}
6533a8779fbSJames Wright                                   };
654bb8a0c61SJames Wright     const CeedScalar x_i[3]     = {x[0][i], x[1][i], x[2][i]};
6553a8779fbSJames Wright     // *INDENT-ON*
6563a8779fbSJames Wright     // -- Grad-to-Grad q_data
6573a8779fbSJames Wright     // dU/dx
6583a8779fbSJames Wright     CeedScalar du[3][3] = {{0}};
6593a8779fbSJames Wright     CeedScalar drhodx[3] = {0};
6603a8779fbSJames Wright     CeedScalar dEdx[3] = {0};
6613a8779fbSJames Wright     CeedScalar dUdx[3][3] = {{0}};
6623a8779fbSJames Wright     CeedScalar dXdxdXdxT[3][3] = {{0}};
6633a8779fbSJames Wright     for (int j=0; j<3; j++) {
6643a8779fbSJames Wright       for (int k=0; k<3; k++) {
6653a8779fbSJames Wright         du[j][k] = (dU[j][k] - drho[k]*u[j]) / rho;
6663a8779fbSJames Wright         drhodx[j] += drho[k] * dXdx[k][j];
6673a8779fbSJames Wright         dEdx[j] += dE[k] * dXdx[k][j];
6683a8779fbSJames Wright         for (int l=0; l<3; l++) {
6693a8779fbSJames Wright           dUdx[j][k] += dU[j][l] * dXdx[l][k];
6703a8779fbSJames Wright           dXdxdXdxT[j][k] += dXdx[j][l]*dXdx[k][l];  //dXdx_j,k * dXdx_k,j
6713a8779fbSJames Wright         }
6723a8779fbSJames Wright       }
6733a8779fbSJames Wright     }
6743a8779fbSJames Wright     CeedScalar dudx[3][3] = {{0}};
6753a8779fbSJames Wright     for (int j=0; j<3; j++)
6763a8779fbSJames Wright       for (int k=0; k<3; k++)
6773a8779fbSJames Wright         for (int l=0; l<3; l++)
6783a8779fbSJames Wright           dudx[j][k] += du[j][l] * dXdx[l][k];
6793a8779fbSJames Wright     // -- grad_T
6803a8779fbSJames Wright     const CeedScalar grad_T[3]  = {(dEdx[0]/rho - E*drhodx[0]/(rho*rho) - /* *NOPAD* */
681bb8a0c61SJames Wright                                     (u[0]*dudx[0][0] + u[1]*dudx[1][0] + u[2]*dudx[2][0]) + g[0])/cv,
6823a8779fbSJames Wright                                    (dEdx[1]/rho - E*drhodx[1]/(rho*rho) - /* *NOPAD* */
683bb8a0c61SJames Wright                                     (u[0]*dudx[0][1] + u[1]*dudx[1][1] + u[2]*dudx[2][1]) + g[1])/cv,
6843a8779fbSJames Wright                                    (dEdx[2]/rho - E*drhodx[2]/(rho*rho) - /* *NOPAD* */
685bb8a0c61SJames Wright                                     (u[0]*dudx[0][2] + u[1]*dudx[1][2] + u[2]*dudx[2][2]) + g[2])/cv
6863a8779fbSJames Wright                                   };
6873a8779fbSJames Wright     // -- Fuvisc
6883a8779fbSJames Wright     // ---- Symmetric 3x3 matrix
6893a8779fbSJames Wright     const CeedScalar Fu[6]     =  {mu*(dudx[0][0] * (2 + lambda) + /* *NOPAD* */
6903a8779fbSJames Wright                                        lambda * (dudx[1][1] + dudx[2][2])),
6913a8779fbSJames Wright                                    mu*(dudx[0][1] + dudx[1][0]), /* *NOPAD* */
6923a8779fbSJames Wright                                    mu*(dudx[0][2] + dudx[2][0]), /* *NOPAD* */
6933a8779fbSJames Wright                                    mu*(dudx[1][1] * (2 + lambda) + /* *NOPAD* */
6943a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[2][2])),
6953a8779fbSJames Wright                                    mu*(dudx[1][2] + dudx[2][1]), /* *NOPAD* */
6963a8779fbSJames Wright                                    mu*(dudx[2][2] * (2 + lambda) + /* *NOPAD* */
6973a8779fbSJames Wright                                        lambda * (dudx[0][0] + dudx[1][1]))
6983a8779fbSJames Wright                                   };
6993a8779fbSJames Wright     // -- Fevisc
7003a8779fbSJames Wright     const CeedScalar Fe[3]     =  {u[0]*Fu[0] + u[1]*Fu[1] + u[2]*Fu[2] + /* *NOPAD* */
7013a8779fbSJames Wright                                    k*grad_T[0], /* *NOPAD* */
7023a8779fbSJames Wright                                    u[0]*Fu[1] + u[1]*Fu[3] + u[2]*Fu[4] + /* *NOPAD* */
7033a8779fbSJames Wright                                    k*grad_T[1], /* *NOPAD* */
7043a8779fbSJames Wright                                    u[0]*Fu[2] + u[1]*Fu[4] + u[2]*Fu[5] + /* *NOPAD* */
7053a8779fbSJames Wright                                    k*grad_T[2] /* *NOPAD* */
7063a8779fbSJames Wright                                   };
7073a8779fbSJames Wright     // Pressure
7083a8779fbSJames Wright     const CeedScalar
7093a8779fbSJames Wright     E_kinetic   = 0.5 * rho * (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]),
710bb8a0c61SJames Wright     E_potential = -rho*(g[0]*x_i[0] + g[1]*x_i[1] + g[2]*x_i[2]),
7113a8779fbSJames Wright     E_internal  = E - E_kinetic - E_potential,
7123a8779fbSJames Wright     P           = E_internal * (gamma - 1.); // P = pressure
7133a8779fbSJames Wright 
7143a8779fbSJames Wright     // jacob_F_conv[3][5][5] = dF(convective)/dq at each direction
7153a8779fbSJames Wright     CeedScalar jacob_F_conv[3][5][5] = {{{0.}}};
716bb8a0c61SJames Wright     computeFluxJacobian_NS(jacob_F_conv, rho, u, E, gamma, g, x_i);
7173a8779fbSJames Wright 
7183a8779fbSJames Wright     // dqdx collects drhodx, dUdx and dEdx in one vector
7193a8779fbSJames Wright     CeedScalar dqdx[5][3];
7203a8779fbSJames Wright     for (int j=0; j<3; j++) {
7213a8779fbSJames Wright       dqdx[0][j] = drhodx[j];
7223a8779fbSJames Wright       dqdx[4][j] = dEdx[j];
7233a8779fbSJames Wright       for (int k=0; k<3; k++)
7243a8779fbSJames Wright         dqdx[k+1][j] = dUdx[k][j];
7253a8779fbSJames Wright     }
7263a8779fbSJames Wright     // strong_conv = dF/dq * dq/dx    (Strong convection)
7273a8779fbSJames Wright     CeedScalar strong_conv[5] = {0};
7283a8779fbSJames Wright     for (int j=0; j<3; j++)
7293a8779fbSJames Wright       for (int k=0; k<5; k++)
7303a8779fbSJames Wright         for (int l=0; l<5; l++)
7313a8779fbSJames Wright           strong_conv[k] += jacob_F_conv[j][k][l] * dqdx[l][j];
7323a8779fbSJames Wright 
7333a8779fbSJames Wright     // Body force
734bb8a0c61SJames Wright     const CeedScalar body_force[5] = {0, rho *g[0], rho *g[1], rho *g[2], 0};
7353a8779fbSJames Wright 
7363a8779fbSJames Wright     // Strong residual
7373a8779fbSJames Wright     CeedScalar strong_res[5];
7383a8779fbSJames Wright     for (int j=0; j<5; j++)
7393a8779fbSJames Wright       strong_res[j] = q_dot[j][i] + strong_conv[j] - body_force[j];
7403a8779fbSJames Wright 
7413a8779fbSJames Wright     // The Physics
7423a8779fbSJames Wright     //-----mass matrix
7433a8779fbSJames Wright     for (int j=0; j<5; j++)
7443a8779fbSJames Wright       v[j][i] = wdetJ*q_dot[j][i];
7453a8779fbSJames Wright 
7463a8779fbSJames Wright     // Zero dv so all future terms can safely sum into it
7473a8779fbSJames Wright     for (int j=0; j<5; j++)
7483a8779fbSJames Wright       for (int k=0; k<3; k++)
7493a8779fbSJames Wright         dv[k][j][i] = 0;
7503a8779fbSJames Wright 
7513a8779fbSJames Wright     // -- Density
7523a8779fbSJames Wright     // ---- u rho
7533a8779fbSJames Wright     for (int j=0; j<3; j++)
7543a8779fbSJames Wright       dv[j][0][i]  -= wdetJ*(rho*u[0]*dXdx[j][0] + rho*u[1]*dXdx[j][1] +
7553a8779fbSJames Wright                              rho*u[2]*dXdx[j][2]);
7563a8779fbSJames Wright     // -- Momentum
7573a8779fbSJames Wright     // ---- rho (u x u) + P I3
7583a8779fbSJames Wright     for (int j=0; j<3; j++)
7593a8779fbSJames Wright       for (int k=0; k<3; k++)
7603a8779fbSJames Wright         dv[k][j+1][i]  -= wdetJ*((rho*u[j]*u[0] + (j==0?P:0))*dXdx[k][0] +
7613a8779fbSJames Wright                                  (rho*u[j]*u[1] + (j==1?P:0))*dXdx[k][1] +
7623a8779fbSJames Wright                                  (rho*u[j]*u[2] + (j==2?P:0))*dXdx[k][2]);
7633a8779fbSJames Wright     // ---- Fuvisc
7643a8779fbSJames Wright     const CeedInt Fuviscidx[3][3] = {{0, 1, 2}, {1, 3, 4}, {2, 4, 5}}; // symmetric matrix indices
7653a8779fbSJames Wright     for (int j=0; j<3; j++)
7663a8779fbSJames Wright       for (int k=0; k<3; k++)
7673a8779fbSJames Wright         dv[k][j+1][i] += wdetJ*(Fu[Fuviscidx[j][0]]*dXdx[k][0] +
7683a8779fbSJames Wright                                 Fu[Fuviscidx[j][1]]*dXdx[k][1] +
7693a8779fbSJames Wright                                 Fu[Fuviscidx[j][2]]*dXdx[k][2]);
7703a8779fbSJames Wright     // -- Total Energy Density
7713a8779fbSJames Wright     // ---- (E + P) u
7723a8779fbSJames Wright     for (int j=0; j<3; j++)
7733a8779fbSJames Wright       dv[j][4][i]  -= wdetJ * (E + P) * (u[0]*dXdx[j][0] + u[1]*dXdx[j][1] +
7743a8779fbSJames Wright                                          u[2]*dXdx[j][2]);
7753a8779fbSJames Wright     // ---- Fevisc
7763a8779fbSJames Wright     for (int j=0; j<3; j++)
7773a8779fbSJames Wright       dv[j][4][i] += wdetJ * (Fe[0]*dXdx[j][0] + Fe[1]*dXdx[j][1] +
7783a8779fbSJames Wright                               Fe[2]*dXdx[j][2]);
7793a8779fbSJames Wright     // Body Force
7803a8779fbSJames Wright     for (int j=0; j<5; j++)
7813a8779fbSJames Wright       v[j][i] -= wdetJ*body_force[j];
7823a8779fbSJames Wright 
783bb8a0c61SJames Wright     // Spatial Stabilization
784bb8a0c61SJames Wright     // -- Not used in favor of diagonal tau. Kept for future testing
785bb8a0c61SJames Wright     // const CeedScalar sound_speed = sqrt(gamma * P / rho);
786bb8a0c61SJames Wright     // CeedScalar Tau_x[3] = {0.};
787bb8a0c61SJames Wright     // Tau_spatial(Tau_x, dXdx, u, sound_speed, c_tau, mu);
7883a8779fbSJames Wright 
7893a8779fbSJames Wright     // -- Stabilization method: none, SU, or SUPG
790bb8a0c61SJames Wright     CeedScalar stab[5][3] = {{0.}};
791bb8a0c61SJames Wright     CeedScalar tau_strong_res[5] = {0.}, tau_strong_res_conservative[5] = {0};
792bb8a0c61SJames Wright     CeedScalar tau_strong_conv[5] = {0.}, tau_strong_conv_conservative[5] = {0};
793bb8a0c61SJames Wright     CeedScalar Tau_d[3] = {0.};
7943a8779fbSJames Wright     switch (context->stabilization) {
7953a8779fbSJames Wright     case STAB_NONE:        // Galerkin
7963a8779fbSJames Wright       break;
7973a8779fbSJames Wright     case STAB_SU:        // SU
798bb8a0c61SJames Wright       Tau_diagPrim(Tau_d, dXdx, u, cv, context, mu, dt, rho);
799bb8a0c61SJames Wright       tau_strong_conv[0] = Tau_d[0] * strong_conv[0];
800bb8a0c61SJames Wright       tau_strong_conv[1] = Tau_d[1] * strong_conv[1];
801bb8a0c61SJames Wright       tau_strong_conv[2] = Tau_d[1] * strong_conv[2];
802bb8a0c61SJames Wright       tau_strong_conv[3] = Tau_d[1] * strong_conv[3];
803bb8a0c61SJames Wright       tau_strong_conv[4] = Tau_d[2] * strong_conv[4];
804bb8a0c61SJames Wright       PrimitiveToConservative_fwd(rho, u, E, Rd, cv, tau_strong_conv,
805bb8a0c61SJames Wright                                   tau_strong_conv_conservative);
8063a8779fbSJames Wright       for (int j=0; j<3; j++)
8073a8779fbSJames Wright         for (int k=0; k<5; k++)
8083a8779fbSJames Wright           for (int l=0; l<5; l++)
809bb8a0c61SJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_conv_conservative[l];
8103a8779fbSJames Wright 
8113a8779fbSJames Wright       for (int j=0; j<5; j++)
8123a8779fbSJames Wright         for (int k=0; k<3; k++)
8133a8779fbSJames Wright           dv[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
8143a8779fbSJames Wright                                 stab[j][1] * dXdx[k][1] +
8153a8779fbSJames Wright                                 stab[j][2] * dXdx[k][2]);
8163a8779fbSJames Wright       break;
8173a8779fbSJames Wright     case STAB_SUPG:        // SUPG
818bb8a0c61SJames Wright       Tau_diagPrim(Tau_d, dXdx, u, cv, context, mu, dt, rho);
819bb8a0c61SJames Wright       tau_strong_res[0] = Tau_d[0] * strong_res[0];
820bb8a0c61SJames Wright       tau_strong_res[1] = Tau_d[1] * strong_res[1];
821bb8a0c61SJames Wright       tau_strong_res[2] = Tau_d[1] * strong_res[2];
822bb8a0c61SJames Wright       tau_strong_res[3] = Tau_d[1] * strong_res[3];
823bb8a0c61SJames Wright       tau_strong_res[4] = Tau_d[2] * strong_res[4];
824bb8a0c61SJames Wright // Alternate route (useful later with primitive variable code)
825bb8a0c61SJames Wright // this function was verified against PHASTA for as IC that was as close as possible
826bb8a0c61SJames Wright //    computeFluxJacobian_NSp(jacob_F_conv_p, rho, u, E, Rd, cv);
827bb8a0c61SJames Wright // it has also been verified to compute a correct through the following
828bb8a0c61SJames Wright //   stab[k][j] += jacob_F_conv_p[j][k][l] * tau_strong_res[l] // flux Jacobian wrt primitive
829bb8a0c61SJames Wright // applied in the triple loop below
830bb8a0c61SJames Wright //  However, it is more flops than using the existing Jacobian wrt q after q_{,Y} viz
831bb8a0c61SJames Wright       PrimitiveToConservative_fwd(rho, u, E, Rd, cv, tau_strong_res,
832bb8a0c61SJames Wright                                   tau_strong_res_conservative);
8333a8779fbSJames Wright       for (int j=0; j<3; j++)
8343a8779fbSJames Wright         for (int k=0; k<5; k++)
8353a8779fbSJames Wright           for (int l=0; l<5; l++)
836bb8a0c61SJames Wright             stab[k][j] += jacob_F_conv[j][k][l] * tau_strong_res_conservative[l];
8373a8779fbSJames Wright 
8383a8779fbSJames Wright       for (int j=0; j<5; j++)
8393a8779fbSJames Wright         for (int k=0; k<3; k++)
8403a8779fbSJames Wright           dv[k][j][i] += wdetJ*(stab[j][0] * dXdx[k][0] +
8413a8779fbSJames Wright                                 stab[j][1] * dXdx[k][1] +
8423a8779fbSJames Wright                                 stab[j][2] * dXdx[k][2]);
8433a8779fbSJames Wright       break;
8443a8779fbSJames Wright     }
8453a8779fbSJames Wright 
8463a8779fbSJames Wright   } // End Quadrature Point Loop
8473a8779fbSJames Wright 
8483a8779fbSJames Wright   // Return
8493a8779fbSJames Wright   return 0;
8503a8779fbSJames Wright }
8513a8779fbSJames Wright // *****************************************************************************
8523a8779fbSJames Wright #endif // newtonian_h
853