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