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 #ifndef newtonian_h 123a8779fbSJames Wright #define newtonian_h 133a8779fbSJames Wright 143a8779fbSJames Wright #include <ceed.h> 15d0cce58aSJeremy L Thompson #include <math.h> 167b530f2aSAdelekeBankole #include <stdlib.h> 172b916ea7SJeremy L Thompson 18475b2820SJames Wright #include "newtonian_state.h" 19d0cce58aSJeremy L Thompson #include "newtonian_types.h" 20d1b9ef12SLeila Ghaffari #include "stabilization.h" 21d0cce58aSJeremy L Thompson #include "utils.h" 22bb8a0c61SJames Wright 23*e7754af5SKenneth E. Jansen CEED_QFUNCTION_HELPER void InternalDampingLayer(const NewtonianIdealGasContext context, const State s, const CeedScalar x_i[3], CeedScalar damp_Y[5], 24*e7754af5SKenneth E. Jansen CeedScalar damp_residual[5]) { 25*e7754af5SKenneth E. Jansen const CeedScalar sigma = LinearRampCoefficient(context->idl_amplitude, context->idl_length, context->idl_start, x_i[0]); 26*e7754af5SKenneth E. Jansen ScaleN(damp_Y, sigma, 5); 27*e7754af5SKenneth E. Jansen CeedScalar dx_i[3] = {0}; 28*e7754af5SKenneth E. Jansen State damp_s = StateFromY_fwd(context, s, damp_Y, x_i, dx_i); 29*e7754af5SKenneth E. Jansen 30*e7754af5SKenneth E. Jansen CeedScalar U[5]; 31*e7754af5SKenneth E. Jansen UnpackState_U(damp_s.U, U); 32*e7754af5SKenneth E. Jansen for (int i = 0; i < 5; i++) damp_residual[i] += U[i]; 33*e7754af5SKenneth E. Jansen } 34*e7754af5SKenneth E. Jansen 35bb8a0c61SJames Wright // ***************************************************************************** 363a8779fbSJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems 373a8779fbSJames Wright // ***************************************************************************** 38b8fb7609SAdeleke O. Bankole CEED_QFUNCTION_HELPER int ICsNewtonianIG(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateToQi_t StateToQi) { 393a8779fbSJames Wright // Inputs 403a8779fbSJames Wright const CeedScalar(*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 413a8779fbSJames Wright 423a8779fbSJames Wright // Outputs 433a8779fbSJames Wright CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 443a8779fbSJames Wright 45bb8a0c61SJames Wright // Context 46bb8a0c61SJames Wright const SetupContext context = (SetupContext)ctx; 47bb8a0c61SJames Wright 483a8779fbSJames Wright // Quadrature Point Loop 492b916ea7SJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 50b8fb7609SAdeleke O. Bankole CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]}; 513a8779fbSJames Wright CeedScalar q[5] = {0.}; 52b8fb7609SAdeleke O. Bankole State s = StateFromPrimitive(&context->gas, context->reference, x); 53b8fb7609SAdeleke O. Bankole StateToQi(&context->gas, s, q); 542b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 553a8779fbSJames Wright } // End of Quadrature Point Loop 563a8779fbSJames Wright return 0; 573a8779fbSJames Wright } 583a8779fbSJames Wright 592b916ea7SJeremy L Thompson CEED_QFUNCTION(ICsNewtonianIG_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 60b8fb7609SAdeleke O. Bankole return ICsNewtonianIG(ctx, Q, in, out, StateToY); 61b8fb7609SAdeleke O. Bankole } 62b8fb7609SAdeleke O. Bankole CEED_QFUNCTION(ICsNewtonianIG_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 63b8fb7609SAdeleke O. Bankole return ICsNewtonianIG(ctx, Q, in, out, StateToU); 64cbe60e31SLeila Ghaffari } 65cbe60e31SLeila Ghaffari 66cbe60e31SLeila Ghaffari // ***************************************************************************** 6704e40bb6SJeremy L Thompson // This QFunction implements the following formulation of Navier-Stokes with explicit time stepping method 683a8779fbSJames Wright // 6904e40bb6SJeremy L Thompson // This is 3D compressible Navier-Stokes in conservation form with state variables of density, momentum density, and total energy density. 703a8779fbSJames Wright // 713a8779fbSJames Wright // State Variables: q = ( rho, U1, U2, U3, E ) 723a8779fbSJames Wright // rho - Mass Density 733a8779fbSJames Wright // Ui - Momentum Density, Ui = rho ui 743a8779fbSJames Wright // E - Total Energy Density, E = rho (cv T + (u u)/2 + g z) 753a8779fbSJames Wright // 763a8779fbSJames Wright // Navier-Stokes Equations: 773a8779fbSJames Wright // drho/dt + div( U ) = 0 783a8779fbSJames Wright // dU/dt + div( rho (u x u) + P I3 ) + rho g khat = div( Fu ) 793a8779fbSJames Wright // dE/dt + div( (E + P) u ) = div( Fe ) 803a8779fbSJames Wright // 813a8779fbSJames Wright // Viscous Stress: 823a8779fbSJames Wright // Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3) 833a8779fbSJames Wright // 843a8779fbSJames Wright // Thermal Stress: 853a8779fbSJames Wright // Fe = u Fu + k grad( T ) 86bb8a0c61SJames Wright // Equation of State 873a8779fbSJames Wright // P = (gamma - 1) (E - rho (u u) / 2 - rho g z) 883a8779fbSJames Wright // 893a8779fbSJames Wright // Stabilization: 903a8779fbSJames Wright // Tau = diag(TauC, TauM, TauM, TauM, TauE) 913a8779fbSJames Wright // f1 = rho sqrt(ui uj gij) 923a8779fbSJames Wright // gij = dXi/dX * dXi/dX 933a8779fbSJames Wright // TauC = Cc f1 / (8 gii) 943a8779fbSJames Wright // TauM = min( 1 , 1 / f1 ) 953a8779fbSJames Wright // TauE = TauM / (Ce cv) 963a8779fbSJames Wright // 973a8779fbSJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 983a8779fbSJames Wright // 993a8779fbSJames Wright // Constants: 1003a8779fbSJames Wright // lambda = - 2 / 3, From Stokes hypothesis 1013a8779fbSJames Wright // mu , Dynamic viscosity 1023a8779fbSJames Wright // k , Thermal conductivity 1033a8779fbSJames Wright // cv , Specific heat, constant volume 1043a8779fbSJames Wright // cp , Specific heat, constant pressure 1053a8779fbSJames Wright // g , Gravity 1063a8779fbSJames Wright // gamma = cp / cv, Specific heat ratio 1073a8779fbSJames Wright // 10804e40bb6SJeremy L Thompson // We require the product of the inverse of the Jacobian (dXdx_j,k) and its transpose (dXdx_k,j) to properly compute integrals of the form: int( gradv 10904e40bb6SJeremy L Thompson // gradu ) 1103a8779fbSJames Wright // ***************************************************************************** 1112b916ea7SJeremy L Thompson CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1123a8779fbSJames Wright // Inputs 1133d65b166SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 1143d65b166SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 1153d65b166SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 1163d65b166SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 1173d65b166SJames Wright 1183a8779fbSJames Wright // Outputs 1193d65b166SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 1203d65b166SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 1213a8779fbSJames Wright 1223a8779fbSJames Wright // Context 1233a8779fbSJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 124bb8a0c61SJames Wright const CeedScalar *g = context->g; 125bb8a0c61SJames Wright const CeedScalar dt = context->dt; 1263a8779fbSJames Wright 1273a8779fbSJames Wright // Quadrature Point Loop 1283d65b166SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 129c1a52365SJed Brown CeedScalar U[5]; 130c1a52365SJed Brown for (int j = 0; j < 5; j++) U[j] = q[j][i]; 131c1a52365SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 132c1a52365SJed Brown State s = StateFromU(context, U, x_i); 133c1a52365SJed Brown 1343a8779fbSJames Wright // -- Interp-to-Interp q_data 1353a8779fbSJames Wright const CeedScalar wdetJ = q_data[0][i]; 1363a8779fbSJames Wright // -- Interp-to-Grad q_data 1373a8779fbSJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 1382b916ea7SJeremy L Thompson const CeedScalar dXdx[3][3] = { 1392b916ea7SJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 14034ea8d65SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 14134ea8d65SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 1423a8779fbSJames Wright }; 143c1a52365SJed Brown State grad_s[3]; 144eef2387dSJed Brown for (CeedInt j = 0; j < 3; j++) { 1452f7ce6c1SJed Brown CeedScalar dx_i[3] = {0}, dU[5]; 1462b916ea7SJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dU[k] = Grad_q[0][k][i] * dXdx[0][j] + Grad_q[1][k][i] * dXdx[1][j] + Grad_q[2][k][i] * dXdx[2][j]; 147c1a52365SJed Brown dx_i[j] = 1.; 1482f7ce6c1SJed Brown grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i); 149c1a52365SJed Brown } 150c1a52365SJed Brown 151c1a52365SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 152c1a52365SJed Brown KMStrainRate(grad_s, strain_rate); 153c1a52365SJed Brown NewtonianStress(context, strain_rate, kmstress); 154c1a52365SJed Brown KMUnpack(kmstress, stress); 155c1a52365SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 156c1a52365SJed Brown 157c1a52365SJed Brown StateConservative F_inviscid[3]; 158c1a52365SJed Brown FluxInviscid(context, s, F_inviscid); 159c1a52365SJed Brown 160c1a52365SJed Brown // Total flux 161c1a52365SJed Brown CeedScalar Flux[5][3]; 162d1b9ef12SLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 163c1a52365SJed Brown 1642b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 1652b916ea7SJeremy L Thompson for (CeedInt k = 0; k < 5; k++) Grad_v[j][k][i] = wdetJ * (dXdx[j][0] * Flux[k][0] + dXdx[j][1] * Flux[k][1] + dXdx[j][2] * Flux[k][2]); 1662b916ea7SJeremy L Thompson } 167c1a52365SJed Brown 168c1a52365SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 1692b916ea7SJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * body_force[j]; 1703a8779fbSJames Wright 171d1b9ef12SLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 172d1b9ef12SLeila Ghaffari CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}; 173d1b9ef12SLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 174d1b9ef12SLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 1753a8779fbSJames Wright 1762b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 1772b916ea7SJeremy L Thompson for (CeedInt k = 0; k < 3; k++) Grad_v[k][j][i] -= wdetJ * (stab[j][0] * dXdx[k][0] + stab[j][1] * dXdx[k][1] + stab[j][2] * dXdx[k][2]); 1782b916ea7SJeremy L Thompson } 1793a8779fbSJames Wright } // End Quadrature Point Loop 1803a8779fbSJames Wright 1813a8779fbSJames Wright // Return 1823a8779fbSJames Wright return 0; 1833a8779fbSJames Wright } 1843a8779fbSJames Wright 1853a8779fbSJames Wright // ***************************************************************************** 18604e40bb6SJeremy L Thompson // This QFunction implements the Navier-Stokes equations (mentioned above) with implicit time stepping method 1873a8779fbSJames Wright // 1883a8779fbSJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 1893a8779fbSJames Wright // SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) ) 19004e40bb6SJeremy L Thompson // (diffusive terms will be added later) 1913a8779fbSJames Wright // ***************************************************************************** 1922b916ea7SJeremy L Thompson CEED_QFUNCTION_HELPER int IFunction_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 1932b916ea7SJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 1943a8779fbSJames Wright // Inputs 1953d65b166SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 1963d65b166SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 1973d65b166SJames Wright const CeedScalar(*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 1983d65b166SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 1993d65b166SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 2003d65b166SJames Wright 2013a8779fbSJames Wright // Outputs 2023d65b166SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 2033d65b166SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 2043d65b166SJames Wright CeedScalar(*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2]; 2053d65b166SJames Wright 2063a8779fbSJames Wright // Context 2073a8779fbSJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 208bb8a0c61SJames Wright const CeedScalar *g = context->g; 209bb8a0c61SJames Wright const CeedScalar dt = context->dt; 210*e7754af5SKenneth E. Jansen const CeedScalar P0 = context->P0; 2113a8779fbSJames Wright 2123a8779fbSJames Wright // Quadrature Point Loop 2133d65b166SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 2143d65b166SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 215c1a52365SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 2163d65b166SJames Wright const State s = StateFromQi(context, qi, x_i); 217c1a52365SJed Brown 2183a8779fbSJames Wright // -- Interp-to-Interp q_data 2193a8779fbSJames Wright const CeedScalar wdetJ = q_data[0][i]; 2203a8779fbSJames Wright // -- Interp-to-Grad q_data 2213a8779fbSJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 2222b916ea7SJeremy L Thompson const CeedScalar dXdx[3][3] = { 2232b916ea7SJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 22434ea8d65SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 22534ea8d65SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 2263a8779fbSJames Wright }; 227c1a52365SJed Brown State grad_s[3]; 228493642f1SJames Wright for (CeedInt j = 0; j < 3; j++) { 22976555becSJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 2303d65b166SJames Wright for (CeedInt k = 0; k < 5; k++) { 2313d65b166SJames Wright dqi[k] = Grad_q[0][k][i] * dXdx[0][j] + Grad_q[1][k][i] * dXdx[1][j] + Grad_q[2][k][i] * dXdx[2][j]; 2323d65b166SJames Wright } 233c1a52365SJed Brown dx_i[j] = 1.; 23476555becSJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 2353a8779fbSJames Wright } 236c1a52365SJed Brown 237c1a52365SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 238c1a52365SJed Brown KMStrainRate(grad_s, strain_rate); 239c1a52365SJed Brown NewtonianStress(context, strain_rate, kmstress); 240c1a52365SJed Brown KMUnpack(kmstress, stress); 241c1a52365SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 242c1a52365SJed Brown 243c1a52365SJed Brown StateConservative F_inviscid[3]; 244c1a52365SJed Brown FluxInviscid(context, s, F_inviscid); 245c1a52365SJed Brown 246c1a52365SJed Brown // Total flux 247c1a52365SJed Brown CeedScalar Flux[5][3]; 248d1b9ef12SLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 249c1a52365SJed Brown 2502b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 2513d65b166SJames Wright for (CeedInt k = 0; k < 5; k++) { 2523d65b166SJames Wright Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * Flux[k][0] + dXdx[j][1] * Flux[k][1] + dXdx[j][2] * Flux[k][2]); 2533d65b166SJames Wright } 2542b916ea7SJeremy L Thompson } 255c1a52365SJed Brown 256c1a52365SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 2573a8779fbSJames Wright 258d1b9ef12SLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 25976555becSJames Wright CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}, qi_dot[5], dx0[3] = {0}; 26076555becSJames Wright for (int j = 0; j < 5; j++) qi_dot[j] = q_dot[j][i]; 26176555becSJames Wright State s_dot = StateFromQi_fwd(context, s, qi_dot, x_i, dx0); 26276555becSJames Wright UnpackState_U(s_dot.U, U_dot); 26376555becSJames Wright 2642b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 5; j++) v[j][i] = wdetJ * (U_dot[j] - body_force[j]); 265*e7754af5SKenneth E. Jansen if (context->idl_enable) { 266*e7754af5SKenneth E. Jansen CeedScalar damp_state[5] = {s.Y.pressure - P0, 0, 0, 0, 0}, idl_residual[5] = {0.}; 267*e7754af5SKenneth E. Jansen InternalDampingLayer(context, s, x_i, damp_state, idl_residual); 268*e7754af5SKenneth E. Jansen for (int j = 0; j < 5; j++) v[j][i] += wdetJ * idl_residual[j]; 269*e7754af5SKenneth E. Jansen } 270*e7754af5SKenneth E. Jansen 271d1b9ef12SLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 272d1b9ef12SLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 2733a8779fbSJames Wright 2742b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 2753d65b166SJames Wright for (CeedInt k = 0; k < 3; k++) { 2763d65b166SJames Wright Grad_v[k][j][i] += wdetJ * (stab[j][0] * dXdx[k][0] + stab[j][1] * dXdx[k][1] + stab[j][2] * dXdx[k][2]); 2773d65b166SJames Wright } 2782b916ea7SJeremy L Thompson } 27976555becSJames Wright for (CeedInt j = 0; j < 5; j++) jac_data[j][i] = qi[j]; 280eef2387dSJed Brown for (CeedInt j = 0; j < 6; j++) jac_data[5 + j][i] = kmstress[j]; 281eef2387dSJed Brown for (CeedInt j = 0; j < 3; j++) jac_data[5 + 6 + j][i] = Tau_d[j]; 2823a8779fbSJames Wright 2833a8779fbSJames Wright } // End Quadrature Point Loop 2843a8779fbSJames Wright 2853a8779fbSJames Wright // Return 2863a8779fbSJames Wright return 0; 2873a8779fbSJames Wright } 288f0b65372SJed Brown 2892b916ea7SJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 29076555becSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 29176555becSJames Wright } 29276555becSJames Wright 2932b916ea7SJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 29476555becSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 29576555becSJames Wright } 29676555becSJames Wright 297cbe60e31SLeila Ghaffari // ***************************************************************************** 29804e40bb6SJeremy L Thompson // This QFunction implements the jacobian of the Navier-Stokes equations for implicit time stepping method. 299cbe60e31SLeila Ghaffari // ***************************************************************************** 3002b916ea7SJeremy L Thompson CEED_QFUNCTION_HELPER int IJacobian_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 3012b916ea7SJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 302f0b65372SJed Brown // Inputs 3033d65b166SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 3043d65b166SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 3053d65b166SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 3063d65b166SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 3073d65b166SJames Wright const CeedScalar(*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 3083d65b166SJames Wright 309f0b65372SJed Brown // Outputs 3103d65b166SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 3113d65b166SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 3123d65b166SJames Wright 313f0b65372SJed Brown // Context 314f0b65372SJed Brown NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 315f0b65372SJed Brown const CeedScalar *g = context->g; 316f0b65372SJed Brown 317f0b65372SJed Brown // Quadrature Point Loop 3183d65b166SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 319f0b65372SJed Brown // -- Interp-to-Interp q_data 320f0b65372SJed Brown const CeedScalar wdetJ = q_data[0][i]; 321f0b65372SJed Brown // -- Interp-to-Grad q_data 322f0b65372SJed Brown // ---- Inverse of change of coordinate matrix: X_i,j 3232b916ea7SJeremy L Thompson const CeedScalar dXdx[3][3] = { 3242b916ea7SJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 32534ea8d65SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 32634ea8d65SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 327f0b65372SJed Brown }; 328f0b65372SJed Brown 3298789e95fSJames Wright CeedScalar qi[5], kmstress[6], Tau_d[3]; 33076555becSJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data[j][i]; 331f0b65372SJed Brown for (int j = 0; j < 6; j++) kmstress[j] = jac_data[5 + j][i]; 332f0b65372SJed Brown for (int j = 0; j < 3; j++) Tau_d[j] = jac_data[5 + 6 + j][i]; 333f0b65372SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 33476555becSJames Wright State s = StateFromQi(context, qi, x_i); 335f0b65372SJed Brown 33676555becSJames Wright CeedScalar dqi[5], dx0[3] = {0}; 33776555becSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 33876555becSJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx0); 339f0b65372SJed Brown 340f0b65372SJed Brown State grad_ds[3]; 341f0b65372SJed Brown for (int j = 0; j < 3; j++) { 34276555becSJames Wright CeedScalar dqi_j[5]; 3432b916ea7SJeremy L Thompson for (int k = 0; k < 5; k++) dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] + Grad_dq[1][k][i] * dXdx[1][j] + Grad_dq[2][k][i] * dXdx[2][j]; 34476555becSJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx0); 345f0b65372SJed Brown } 346f0b65372SJed Brown 347f0b65372SJed Brown CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 348f0b65372SJed Brown KMStrainRate(grad_ds, dstrain_rate); 349f0b65372SJed Brown NewtonianStress(context, dstrain_rate, dkmstress); 350f0b65372SJed Brown KMUnpack(dkmstress, dstress); 351f0b65372SJed Brown KMUnpack(kmstress, stress); 352f0b65372SJed Brown ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 353f0b65372SJed Brown 354f0b65372SJed Brown StateConservative dF_inviscid[3]; 355f0b65372SJed Brown FluxInviscid_fwd(context, s, ds, dF_inviscid); 356f0b65372SJed Brown 357f0b65372SJed Brown // Total flux 358f0b65372SJed Brown CeedScalar dFlux[5][3]; 359d1b9ef12SLeila Ghaffari FluxTotal(dF_inviscid, dstress, dFe, dFlux); 360f0b65372SJed Brown 3612b916ea7SJeremy L Thompson for (int j = 0; j < 3; j++) { 3622b916ea7SJeremy L Thompson for (int k = 0; k < 5; k++) Grad_v[j][k][i] = -wdetJ * (dXdx[j][0] * dFlux[k][0] + dXdx[j][1] * dFlux[k][1] + dXdx[j][2] * dFlux[k][2]); 3632b916ea7SJeremy L Thompson } 364f0b65372SJed Brown 365f0b65372SJed Brown const CeedScalar dbody_force[5] = {0, ds.U.density * g[0], ds.U.density * g[1], ds.U.density * g[2], 0}; 36676555becSJames Wright CeedScalar dU[5] = {0.}; 36776555becSJames Wright UnpackState_U(ds.U, dU); 3682b916ea7SJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]); 369f0b65372SJed Brown 370*e7754af5SKenneth E. Jansen if (context->idl_enable) { 371*e7754af5SKenneth E. Jansen CeedScalar damp_state[5] = {ds.Y.pressure, 0, 0, 0, 0}, idl_residual[5] = {0.}; 372*e7754af5SKenneth E. Jansen // This is a Picard-type linearization of the damping and could be replaced by an InternalDampingLayer_fwd that uses s and ds. 373*e7754af5SKenneth E. Jansen InternalDampingLayer(context, s, x_i, damp_state, idl_residual); 374*e7754af5SKenneth E. Jansen for (int j = 0; j < 5; j++) v[j][i] += wdetJ * idl_residual[j]; 375*e7754af5SKenneth E. Jansen } 376*e7754af5SKenneth E. Jansen 377d1b9ef12SLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 378d1b9ef12SLeila Ghaffari CeedScalar dstab[5][3], U_dot[5] = {0}; 379d1b9ef12SLeila Ghaffari for (CeedInt j = 0; j < 5; j++) U_dot[j] = context->ijacobian_time_shift * dU[j]; 380d1b9ef12SLeila Ghaffari Stabilization(context, s, Tau_d, grad_ds, U_dot, dbody_force, x_i, dstab); 381d1b9ef12SLeila Ghaffari 3822b916ea7SJeremy L Thompson for (int j = 0; j < 5; j++) { 3832b916ea7SJeremy L Thompson for (int k = 0; k < 3; k++) Grad_v[k][j][i] += wdetJ * (dstab[j][0] * dXdx[k][0] + dstab[j][1] * dXdx[k][1] + dstab[j][2] * dXdx[k][2]); 3842b916ea7SJeremy L Thompson } 385f0b65372SJed Brown } // End Quadrature Point Loop 386f0b65372SJed Brown return 0; 387f0b65372SJed Brown } 3888085925cSJames Wright 3892b916ea7SJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 39076555becSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 39176555becSJames Wright } 39276555becSJames Wright 3932b916ea7SJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 39476555becSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 39576555becSJames Wright } 39676555becSJames Wright 397d1b9ef12SLeila Ghaffari // ***************************************************************************** 3988085925cSJames Wright // Compute boundary integral (ie. for strongly set inflows) 399d1b9ef12SLeila Ghaffari // ***************************************************************************** 4002b916ea7SJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 4012b916ea7SJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 4023d65b166SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 4033d65b166SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 4043d65b166SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 4053d65b166SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 4068085925cSJames Wright 4073d65b166SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 4083d65b166SJames Wright CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 4098085925cSJames Wright 410d3b25f3aSJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 411d3b25f3aSJames Wright const bool is_implicit = context->is_implicit; 4128085925cSJames Wright 4132b916ea7SJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 414d3b25f3aSJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 41541e73928SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 41641e73928SJames Wright State s = StateFromQi(context, qi, x_i); 4178085925cSJames Wright 4188085925cSJames Wright const CeedScalar wdetJb = (is_implicit ? -1. : 1.) * q_data_sur[0][i]; 419c5740391SJames Wright // ---- Normal vector 4202b916ea7SJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 4218085925cSJames Wright 422d3b25f3aSJames Wright const CeedScalar dXdx[2][3] = { 423d3b25f3aSJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 424d3b25f3aSJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 425d3b25f3aSJames Wright }; 4268085925cSJames Wright 427d3b25f3aSJames Wright State grad_s[3]; 428d3b25f3aSJames Wright for (CeedInt j = 0; j < 3; j++) { 42941e73928SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 4302b916ea7SJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dqi[k] = Grad_q[0][k][i] * dXdx[0][j] + Grad_q[1][k][i] * dXdx[1][j]; 431d3b25f3aSJames Wright dx_i[j] = 1.; 43241e73928SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 433d3b25f3aSJames Wright } 4348085925cSJames Wright 435d3b25f3aSJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 436d3b25f3aSJames Wright KMStrainRate(grad_s, strain_rate); 437d3b25f3aSJames Wright NewtonianStress(context, strain_rate, kmstress); 438d3b25f3aSJames Wright KMUnpack(kmstress, stress); 439d3b25f3aSJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 440d3b25f3aSJames Wright 441d3b25f3aSJames Wright StateConservative F_inviscid[3]; 442d3b25f3aSJames Wright FluxInviscid(context, s, F_inviscid); 443d3b25f3aSJames Wright 444c5740391SJames Wright CeedScalar Flux[5]; 445c5740391SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 446d3b25f3aSJames Wright 447c5740391SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 4488085925cSJames Wright 449c5740391SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 45068ae065aSJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 4518085925cSJames Wright } 4528085925cSJames Wright return 0; 4538085925cSJames Wright } 4548085925cSJames Wright 4552b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 456d4559bbeSJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromU, StateFromU_fwd); 457d4559bbeSJames Wright } 458d4559bbeSJames Wright 4592b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 460d4559bbeSJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromY, StateFromY_fwd); 461d4559bbeSJames Wright } 462d4559bbeSJames Wright 463d1b9ef12SLeila Ghaffari // ***************************************************************************** 46468ae065aSJames Wright // Jacobian for "set nothing" boundary integral 465d1b9ef12SLeila Ghaffari // ***************************************************************************** 4662b916ea7SJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 467d4559bbeSJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 46868ae065aSJames Wright // Inputs 4693d65b166SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 4703d65b166SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 4713d65b166SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 4723d65b166SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 4733d65b166SJames Wright const CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 4743d65b166SJames Wright 47568ae065aSJames Wright // Outputs 47668ae065aSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 47768ae065aSJames Wright 47868ae065aSJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 47968ae065aSJames Wright const bool implicit = context->is_implicit; 48068ae065aSJames Wright 48168ae065aSJames Wright // Quadrature Point Loop 4823d65b166SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 48368ae065aSJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 48468ae065aSJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 4852b916ea7SJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 48668ae065aSJames Wright const CeedScalar dXdx[2][3] = { 48768ae065aSJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 48868ae065aSJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 48968ae065aSJames Wright }; 49068ae065aSJames Wright 49141e73928SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 49241e73928SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 49368ae065aSJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 49441e73928SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 4953934e2b1SJames Wright 49641e73928SJames Wright State s = StateFromQi(context, qi, x_i); 49741e73928SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 49868ae065aSJames Wright 49968ae065aSJames Wright State grad_ds[3]; 50068ae065aSJames Wright for (CeedInt j = 0; j < 3; j++) { 50141e73928SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 5022b916ea7SJeremy L Thompson for (CeedInt k = 0; k < 5; k++) dqi_j[k] = Grad_dq[0][k][i] * dXdx[0][j] + Grad_dq[1][k][i] * dXdx[1][j]; 50368ae065aSJames Wright dx_i[j] = 1.; 50441e73928SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 50568ae065aSJames Wright } 50668ae065aSJames Wright 50768ae065aSJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 50868ae065aSJames Wright KMStrainRate(grad_ds, dstrain_rate); 50968ae065aSJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 51068ae065aSJames Wright KMUnpack(dkmstress, dstress); 51168ae065aSJames Wright KMUnpack(kmstress, stress); 51268ae065aSJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 51368ae065aSJames Wright 51468ae065aSJames Wright StateConservative dF_inviscid[3]; 51568ae065aSJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 51668ae065aSJames Wright 517c5740391SJames Wright CeedScalar dFlux[5]; 518c5740391SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 51968ae065aSJames Wright 520c5740391SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 52168ae065aSJames Wright } // End Quadrature Point Loop 52268ae065aSJames Wright return 0; 52368ae065aSJames Wright } 52468ae065aSJames Wright 5252b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 526d4559bbeSJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 527d4559bbeSJames Wright } 528d4559bbeSJames Wright 5292b916ea7SJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 530d4559bbeSJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 531d4559bbeSJames Wright } 532d4559bbeSJames Wright 5333a8779fbSJames Wright #endif // newtonian_h 534