xref: /honee/qfunctions/shocktube.h (revision 493642f1e7bb5ccdccd1086ef1091462e675d35c)
1af8870a9STimothy Aiken // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2af8870a9STimothy Aiken // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3af8870a9STimothy Aiken // reserved. See files LICENSE and NOTICE for details.
4af8870a9STimothy Aiken //
5af8870a9STimothy Aiken // This file is part of CEED, a collection of benchmarks, miniapps, software
6af8870a9STimothy Aiken // libraries and APIs for efficient high-order finite element and spectral
7af8870a9STimothy Aiken // element discretizations for exascale applications. For more information and
8af8870a9STimothy Aiken // source code availability see http://github.com/ceed.
9af8870a9STimothy Aiken //
10af8870a9STimothy Aiken // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11af8870a9STimothy Aiken // a collaborative effort of two U.S. Department of Energy organizations (Office
12af8870a9STimothy Aiken // of Science and the National Nuclear Security Administration) responsible for
13af8870a9STimothy Aiken // the planning and preparation of a capable exascale ecosystem, including
14af8870a9STimothy Aiken // software, applications, hardware, advanced system engineering and early
15af8870a9STimothy Aiken // testbed platforms, in support of the nation's exascale computing imperative.
16af8870a9STimothy Aiken 
17af8870a9STimothy Aiken /// @file
18af8870a9STimothy Aiken /// Shock tube initial condition and Euler equation operator for Navier-Stokes
19af8870a9STimothy Aiken /// example using PETSc - modified from eulervortex.h
20af8870a9STimothy Aiken 
21af8870a9STimothy Aiken // Model from:
22af8870a9STimothy Aiken //   On the Order of Accuracy and Numerical Performance of Two Classes of
23af8870a9STimothy Aiken //   Finite Volume WENO Schemes, Zhang, Zhang, and Shu (2011).
24af8870a9STimothy Aiken 
25af8870a9STimothy Aiken #ifndef shocktube_h
26af8870a9STimothy Aiken #define shocktube_h
27af8870a9STimothy Aiken 
28af8870a9STimothy Aiken #include <math.h>
29*493642f1SJames Wright #include <ceed.h>
30af8870a9STimothy Aiken 
31af8870a9STimothy Aiken #ifndef M_PI
32af8870a9STimothy Aiken #define M_PI    3.14159265358979323846
33af8870a9STimothy Aiken #endif
34af8870a9STimothy Aiken 
35af8870a9STimothy Aiken typedef struct SetupContext_ *SetupContext;
36af8870a9STimothy Aiken struct SetupContext_ {
37af8870a9STimothy Aiken   CeedScalar theta0;
38af8870a9STimothy Aiken   CeedScalar thetaC;
39af8870a9STimothy Aiken   CeedScalar P0;
40af8870a9STimothy Aiken   CeedScalar N;
41af8870a9STimothy Aiken   CeedScalar cv;
42af8870a9STimothy Aiken   CeedScalar cp;
43af8870a9STimothy Aiken   CeedScalar time;
44af8870a9STimothy Aiken   CeedScalar mid_point;
45af8870a9STimothy Aiken   CeedScalar P_high;
46af8870a9STimothy Aiken   CeedScalar rho_high;
47af8870a9STimothy Aiken   CeedScalar P_low;
48af8870a9STimothy Aiken   CeedScalar rho_low;
49af8870a9STimothy Aiken   int wind_type;              // See WindType: 0=ROTATION, 1=TRANSLATION
50af8870a9STimothy Aiken   int bubble_type;            // See BubbleType: 0=SPHERE, 1=CYLINDER
51af8870a9STimothy Aiken   int bubble_continuity_type; // See BubbleContinuityType: 0=SMOOTH, 1=BACK_SHARP 2=THICK
52af8870a9STimothy Aiken };
53af8870a9STimothy Aiken 
54af8870a9STimothy Aiken typedef struct ShockTubeContext_ *ShockTubeContext;
55af8870a9STimothy Aiken struct ShockTubeContext_ {
56af8870a9STimothy Aiken   CeedScalar Cyzb;
57af8870a9STimothy Aiken   CeedScalar Byzb;
58af8870a9STimothy Aiken   CeedScalar c_tau;
59af8870a9STimothy Aiken   bool implicit;
60af8870a9STimothy Aiken   bool yzb;
61af8870a9STimothy Aiken   int stabilization;
62af8870a9STimothy Aiken };
63af8870a9STimothy Aiken 
64af8870a9STimothy Aiken // *****************************************************************************
65af8870a9STimothy Aiken // This function sets the initial conditions
66af8870a9STimothy Aiken //
67af8870a9STimothy Aiken //   Temperature:
68af8870a9STimothy Aiken //     T   = P / (rho * R)
69af8870a9STimothy Aiken //   Density:
70af8870a9STimothy Aiken //     rho = 1.0        if x <= mid_point
71af8870a9STimothy Aiken //         = 0.125      if x >  mid_point
72af8870a9STimothy Aiken //   Pressure:
73af8870a9STimothy Aiken //     P   = 1.0        if x <= mid_point
74af8870a9STimothy Aiken //         = 0.1        if x >  mid_point
75af8870a9STimothy Aiken //   Velocity:
76af8870a9STimothy Aiken //     u   = 0
77af8870a9STimothy Aiken //   Velocity/Momentum Density:
78af8870a9STimothy Aiken //     Ui  = rho ui
79af8870a9STimothy Aiken //   Total Energy:
80af8870a9STimothy Aiken //     E   = P / (gamma - 1) + rho (u u)/2
81af8870a9STimothy Aiken //
82af8870a9STimothy Aiken // Constants:
83af8870a9STimothy Aiken //   cv              ,  Specific heat, constant volume
84af8870a9STimothy Aiken //   cp              ,  Specific heat, constant pressure
85af8870a9STimothy Aiken //   mid_point       ,  Location of initial domain mid_point
86af8870a9STimothy Aiken //   gamma  = cp / cv,  Specific heat ratio
87af8870a9STimothy Aiken //
88af8870a9STimothy Aiken // *****************************************************************************
89af8870a9STimothy Aiken 
90af8870a9STimothy Aiken // *****************************************************************************
91af8870a9STimothy Aiken // This helper function provides support for the exact, time-dependent solution
92af8870a9STimothy Aiken //   (currently not implemented) and IC formulation for Euler traveling vortex
93af8870a9STimothy Aiken // *****************************************************************************
94*493642f1SJames Wright CEED_QFUNCTION_HELPER CeedInt Exact_ShockTube(CeedInt dim, CeedScalar time,
95af8870a9STimothy Aiken     const CeedScalar X[], CeedInt Nf, CeedScalar q[],
96af8870a9STimothy Aiken     void *ctx) {
97af8870a9STimothy Aiken 
98af8870a9STimothy Aiken   // Context
99af8870a9STimothy Aiken   const SetupContext context = (SetupContext)ctx;
100af8870a9STimothy Aiken   const CeedScalar mid_point = context->mid_point;      // Midpoint of the domain
101af8870a9STimothy Aiken   const CeedScalar P_high = context->P_high;            // Driver section pressure
102af8870a9STimothy Aiken   const CeedScalar rho_high = context->rho_high;        // Driver section density
103af8870a9STimothy Aiken   const CeedScalar P_low = context->P_low;              // Driven section pressure
104af8870a9STimothy Aiken   const CeedScalar rho_low = context->rho_low;          // Driven section density
105af8870a9STimothy Aiken 
106af8870a9STimothy Aiken   // Setup
107af8870a9STimothy Aiken   const CeedScalar gamma = 1.4;    // ratio of specific heats
108af8870a9STimothy Aiken   const CeedScalar x     = X[0];   // Coordinates
109af8870a9STimothy Aiken 
110af8870a9STimothy Aiken   CeedScalar rho, P, u[3] = {0.};
111af8870a9STimothy Aiken 
112af8870a9STimothy Aiken   // Initial Conditions
113af8870a9STimothy Aiken   if (x <= mid_point) {
114af8870a9STimothy Aiken     rho = rho_high;
115af8870a9STimothy Aiken     P   = P_high;
116af8870a9STimothy Aiken   } else {
117af8870a9STimothy Aiken     rho = rho_low;
118af8870a9STimothy Aiken     P   = P_low;
119af8870a9STimothy Aiken   }
120af8870a9STimothy Aiken 
121af8870a9STimothy Aiken   // Assign exact solution
122af8870a9STimothy Aiken   q[0] = rho;
123af8870a9STimothy Aiken   q[1] = rho * u[0];
124af8870a9STimothy Aiken   q[2] = rho * u[1];
125af8870a9STimothy Aiken   q[3] = rho * u[2];
126af8870a9STimothy Aiken   q[4] = P / (gamma-1.0) + rho * (u[0]*u[0]) / 2.;
127af8870a9STimothy Aiken 
128af8870a9STimothy Aiken   // Return
129af8870a9STimothy Aiken   return 0;
130af8870a9STimothy Aiken }
131af8870a9STimothy Aiken 
132af8870a9STimothy Aiken // *****************************************************************************
133af8870a9STimothy Aiken // Helper function for computing flux Jacobian
134af8870a9STimothy Aiken // *****************************************************************************
135af8870a9STimothy Aiken CEED_QFUNCTION_HELPER void ConvectiveFluxJacobian_Euler(CeedScalar dF[3][5][5],
136af8870a9STimothy Aiken     const CeedScalar rho, const CeedScalar u[3], const CeedScalar E,
137af8870a9STimothy Aiken     const CeedScalar gamma) {
138af8870a9STimothy Aiken   CeedScalar u_sq = u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; // Velocity square
139af8870a9STimothy Aiken   for (CeedInt i=0; i<3; i++) { // Jacobian matrices for 3 directions
140af8870a9STimothy Aiken     for (CeedInt j=0; j<3; j++) { // Rows of each Jacobian matrix
141af8870a9STimothy Aiken       dF[i][j+1][0] = ((i==j) ? ((gamma-1.)*(u_sq/2.)) : 0.) - u[i]*u[j];
142af8870a9STimothy Aiken       for (CeedInt k=0; k<3; k++) { // Columns of each Jacobian matrix
143af8870a9STimothy Aiken         dF[i][0][k+1]   = ((i==k) ? 1. : 0.);
144af8870a9STimothy Aiken         dF[i][j+1][k+1] = ((j==k) ? u[i] : 0.) +
145af8870a9STimothy Aiken                           ((i==k) ? u[j] : 0.) -
146af8870a9STimothy Aiken                           ((i==j) ? u[k] : 0.) * (gamma-1.);
147af8870a9STimothy Aiken         dF[i][4][k+1]   = ((i==k) ? (E*gamma/rho - (gamma-1.)*u_sq/2.) : 0.) -
148af8870a9STimothy Aiken                           (gamma-1.)*u[i]*u[k];
149af8870a9STimothy Aiken       }
150af8870a9STimothy Aiken       dF[i][j+1][4] = ((i==j) ? (gamma-1.) : 0.);
151af8870a9STimothy Aiken     }
152af8870a9STimothy Aiken     dF[i][4][0] = u[i] * ((gamma-1.)*u_sq - E*gamma/rho);
153af8870a9STimothy Aiken     dF[i][4][4] = u[i] * gamma;
154af8870a9STimothy Aiken   }
155af8870a9STimothy Aiken }
156af8870a9STimothy Aiken 
157af8870a9STimothy Aiken // *****************************************************************************
158af8870a9STimothy Aiken // Helper function for calculating the covariant length scale in the direction
159af8870a9STimothy Aiken // of some 3 element input vector
160af8870a9STimothy Aiken //
161af8870a9STimothy Aiken // Where
162af8870a9STimothy Aiken //  vec         = vector that length is measured in the direction of
163af8870a9STimothy Aiken //  h           = covariant element length along vec
164af8870a9STimothy Aiken // *****************************************************************************
165af8870a9STimothy Aiken CEED_QFUNCTION_HELPER CeedScalar Covariant_length_along_vector(
166af8870a9STimothy Aiken   CeedScalar vec[3], const CeedScalar dXdx[3][3]) {
167af8870a9STimothy Aiken 
168af8870a9STimothy Aiken   CeedScalar vec_norm = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
169af8870a9STimothy Aiken   CeedScalar vec_dot_jacobian[3] = {0.0};
170af8870a9STimothy Aiken   for (CeedInt i=0; i<3; i++) {
171af8870a9STimothy Aiken     for (CeedInt j=0; j<3; j++) {
172af8870a9STimothy Aiken       vec_dot_jacobian[i] += dXdx[j][i]*vec[i];
173af8870a9STimothy Aiken     }
174af8870a9STimothy Aiken   }
175af8870a9STimothy Aiken   CeedScalar norm_vec_dot_jacobian = sqrt(vec_dot_jacobian[0]*vec_dot_jacobian[0]+
176af8870a9STimothy Aiken                                           vec_dot_jacobian[1]*vec_dot_jacobian[1]+
177af8870a9STimothy Aiken                                           vec_dot_jacobian[2]*vec_dot_jacobian[2]);
178af8870a9STimothy Aiken   CeedScalar h = 2.0 * vec_norm / norm_vec_dot_jacobian;
179af8870a9STimothy Aiken   return h;
180af8870a9STimothy Aiken }
181af8870a9STimothy Aiken 
182af8870a9STimothy Aiken 
183af8870a9STimothy Aiken // *****************************************************************************
184af8870a9STimothy Aiken // Helper function for computing Tau elements (stabilization constant)
185af8870a9STimothy Aiken //   Model from:
186af8870a9STimothy Aiken //     Stabilized Methods for Compressible Flows, Hughes et al 2010
187af8870a9STimothy Aiken //
188af8870a9STimothy Aiken //   Spatial criterion #2 - Tau is a 3x3 diagonal matrix
189af8870a9STimothy Aiken //   Tau[i] = c_tau h[i] Xi(Pe) / rho(A[i]) (no sum)
190af8870a9STimothy Aiken //
191af8870a9STimothy Aiken // Where
192af8870a9STimothy Aiken //   c_tau     = stabilization constant (0.5 is reported as "optimal")
193af8870a9STimothy Aiken //   h[i]      = 2 length(dxdX[i])
194af8870a9STimothy Aiken //   Pe        = Peclet number ( Pe = sqrt(u u) / dot(dXdx,u) diffusivity )
195af8870a9STimothy Aiken //   Xi(Pe)    = coth Pe - 1. / Pe (1. at large local Peclet number )
196af8870a9STimothy Aiken //   rho(A[i]) = spectral radius of the convective flux Jacobian i,
197af8870a9STimothy Aiken //               wave speed in direction i
198af8870a9STimothy Aiken // *****************************************************************************
199af8870a9STimothy Aiken CEED_QFUNCTION_HELPER void Tau_spatial(CeedScalar Tau_x[3],
200af8870a9STimothy Aiken                                        const CeedScalar dXdx[3][3], const CeedScalar u[3],
201af8870a9STimothy Aiken                                        const CeedScalar sound_speed, const CeedScalar c_tau) {
202*493642f1SJames Wright   for (CeedInt i=0; i<3; i++) {
203af8870a9STimothy Aiken     // length of element in direction i
204af8870a9STimothy Aiken     CeedScalar h = 2 / sqrt(dXdx[0][i]*dXdx[0][i] + dXdx[1][i]*dXdx[1][i] +
205af8870a9STimothy Aiken                             dXdx[2][i]*dXdx[2][i]);
206af8870a9STimothy Aiken     // fastest wave in direction i
207af8870a9STimothy Aiken     CeedScalar fastest_wave = fabs(u[i]) + sound_speed;
208af8870a9STimothy Aiken     Tau_x[i] = c_tau * h / fastest_wave;
209af8870a9STimothy Aiken   }
210af8870a9STimothy Aiken }
211af8870a9STimothy Aiken 
212af8870a9STimothy Aiken // *****************************************************************************
213af8870a9STimothy Aiken // This QFunction sets the initial conditions for shock tube
214af8870a9STimothy Aiken // *****************************************************************************
215af8870a9STimothy Aiken CEED_QFUNCTION(ICsShockTube)(void *ctx, CeedInt Q,
216af8870a9STimothy Aiken                              const CeedScalar *const *in, CeedScalar *const *out) {
217af8870a9STimothy Aiken   // Inputs
218af8870a9STimothy Aiken   const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
219af8870a9STimothy Aiken 
220af8870a9STimothy Aiken   // Outputs
221af8870a9STimothy Aiken   CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
222af8870a9STimothy Aiken 
223af8870a9STimothy Aiken   CeedPragmaSIMD
224af8870a9STimothy Aiken   // Quadrature Point Loop
225af8870a9STimothy Aiken   for (CeedInt i=0; i<Q; i++) {
226af8870a9STimothy Aiken     const CeedScalar x[] = {X[0][i], X[1][i], X[2][i]};
227af8870a9STimothy Aiken     CeedScalar q[5];
228af8870a9STimothy Aiken 
229af8870a9STimothy Aiken     Exact_ShockTube(3, 0., x, 5, q, ctx);
230af8870a9STimothy Aiken 
231af8870a9STimothy Aiken     for (CeedInt j=0; j<5; j++)
232af8870a9STimothy Aiken       q0[j][i] = q[j];
233af8870a9STimothy Aiken   } // End of Quadrature Point Loop
234af8870a9STimothy Aiken 
235af8870a9STimothy Aiken   // Return
236af8870a9STimothy Aiken   return 0;
237af8870a9STimothy Aiken }
238af8870a9STimothy Aiken 
239af8870a9STimothy Aiken // *****************************************************************************
240af8870a9STimothy Aiken // This QFunction implements the following formulation of Euler equations
241af8870a9STimothy Aiken //   with explicit time stepping method
242af8870a9STimothy Aiken //
243af8870a9STimothy Aiken // This is 3D Euler for compressible gas dynamics in conservation
244af8870a9STimothy Aiken //   form with state variables of density, momentum density, and total
245af8870a9STimothy Aiken //   energy density.
246af8870a9STimothy Aiken //
247af8870a9STimothy Aiken // State Variables: q = ( rho, U1, U2, U3, E )
248af8870a9STimothy Aiken //   rho - Mass Density
249af8870a9STimothy Aiken //   Ui  - Momentum Density,      Ui = rho ui
250af8870a9STimothy Aiken //   E   - Total Energy Density,  E  = P / (gamma - 1) + rho (u u)/2
251af8870a9STimothy Aiken //
252af8870a9STimothy Aiken // Euler Equations:
253af8870a9STimothy Aiken //   drho/dt + div( U )                   = 0
254af8870a9STimothy Aiken //   dU/dt   + div( rho (u x u) + P I3 )  = 0
255af8870a9STimothy Aiken //   dE/dt   + div( (E + P) u )           = 0
256af8870a9STimothy Aiken //
257af8870a9STimothy Aiken // Equation of State:
258af8870a9STimothy Aiken //   P = (gamma - 1) (E - rho (u u) / 2)
259af8870a9STimothy Aiken //
260af8870a9STimothy Aiken // Constants:
261af8870a9STimothy Aiken //   cv              ,  Specific heat, constant volume
262af8870a9STimothy Aiken //   cp              ,  Specific heat, constant pressure
263af8870a9STimothy Aiken //   g               ,  Gravity
264af8870a9STimothy Aiken //   gamma  = cp / cv,  Specific heat ratio
265af8870a9STimothy Aiken // *****************************************************************************
266af8870a9STimothy Aiken CEED_QFUNCTION(EulerShockTube)(void *ctx, CeedInt Q,
267af8870a9STimothy Aiken                                const CeedScalar *const *in, CeedScalar *const *out) {
268af8870a9STimothy Aiken   // *INDENT-OFF*
269af8870a9STimothy Aiken   // Inputs
270af8870a9STimothy Aiken   const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0],
271af8870a9STimothy Aiken                    (*dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1],
272af8870a9STimothy Aiken                    (*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2];
273af8870a9STimothy Aiken   // Outputs
274af8870a9STimothy Aiken   CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0],
275af8870a9STimothy Aiken              (*dv)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1];
276af8870a9STimothy Aiken 
277af8870a9STimothy Aiken   const CeedScalar gamma = 1.4;
278af8870a9STimothy Aiken 
279af8870a9STimothy Aiken   ShockTubeContext context = (ShockTubeContext)ctx;
280af8870a9STimothy Aiken   const CeedScalar Cyzb  = context->Cyzb;
281af8870a9STimothy Aiken   const CeedScalar Byzb  = context->Byzb;
282af8870a9STimothy Aiken   const CeedScalar c_tau = context->c_tau;
283af8870a9STimothy Aiken 
284af8870a9STimothy Aiken   CeedPragmaSIMD
285af8870a9STimothy Aiken   // Quadrature Point Loop
286af8870a9STimothy Aiken   for (CeedInt i=0; i<Q; i++) {
287af8870a9STimothy Aiken     // *INDENT-OFF*
288af8870a9STimothy Aiken     // Setup
289af8870a9STimothy Aiken     // -- Interp in
290af8870a9STimothy Aiken     const CeedScalar rho        =   q[0][i];
291af8870a9STimothy Aiken     const CeedScalar u[3]       =  {q[1][i] / rho,
292af8870a9STimothy Aiken                                     q[2][i] / rho,
293af8870a9STimothy Aiken                                     q[3][i] / rho
294af8870a9STimothy Aiken                                    };
295af8870a9STimothy Aiken     const CeedScalar E          =   q[4][i];
296af8870a9STimothy Aiken     const CeedScalar drho[3]    =  {dq[0][0][i],
297af8870a9STimothy Aiken                                     dq[1][0][i],
298af8870a9STimothy Aiken                                     dq[2][0][i]
299af8870a9STimothy Aiken                                    };
300af8870a9STimothy Aiken     const CeedScalar dU[3][3]   = {{dq[0][1][i],
301af8870a9STimothy Aiken                                     dq[1][1][i],
302af8870a9STimothy Aiken                                     dq[2][1][i]},
303af8870a9STimothy Aiken                                    {dq[0][2][i],
304af8870a9STimothy Aiken                                     dq[1][2][i],
305af8870a9STimothy Aiken                                     dq[2][2][i]},
306af8870a9STimothy Aiken                                    {dq[0][3][i],
307af8870a9STimothy Aiken                                     dq[1][3][i],
308af8870a9STimothy Aiken                                     dq[2][3][i]}
309af8870a9STimothy Aiken                                   };
310af8870a9STimothy Aiken     const CeedScalar dE[3]      =  {dq[0][4][i],
311af8870a9STimothy Aiken                                     dq[1][4][i],
312af8870a9STimothy Aiken                                     dq[2][4][i]
313af8870a9STimothy Aiken                                    };
314af8870a9STimothy Aiken     // -- Interp-to-Interp q_data
315af8870a9STimothy Aiken     const CeedScalar wdetJ      =   q_data[0][i];
316af8870a9STimothy Aiken     // -- Interp-to-Grad q_data
317af8870a9STimothy Aiken     // ---- Inverse of change of coordinate matrix: X_i,j
318af8870a9STimothy Aiken     // *INDENT-OFF*
319af8870a9STimothy Aiken     const CeedScalar dXdx[3][3] = {{q_data[1][i],
320af8870a9STimothy Aiken                                     q_data[2][i],
321af8870a9STimothy Aiken                                     q_data[3][i]},
322af8870a9STimothy Aiken                                    {q_data[4][i],
323af8870a9STimothy Aiken                                     q_data[5][i],
324af8870a9STimothy Aiken                                     q_data[6][i]},
325af8870a9STimothy Aiken                                    {q_data[7][i],
326af8870a9STimothy Aiken                                     q_data[8][i],
327af8870a9STimothy Aiken                                     q_data[9][i]}
328af8870a9STimothy Aiken                                   };
329af8870a9STimothy Aiken     // dU/dx
330af8870a9STimothy Aiken     CeedScalar du[3][3] = {{0}};
331af8870a9STimothy Aiken     CeedScalar drhodx[3] = {0};
332af8870a9STimothy Aiken     CeedScalar dEdx[3] = {0};
333af8870a9STimothy Aiken     CeedScalar dUdx[3][3] = {{0}};
334af8870a9STimothy Aiken     CeedScalar dXdxdXdxT[3][3] = {{0}};
335*493642f1SJames Wright     for (CeedInt j=0; j<3; j++) {
336*493642f1SJames Wright       for (CeedInt k=0; k<3; k++) {
337af8870a9STimothy Aiken         du[j][k] = (dU[j][k] - drho[k]*u[j]) / rho;
338af8870a9STimothy Aiken         drhodx[j] += drho[k] * dXdx[k][j];
339af8870a9STimothy Aiken         dEdx[j] += dE[k] * dXdx[k][j];
340*493642f1SJames Wright         for (CeedInt l=0; l<3; l++) {
341af8870a9STimothy Aiken           dUdx[j][k] += dU[j][l] * dXdx[l][k];
342af8870a9STimothy Aiken           dXdxdXdxT[j][k] += dXdx[j][l]*dXdx[k][l];  //dXdx_j,k * dXdx_k,j
343af8870a9STimothy Aiken         }
344af8870a9STimothy Aiken       }
345af8870a9STimothy Aiken     }
346af8870a9STimothy Aiken 
347af8870a9STimothy Aiken     // *INDENT-ON*
348af8870a9STimothy Aiken     const CeedScalar
349af8870a9STimothy Aiken     E_kinetic  = 0.5 * rho * (u[0]*u[0] + u[1]*u[1] + u[2]*u[2]),
350af8870a9STimothy Aiken     E_internal = E - E_kinetic,
351af8870a9STimothy Aiken     P          = E_internal * (gamma - 1); // P = pressure
352af8870a9STimothy Aiken 
353af8870a9STimothy Aiken     // The Physics
354af8870a9STimothy Aiken     // Zero v and dv so all future terms can safely sum into it
355*493642f1SJames Wright     for (CeedInt j=0; j<5; j++) {
356af8870a9STimothy Aiken       v[j][i] = 0;
357*493642f1SJames Wright       for (CeedInt k=0; k<3; k++)
358af8870a9STimothy Aiken         dv[k][j][i] = 0;
359af8870a9STimothy Aiken     }
360af8870a9STimothy Aiken 
361af8870a9STimothy Aiken     // -- Density
362af8870a9STimothy Aiken     // ---- u rho
363*493642f1SJames Wright     for (CeedInt j=0; j<3; j++)
364af8870a9STimothy Aiken       dv[j][0][i]  += wdetJ*(rho*u[0]*dXdx[j][0] + rho*u[1]*dXdx[j][1] +
365af8870a9STimothy Aiken                              rho*u[2]*dXdx[j][2]);
366af8870a9STimothy Aiken     // -- Momentum
367af8870a9STimothy Aiken     // ---- rho (u x u) + P I3
368*493642f1SJames Wright     for (CeedInt j=0; j<3; j++)
369*493642f1SJames Wright       for (CeedInt k=0; k<3; k++)
370af8870a9STimothy Aiken         dv[k][j+1][i]  += wdetJ*((rho*u[j]*u[0] + (j==0?P:0))*dXdx[k][0] +
371af8870a9STimothy Aiken                                  (rho*u[j]*u[1] + (j==1?P:0))*dXdx[k][1] +
372af8870a9STimothy Aiken                                  (rho*u[j]*u[2] + (j==2?P:0))*dXdx[k][2]);
373af8870a9STimothy Aiken     // -- Total Energy Density
374af8870a9STimothy Aiken     // ---- (E + P) u
375*493642f1SJames Wright     for (CeedInt j=0; j<3; j++)
376af8870a9STimothy Aiken       dv[j][4][i]  += wdetJ * (E + P) * (u[0]*dXdx[j][0] + u[1]*dXdx[j][1] +
377af8870a9STimothy Aiken                                          u[2]*dXdx[j][2]);
378af8870a9STimothy Aiken 
379af8870a9STimothy Aiken     // -- YZB stabilization
380af8870a9STimothy Aiken     if (context->yzb) {
381af8870a9STimothy Aiken       CeedScalar drho_norm = 0.0;         // magnitude of the density gradient
382af8870a9STimothy Aiken       CeedScalar j_vec[3] = {0.0};        // unit vector aligned with the density gradient
383af8870a9STimothy Aiken       CeedScalar h_shock = 0.0;           // element lengthscale
384af8870a9STimothy Aiken       CeedScalar acoustic_vel = 0.0;      // characteristic velocity, acoustic speed
385af8870a9STimothy Aiken       CeedScalar tau_shock = 0.0;         // timescale
386af8870a9STimothy Aiken       CeedScalar nu_shock = 0.0;          // artificial diffusion
387af8870a9STimothy Aiken 
388af8870a9STimothy Aiken       // Unit vector aligned with the density gradient
389af8870a9STimothy Aiken       drho_norm = sqrt(drhodx[0]*drhodx[0] + drhodx[1]*drhodx[1] +
390af8870a9STimothy Aiken                        drhodx[2]*drhodx[2]);
391*493642f1SJames Wright       for (CeedInt j=0; j<3; j++)
392af8870a9STimothy Aiken         j_vec[j] = drhodx[j] / (drho_norm + 1e-20);
393af8870a9STimothy Aiken 
394af8870a9STimothy Aiken       if (drho_norm == 0.0) {
395af8870a9STimothy Aiken         nu_shock = 0.0;
396af8870a9STimothy Aiken       } else {
397af8870a9STimothy Aiken         h_shock = Covariant_length_along_vector(j_vec, dXdx);
398af8870a9STimothy Aiken         h_shock /= Cyzb;
399af8870a9STimothy Aiken         acoustic_vel = sqrt(gamma*P/rho);
400af8870a9STimothy Aiken         tau_shock = h_shock / (2*acoustic_vel) * pow(drho_norm * h_shock / rho, Byzb);
401af8870a9STimothy Aiken         nu_shock = fabs(tau_shock * acoustic_vel * acoustic_vel);
402af8870a9STimothy Aiken       }
403af8870a9STimothy Aiken 
404*493642f1SJames Wright       for (CeedInt j=0; j<3; j++)
405af8870a9STimothy Aiken         dv[j][0][i] -= wdetJ * nu_shock * drhodx[j];
406af8870a9STimothy Aiken 
407*493642f1SJames Wright       for (CeedInt k=0; k<3; k++)
408*493642f1SJames Wright         for (CeedInt j=0; j<3; j++)
409af8870a9STimothy Aiken           dv[j][k][i] -= wdetJ * nu_shock * du[k][j];
410af8870a9STimothy Aiken 
411*493642f1SJames Wright       for (CeedInt j=0; j<3; j++)
412af8870a9STimothy Aiken         dv[j][4][i] -= wdetJ * nu_shock * dEdx[j];
413af8870a9STimothy Aiken     }
414af8870a9STimothy Aiken 
415af8870a9STimothy Aiken     // Stabilization
416af8870a9STimothy Aiken     // Need the Jacobian for the advective fluxes for stabilization
417af8870a9STimothy Aiken     //    indexed as: jacob_F_conv[direction][flux component][solution component]
418af8870a9STimothy Aiken     CeedScalar jacob_F_conv[3][5][5] = {{{0.}}};
419af8870a9STimothy Aiken     ConvectiveFluxJacobian_Euler(jacob_F_conv, rho, u, E, gamma);
420af8870a9STimothy Aiken 
421af8870a9STimothy Aiken 
422af8870a9STimothy Aiken     // dqdx collects drhodx, dUdx and dEdx in one vector
423af8870a9STimothy Aiken     CeedScalar dqdx[5][3];
424*493642f1SJames Wright     for (CeedInt j=0; j<3; j++) {
425af8870a9STimothy Aiken       dqdx[0][j] = drhodx[j];
426af8870a9STimothy Aiken       dqdx[4][j] = dEdx[j];
427*493642f1SJames Wright       for (CeedInt k=0; k<3; k++)
428af8870a9STimothy Aiken         dqdx[k+1][j] = dUdx[k][j];
429af8870a9STimothy Aiken     }
430af8870a9STimothy Aiken 
431af8870a9STimothy Aiken     // strong_conv = dF/dq * dq/dx    (Strong convection)
432af8870a9STimothy Aiken     CeedScalar strong_conv[5] = {0};
433*493642f1SJames Wright     for (CeedInt j=0; j<3; j++)
434*493642f1SJames Wright       for (CeedInt k=0; k<5; k++)
435*493642f1SJames Wright         for (CeedInt l=0; l<5; l++)
436af8870a9STimothy Aiken           strong_conv[k] += jacob_F_conv[j][k][l] * dqdx[l][j];
437af8870a9STimothy Aiken 
438af8870a9STimothy Aiken     // Stabilization
439af8870a9STimothy Aiken     // -- Tau elements
440af8870a9STimothy Aiken     const CeedScalar sound_speed = sqrt(gamma * P / rho);
441af8870a9STimothy Aiken     CeedScalar Tau_x[3] = {0.};
442af8870a9STimothy Aiken     Tau_spatial(Tau_x, dXdx, u, sound_speed, c_tau);
443af8870a9STimothy Aiken 
444af8870a9STimothy Aiken     CeedScalar stab[5][3] = {0};
445af8870a9STimothy Aiken     switch (context->stabilization) {
446af8870a9STimothy Aiken     case 0:        // Galerkin
447af8870a9STimothy Aiken       break;
448af8870a9STimothy Aiken     case 1:        // SU
449*493642f1SJames Wright       for (CeedInt j=0; j<3; j++)
450*493642f1SJames Wright         for (CeedInt k=0; k<5; k++)
451*493642f1SJames Wright           for (CeedInt l=0; l<5; l++) {
452af8870a9STimothy Aiken             stab[k][j] += jacob_F_conv[j][k][l] * Tau_x[j] * strong_conv[l];
453af8870a9STimothy Aiken           }
454*493642f1SJames Wright       for (CeedInt j=0; j<5; j++)
455*493642f1SJames Wright         for (CeedInt k=0; k<3; k++)
456af8870a9STimothy Aiken           dv[k][j][i] -= wdetJ*(stab[j][0] * dXdx[k][0] +
457af8870a9STimothy Aiken                                 stab[j][1] * dXdx[k][1] +
458af8870a9STimothy Aiken                                 stab[j][2] * dXdx[k][2]);
459af8870a9STimothy Aiken       break;
460af8870a9STimothy Aiken     }
461af8870a9STimothy Aiken 
462af8870a9STimothy Aiken   } // End Quadrature Point Loop
463af8870a9STimothy Aiken 
464af8870a9STimothy Aiken   // Return
465af8870a9STimothy Aiken   return 0;
466af8870a9STimothy Aiken }
467af8870a9STimothy Aiken 
468af8870a9STimothy Aiken #endif // shocktube_h
469