13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 388b783a1SJames Wright // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 588b783a1SJames Wright // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 788b783a1SJames Wright 888b783a1SJames Wright /// @file 988b783a1SJames Wright /// Operator for Navier-Stokes example using PETSc 1088b783a1SJames Wright 1188b783a1SJames Wright #ifndef newtonian_h 1288b783a1SJames Wright #define newtonian_h 1388b783a1SJames Wright 1488b783a1SJames Wright #include <ceed.h> 15c9c2c079SJeremy L Thompson #include <math.h> 16738af36cSAdelekeBankole #include <stdlib.h> 172b730f8bSJeremy L Thompson 18c6e8c570SJames Wright #include "newtonian_state.h" 19c9c2c079SJeremy L Thompson #include "newtonian_types.h" 202b89d87eSLeila Ghaffari #include "stabilization.h" 21c9c2c079SJeremy L Thompson #include "utils.h" 2288626eedSJames Wright 23530ad8c4SKenneth E. Jansen CEED_QFUNCTION_HELPER void InternalDampingLayer(const NewtonianIdealGasContext context, const State s, const CeedScalar x_i[3], CeedScalar damp_Y[5], 24530ad8c4SKenneth E. Jansen CeedScalar damp_residual[5]) { 25530ad8c4SKenneth E. Jansen const CeedScalar sigma = LinearRampCoefficient(context->idl_amplitude, context->idl_length, context->idl_start, x_i[0]); 26530ad8c4SKenneth E. Jansen ScaleN(damp_Y, sigma, 5); 27530ad8c4SKenneth E. Jansen CeedScalar dx_i[3] = {0}; 28530ad8c4SKenneth E. Jansen State damp_s = StateFromY_fwd(context, s, damp_Y, x_i, dx_i); 29530ad8c4SKenneth E. Jansen 30530ad8c4SKenneth E. Jansen CeedScalar U[5]; 31530ad8c4SKenneth E. Jansen UnpackState_U(damp_s.U, U); 32530ad8c4SKenneth E. Jansen for (int i = 0; i < 5; i++) damp_residual[i] += U[i]; 33530ad8c4SKenneth E. Jansen } 34530ad8c4SKenneth E. Jansen 3588626eedSJames Wright // ***************************************************************************** 3688b783a1SJames Wright // This QFunction sets a "still" initial condition for generic Newtonian IG problems 3788b783a1SJames Wright // ***************************************************************************** 38d310b3d3SAdeleke O. Bankole CEED_QFUNCTION_HELPER int ICsNewtonianIG(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateToQi_t StateToQi) { 3988b783a1SJames Wright // Inputs 4088b783a1SJames Wright const CeedScalar(*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 4188b783a1SJames Wright 4288b783a1SJames Wright // Outputs 4388b783a1SJames Wright CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 4488b783a1SJames Wright 4588626eedSJames Wright // Context 4688626eedSJames Wright const SetupContext context = (SetupContext)ctx; 4788626eedSJames Wright 4888b783a1SJames Wright // Quadrature Point Loop 492b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 50d310b3d3SAdeleke O. Bankole CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]}; 5188b783a1SJames Wright CeedScalar q[5] = {0.}; 52d310b3d3SAdeleke O. Bankole State s = StateFromPrimitive(&context->gas, context->reference, x); 53d310b3d3SAdeleke O. Bankole StateToQi(&context->gas, s, q); 542b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 5588b783a1SJames Wright } // End of Quadrature Point Loop 5688b783a1SJames Wright return 0; 5788b783a1SJames Wright } 5888b783a1SJames Wright 592b730f8bSJeremy L Thompson CEED_QFUNCTION(ICsNewtonianIG_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 60d310b3d3SAdeleke O. Bankole return ICsNewtonianIG(ctx, Q, in, out, StateToY); 61d310b3d3SAdeleke O. Bankole } 62d310b3d3SAdeleke O. Bankole CEED_QFUNCTION(ICsNewtonianIG_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 63d310b3d3SAdeleke O. Bankole return ICsNewtonianIG(ctx, Q, in, out, StateToU); 64dc805cc4SLeila Ghaffari } 65dc805cc4SLeila Ghaffari 66dc805cc4SLeila Ghaffari // ***************************************************************************** 67ea61e9acSJeremy L Thompson // This QFunction implements the following formulation of Navier-Stokes with explicit time stepping method 6888b783a1SJames Wright // 69ea61e9acSJeremy L Thompson // This is 3D compressible Navier-Stokes in conservation form with state variables of density, momentum density, and total energy density. 7088b783a1SJames Wright // 7188b783a1SJames Wright // State Variables: q = ( rho, U1, U2, U3, E ) 7288b783a1SJames Wright // rho - Mass Density 7388b783a1SJames Wright // Ui - Momentum Density, Ui = rho ui 7488b783a1SJames Wright // E - Total Energy Density, E = rho (cv T + (u u)/2 + g z) 7588b783a1SJames Wright // 7688b783a1SJames Wright // Navier-Stokes Equations: 7788b783a1SJames Wright // drho/dt + div( U ) = 0 7888b783a1SJames Wright // dU/dt + div( rho (u x u) + P I3 ) + rho g khat = div( Fu ) 7988b783a1SJames Wright // dE/dt + div( (E + P) u ) = div( Fe ) 8088b783a1SJames Wright // 8188b783a1SJames Wright // Viscous Stress: 8288b783a1SJames Wright // Fu = mu (grad( u ) + grad( u )^T + lambda div ( u ) I3) 8388b783a1SJames Wright // 8488b783a1SJames Wright // Thermal Stress: 8588b783a1SJames Wright // Fe = u Fu + k grad( T ) 8688626eedSJames Wright // Equation of State 8788b783a1SJames Wright // P = (gamma - 1) (E - rho (u u) / 2 - rho g z) 8888b783a1SJames Wright // 8988b783a1SJames Wright // Stabilization: 9088b783a1SJames Wright // Tau = diag(TauC, TauM, TauM, TauM, TauE) 9188b783a1SJames Wright // f1 = rho sqrt(ui uj gij) 9288b783a1SJames Wright // gij = dXi/dX * dXi/dX 9388b783a1SJames Wright // TauC = Cc f1 / (8 gii) 9488b783a1SJames Wright // TauM = min( 1 , 1 / f1 ) 9588b783a1SJames Wright // TauE = TauM / (Ce cv) 9688b783a1SJames Wright // 9788b783a1SJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 9888b783a1SJames Wright // 9988b783a1SJames Wright // Constants: 10088b783a1SJames Wright // lambda = - 2 / 3, From Stokes hypothesis 10188b783a1SJames Wright // mu , Dynamic viscosity 10288b783a1SJames Wright // k , Thermal conductivity 10388b783a1SJames Wright // cv , Specific heat, constant volume 10488b783a1SJames Wright // cp , Specific heat, constant pressure 10588b783a1SJames Wright // g , Gravity 10688b783a1SJames Wright // gamma = cp / cv, Specific heat ratio 10788b783a1SJames Wright // 108ea61e9acSJeremy 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 109ea61e9acSJeremy L Thompson // gradu ) 11088b783a1SJames Wright // ***************************************************************************** 1112b730f8bSJeremy L Thompson CEED_QFUNCTION(RHSFunction_Newtonian)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 11288b783a1SJames Wright // Inputs 11346603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 11446603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 11546603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 11646603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 11746603fc5SJames Wright 11888b783a1SJames Wright // Outputs 11946603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 12046603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 12188b783a1SJames Wright 12288b783a1SJames Wright // Context 12388b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 12488626eedSJames Wright const CeedScalar *g = context->g; 12588626eedSJames Wright const CeedScalar dt = context->dt; 12688b783a1SJames Wright 12788b783a1SJames Wright // Quadrature Point Loop 12846603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 1295c677226SJed Brown CeedScalar U[5]; 1305c677226SJed Brown for (int j = 0; j < 5; j++) U[j] = q[j][i]; 1315c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 1325c677226SJed Brown State s = StateFromU(context, U, x_i); 1335c677226SJed Brown 13488b783a1SJames Wright // -- Interp-to-Interp q_data 13588b783a1SJames Wright const CeedScalar wdetJ = q_data[0][i]; 13688b783a1SJames Wright // -- Interp-to-Grad q_data 13788b783a1SJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 1382b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 1392b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 14023d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 14123d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 14288b783a1SJames Wright }; 1435c677226SJed Brown State grad_s[3]; 1443c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) { 1456f00d0e6SJed Brown CeedScalar dx_i[3] = {0}, dU[5]; 1462b730f8bSJeremy 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]; 1475c677226SJed Brown dx_i[j] = 1.; 1486f00d0e6SJed Brown grad_s[j] = StateFromU_fwd(context, s, dU, x_i, dx_i); 1495c677226SJed Brown } 1505c677226SJed Brown 1515c677226SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 152*d08fcc28SJames Wright KMStrainRate_State(grad_s, strain_rate); 1535c677226SJed Brown NewtonianStress(context, strain_rate, kmstress); 1545c677226SJed Brown KMUnpack(kmstress, stress); 1555c677226SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 1565c677226SJed Brown 1575c677226SJed Brown StateConservative F_inviscid[3]; 1585c677226SJed Brown FluxInviscid(context, s, F_inviscid); 1595c677226SJed Brown 1605c677226SJed Brown // Total flux 1615c677226SJed Brown CeedScalar Flux[5][3]; 1622b89d87eSLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 1635c677226SJed Brown 1642b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 1652b730f8bSJeremy 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]); 1662b730f8bSJeremy L Thompson } 1675c677226SJed Brown 1685c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 1692b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * body_force[j]; 17088b783a1SJames Wright 1712b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 1722b89d87eSLeila Ghaffari CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}; 1732b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 1742b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 17588b783a1SJames Wright 1762b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 1772b730f8bSJeremy 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]); 1782b730f8bSJeremy L Thompson } 17988b783a1SJames Wright } // End Quadrature Point Loop 18088b783a1SJames Wright 18188b783a1SJames Wright // Return 18288b783a1SJames Wright return 0; 18388b783a1SJames Wright } 18488b783a1SJames Wright 18588b783a1SJames Wright // ***************************************************************************** 186ea61e9acSJeremy L Thompson // This QFunction implements the Navier-Stokes equations (mentioned above) with implicit time stepping method 18788b783a1SJames Wright // 18888b783a1SJames Wright // SU = Galerkin + grad(v) . ( Ai^T * Tau * (Aj q,j) ) 18988b783a1SJames Wright // SUPG = Galerkin + grad(v) . ( Ai^T * Tau * (q_dot + Aj q,j - body force) ) 190ea61e9acSJeremy L Thompson // (diffusive terms will be added later) 19188b783a1SJames Wright // ***************************************************************************** 1922b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IFunction_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 1932b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 19488b783a1SJames Wright // Inputs 19546603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 19646603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 19746603fc5SJames Wright const CeedScalar(*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 19846603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 19946603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 20046603fc5SJames Wright 20188b783a1SJames Wright // Outputs 20246603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 20346603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 20446603fc5SJames Wright CeedScalar(*jac_data)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[2]; 20546603fc5SJames Wright 20688b783a1SJames Wright // Context 20788b783a1SJames Wright NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 20888626eedSJames Wright const CeedScalar *g = context->g; 20988626eedSJames Wright const CeedScalar dt = context->dt; 210530ad8c4SKenneth E. Jansen const CeedScalar P0 = context->P0; 21188b783a1SJames Wright 21288b783a1SJames Wright // Quadrature Point Loop 21346603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 21446603fc5SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 2155c677226SJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 21646603fc5SJames Wright const State s = StateFromQi(context, qi, x_i); 2175c677226SJed Brown 21888b783a1SJames Wright // -- Interp-to-Interp q_data 21988b783a1SJames Wright const CeedScalar wdetJ = q_data[0][i]; 22088b783a1SJames Wright // -- Interp-to-Grad q_data 22188b783a1SJames Wright // ---- Inverse of change of coordinate matrix: X_i,j 2222b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 2232b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 22423d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 22523d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 22688b783a1SJames Wright }; 2275c677226SJed Brown State grad_s[3]; 228ba6664aeSJames Wright for (CeedInt j = 0; j < 3; j++) { 2293d02368aSJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 23046603fc5SJames Wright for (CeedInt k = 0; k < 5; k++) { 23146603fc5SJames 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]; 23246603fc5SJames Wright } 2335c677226SJed Brown dx_i[j] = 1.; 2343d02368aSJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 23588b783a1SJames Wright } 2365c677226SJed Brown 2375c677226SJed Brown CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 238*d08fcc28SJames Wright KMStrainRate_State(grad_s, strain_rate); 2395c677226SJed Brown NewtonianStress(context, strain_rate, kmstress); 2405c677226SJed Brown KMUnpack(kmstress, stress); 2415c677226SJed Brown ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 2425c677226SJed Brown 2435c677226SJed Brown StateConservative F_inviscid[3]; 2445c677226SJed Brown FluxInviscid(context, s, F_inviscid); 2455c677226SJed Brown 2465c677226SJed Brown // Total flux 2475c677226SJed Brown CeedScalar Flux[5][3]; 2482b89d87eSLeila Ghaffari FluxTotal(F_inviscid, stress, Fe, Flux); 2495c677226SJed Brown 2502b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 3; j++) { 25146603fc5SJames Wright for (CeedInt k = 0; k < 5; k++) { 25246603fc5SJames 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]); 25346603fc5SJames Wright } 2542b730f8bSJeremy L Thompson } 2555c677226SJed Brown 2565c677226SJed Brown const CeedScalar body_force[5] = {0, s.U.density * g[0], s.U.density * g[1], s.U.density * g[2], 0}; 25788b783a1SJames Wright 2582b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 2593d02368aSJames Wright CeedScalar Tau_d[3], stab[5][3], U_dot[5] = {0}, qi_dot[5], dx0[3] = {0}; 2603d02368aSJames Wright for (int j = 0; j < 5; j++) qi_dot[j] = q_dot[j][i]; 2613d02368aSJames Wright State s_dot = StateFromQi_fwd(context, s, qi_dot, x_i, dx0); 2623d02368aSJames Wright UnpackState_U(s_dot.U, U_dot); 2633d02368aSJames Wright 2642b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) v[j][i] = wdetJ * (U_dot[j] - body_force[j]); 265530ad8c4SKenneth E. Jansen if (context->idl_enable) { 266530ad8c4SKenneth E. Jansen CeedScalar damp_state[5] = {s.Y.pressure - P0, 0, 0, 0, 0}, idl_residual[5] = {0.}; 267530ad8c4SKenneth E. Jansen InternalDampingLayer(context, s, x_i, damp_state, idl_residual); 268530ad8c4SKenneth E. Jansen for (int j = 0; j < 5; j++) v[j][i] += wdetJ * idl_residual[j]; 269530ad8c4SKenneth E. Jansen } 270530ad8c4SKenneth E. Jansen 2712b89d87eSLeila Ghaffari Tau_diagPrim(context, s, dXdx, dt, Tau_d); 2722b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_s, U_dot, body_force, x_i, stab); 27388b783a1SJames Wright 2742b730f8bSJeremy L Thompson for (CeedInt j = 0; j < 5; j++) { 27546603fc5SJames Wright for (CeedInt k = 0; k < 3; k++) { 27646603fc5SJames 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]); 27746603fc5SJames Wright } 2782b730f8bSJeremy L Thompson } 2793d02368aSJames Wright for (CeedInt j = 0; j < 5; j++) jac_data[j][i] = qi[j]; 2803c4b7af6SJed Brown for (CeedInt j = 0; j < 6; j++) jac_data[5 + j][i] = kmstress[j]; 2813c4b7af6SJed Brown for (CeedInt j = 0; j < 3; j++) jac_data[5 + 6 + j][i] = Tau_d[j]; 28288b783a1SJames Wright 28388b783a1SJames Wright } // End Quadrature Point Loop 28488b783a1SJames Wright 28588b783a1SJames Wright // Return 28688b783a1SJames Wright return 0; 28788b783a1SJames Wright } 288e334ad8fSJed Brown 2892b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2903d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 2913d02368aSJames Wright } 2923d02368aSJames Wright 2932b730f8bSJeremy L Thompson CEED_QFUNCTION(IFunction_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 2943d02368aSJames Wright return IFunction_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 2953d02368aSJames Wright } 2963d02368aSJames Wright 297dc805cc4SLeila Ghaffari // ***************************************************************************** 298ea61e9acSJeremy L Thompson // This QFunction implements the jacobian of the Navier-Stokes equations for implicit time stepping method. 299dc805cc4SLeila Ghaffari // ***************************************************************************** 3002b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int IJacobian_Newtonian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 3012b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 302e334ad8fSJed Brown // Inputs 30346603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 30446603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 30546603fc5SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 30646603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 30746603fc5SJames Wright const CeedScalar(*jac_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 30846603fc5SJames Wright 309e334ad8fSJed Brown // Outputs 31046603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 31146603fc5SJames Wright CeedScalar(*Grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 31246603fc5SJames Wright 313e334ad8fSJed Brown // Context 314e334ad8fSJed Brown NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 315e334ad8fSJed Brown const CeedScalar *g = context->g; 316e334ad8fSJed Brown 317e334ad8fSJed Brown // Quadrature Point Loop 31846603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 319e334ad8fSJed Brown // -- Interp-to-Interp q_data 320e334ad8fSJed Brown const CeedScalar wdetJ = q_data[0][i]; 321e334ad8fSJed Brown // -- Interp-to-Grad q_data 322e334ad8fSJed Brown // ---- Inverse of change of coordinate matrix: X_i,j 3232b730f8bSJeremy L Thompson const CeedScalar dXdx[3][3] = { 3242b730f8bSJeremy L Thompson {q_data[1][i], q_data[2][i], q_data[3][i]}, 32523d6ba15SJames Wright {q_data[4][i], q_data[5][i], q_data[6][i]}, 32623d6ba15SJames Wright {q_data[7][i], q_data[8][i], q_data[9][i]} 327e334ad8fSJed Brown }; 328e334ad8fSJed Brown 329c98a0616SJames Wright CeedScalar qi[5], kmstress[6], Tau_d[3]; 3303d02368aSJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data[j][i]; 331e334ad8fSJed Brown for (int j = 0; j < 6; j++) kmstress[j] = jac_data[5 + j][i]; 332e334ad8fSJed Brown for (int j = 0; j < 3; j++) Tau_d[j] = jac_data[5 + 6 + j][i]; 333e334ad8fSJed Brown const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 3343d02368aSJames Wright State s = StateFromQi(context, qi, x_i); 335e334ad8fSJed Brown 3363d02368aSJames Wright CeedScalar dqi[5], dx0[3] = {0}; 3373d02368aSJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 3383d02368aSJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx0); 339e334ad8fSJed Brown 340e334ad8fSJed Brown State grad_ds[3]; 341e334ad8fSJed Brown for (int j = 0; j < 3; j++) { 3423d02368aSJames Wright CeedScalar dqi_j[5]; 3432b730f8bSJeremy 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]; 3443d02368aSJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx0); 345e334ad8fSJed Brown } 346e334ad8fSJed Brown 347e334ad8fSJed Brown CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 348*d08fcc28SJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 349e334ad8fSJed Brown NewtonianStress(context, dstrain_rate, dkmstress); 350e334ad8fSJed Brown KMUnpack(dkmstress, dstress); 351e334ad8fSJed Brown KMUnpack(kmstress, stress); 352e334ad8fSJed Brown ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 353e334ad8fSJed Brown 354e334ad8fSJed Brown StateConservative dF_inviscid[3]; 355e334ad8fSJed Brown FluxInviscid_fwd(context, s, ds, dF_inviscid); 356e334ad8fSJed Brown 357e334ad8fSJed Brown // Total flux 358e334ad8fSJed Brown CeedScalar dFlux[5][3]; 3592b89d87eSLeila Ghaffari FluxTotal(dF_inviscid, dstress, dFe, dFlux); 360e334ad8fSJed Brown 3612b730f8bSJeremy L Thompson for (int j = 0; j < 3; j++) { 3622b730f8bSJeremy 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]); 3632b730f8bSJeremy L Thompson } 364e334ad8fSJed Brown 365e334ad8fSJed Brown const CeedScalar dbody_force[5] = {0, ds.U.density * g[0], ds.U.density * g[1], ds.U.density * g[2], 0}; 3663d02368aSJames Wright CeedScalar dU[5] = {0.}; 3673d02368aSJames Wright UnpackState_U(ds.U, dU); 3682b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) v[j][i] = wdetJ * (context->ijacobian_time_shift * dU[j] - dbody_force[j]); 369e334ad8fSJed Brown 370530ad8c4SKenneth E. Jansen if (context->idl_enable) { 371530ad8c4SKenneth E. Jansen CeedScalar damp_state[5] = {ds.Y.pressure, 0, 0, 0, 0}, idl_residual[5] = {0.}; 372530ad8c4SKenneth E. Jansen // This is a Picard-type linearization of the damping and could be replaced by an InternalDampingLayer_fwd that uses s and ds. 373530ad8c4SKenneth E. Jansen InternalDampingLayer(context, s, x_i, damp_state, idl_residual); 374530ad8c4SKenneth E. Jansen for (int j = 0; j < 5; j++) v[j][i] += wdetJ * idl_residual[j]; 375530ad8c4SKenneth E. Jansen } 376530ad8c4SKenneth E. Jansen 3772b89d87eSLeila Ghaffari // -- Stabilization method: none (Galerkin), SU, or SUPG 3782b89d87eSLeila Ghaffari CeedScalar dstab[5][3], U_dot[5] = {0}; 3792b89d87eSLeila Ghaffari for (CeedInt j = 0; j < 5; j++) U_dot[j] = context->ijacobian_time_shift * dU[j]; 3802b89d87eSLeila Ghaffari Stabilization(context, s, Tau_d, grad_ds, U_dot, dbody_force, x_i, dstab); 3812b89d87eSLeila Ghaffari 3822b730f8bSJeremy L Thompson for (int j = 0; j < 5; j++) { 3832b730f8bSJeremy 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]); 3842b730f8bSJeremy L Thompson } 385e334ad8fSJed Brown } // End Quadrature Point Loop 386e334ad8fSJed Brown return 0; 387e334ad8fSJed Brown } 38865dd5cafSJames Wright 3892b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3903d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 3913d02368aSJames Wright } 3923d02368aSJames Wright 3932b730f8bSJeremy L Thompson CEED_QFUNCTION(IJacobian_Newtonian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 3943d02368aSJames Wright return IJacobian_Newtonian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 3953d02368aSJames Wright } 3963d02368aSJames Wright 3972b89d87eSLeila Ghaffari // ***************************************************************************** 39865dd5cafSJames Wright // Compute boundary integral (ie. for strongly set inflows) 3992b89d87eSLeila Ghaffari // ***************************************************************************** 4002b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateFromQi_t StateFromQi, 4012b730f8bSJeremy L Thompson StateFromQi_fwd_t StateFromQi_fwd) { 40246603fc5SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 40346603fc5SJames Wright const CeedScalar(*Grad_q)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 40446603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 40546603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 40665dd5cafSJames Wright 40746603fc5SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 40846603fc5SJames Wright CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 40965dd5cafSJames Wright 4102c4e60d7SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 4112c4e60d7SJames Wright const bool is_implicit = context->is_implicit; 41265dd5cafSJames Wright 4132b730f8bSJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 4142c4e60d7SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 415efe9d856SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 416efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 41765dd5cafSJames Wright 41865dd5cafSJames Wright const CeedScalar wdetJb = (is_implicit ? -1. : 1.) * q_data_sur[0][i]; 4195bce47c7SJames Wright // ---- Normal vector 4202b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 42165dd5cafSJames Wright 4222c4e60d7SJames Wright const CeedScalar dXdx[2][3] = { 4232c4e60d7SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 4242c4e60d7SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 4252c4e60d7SJames Wright }; 42665dd5cafSJames Wright 4272c4e60d7SJames Wright State grad_s[3]; 4282c4e60d7SJames Wright for (CeedInt j = 0; j < 3; j++) { 429efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi[5]; 4302b730f8bSJeremy 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]; 4312c4e60d7SJames Wright dx_i[j] = 1.; 432efe9d856SJames Wright grad_s[j] = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 4332c4e60d7SJames Wright } 43465dd5cafSJames Wright 4352c4e60d7SJames Wright CeedScalar strain_rate[6], kmstress[6], stress[3][3], Fe[3]; 436*d08fcc28SJames Wright KMStrainRate_State(grad_s, strain_rate); 4372c4e60d7SJames Wright NewtonianStress(context, strain_rate, kmstress); 4382c4e60d7SJames Wright KMUnpack(kmstress, stress); 4392c4e60d7SJames Wright ViscousEnergyFlux(context, s.Y, grad_s, stress, Fe); 4402c4e60d7SJames Wright 4412c4e60d7SJames Wright StateConservative F_inviscid[3]; 4422c4e60d7SJames Wright FluxInviscid(context, s, F_inviscid); 4432c4e60d7SJames Wright 4445bce47c7SJames Wright CeedScalar Flux[5]; 4455bce47c7SJames Wright FluxTotal_Boundary(F_inviscid, stress, Fe, norm, Flux); 4462c4e60d7SJames Wright 4475bce47c7SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = -wdetJb * Flux[j]; 44865dd5cafSJames Wright 4495bce47c7SJames Wright for (int j = 0; j < 5; j++) jac_data_sur[j][i] = qi[j]; 450b55ac660SJames Wright for (int j = 0; j < 6; j++) jac_data_sur[5 + j][i] = kmstress[j]; 45165dd5cafSJames Wright } 45265dd5cafSJames Wright return 0; 45365dd5cafSJames Wright } 45465dd5cafSJames Wright 4552b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 45620840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromU, StateFromU_fwd); 45720840d50SJames Wright } 45820840d50SJames Wright 4592b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 46020840d50SJames Wright return BoundaryIntegral(ctx, Q, in, out, StateFromY, StateFromY_fwd); 46120840d50SJames Wright } 46220840d50SJames Wright 4632b89d87eSLeila Ghaffari // ***************************************************************************** 464b55ac660SJames Wright // Jacobian for "set nothing" boundary integral 4652b89d87eSLeila Ghaffari // ***************************************************************************** 4662b730f8bSJeremy L Thompson CEED_QFUNCTION_HELPER int BoundaryIntegral_Jacobian(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, 46720840d50SJames Wright StateFromQi_t StateFromQi, StateFromQi_fwd_t StateFromQi_fwd) { 468b55ac660SJames Wright // Inputs 46946603fc5SJames Wright const CeedScalar(*dq)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 47046603fc5SJames Wright const CeedScalar(*Grad_dq)[5][CEED_Q_VLA] = (const CeedScalar(*)[5][CEED_Q_VLA])in[1]; 47146603fc5SJames Wright const CeedScalar(*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 47246603fc5SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 47346603fc5SJames Wright const CeedScalar(*jac_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[4]; 47446603fc5SJames Wright 475b55ac660SJames Wright // Outputs 476b55ac660SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 477b55ac660SJames Wright 478b55ac660SJames Wright const NewtonianIdealGasContext context = (NewtonianIdealGasContext)ctx; 479b55ac660SJames Wright const bool implicit = context->is_implicit; 480b55ac660SJames Wright 481b55ac660SJames Wright // Quadrature Point Loop 48246603fc5SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 483b55ac660SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 484b55ac660SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 4852b730f8bSJeremy L Thompson const CeedScalar norm[3] = {q_data_sur[1][i], q_data_sur[2][i], q_data_sur[3][i]}; 486b55ac660SJames Wright const CeedScalar dXdx[2][3] = { 487b55ac660SJames Wright {q_data_sur[4][i], q_data_sur[5][i], q_data_sur[6][i]}, 488b55ac660SJames Wright {q_data_sur[7][i], q_data_sur[8][i], q_data_sur[9][i]} 489b55ac660SJames Wright }; 490b55ac660SJames Wright 491efe9d856SJames Wright CeedScalar qi[5], kmstress[6], dqi[5], dx_i[3] = {0.}; 492efe9d856SJames Wright for (int j = 0; j < 5; j++) qi[j] = jac_data_sur[j][i]; 493b55ac660SJames Wright for (int j = 0; j < 6; j++) kmstress[j] = jac_data_sur[5 + j][i]; 494efe9d856SJames Wright for (int j = 0; j < 5; j++) dqi[j] = dq[j][i]; 49557e55a1cSJames Wright 496efe9d856SJames Wright State s = StateFromQi(context, qi, x_i); 497efe9d856SJames Wright State ds = StateFromQi_fwd(context, s, dqi, x_i, dx_i); 498b55ac660SJames Wright 499b55ac660SJames Wright State grad_ds[3]; 500b55ac660SJames Wright for (CeedInt j = 0; j < 3; j++) { 501efe9d856SJames Wright CeedScalar dx_i[3] = {0}, dqi_j[5]; 5022b730f8bSJeremy 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]; 503b55ac660SJames Wright dx_i[j] = 1.; 504efe9d856SJames Wright grad_ds[j] = StateFromQi_fwd(context, s, dqi_j, x_i, dx_i); 505b55ac660SJames Wright } 506b55ac660SJames Wright 507b55ac660SJames Wright CeedScalar dstrain_rate[6], dkmstress[6], stress[3][3], dstress[3][3], dFe[3]; 508*d08fcc28SJames Wright KMStrainRate_State(grad_ds, dstrain_rate); 509b55ac660SJames Wright NewtonianStress(context, dstrain_rate, dkmstress); 510b55ac660SJames Wright KMUnpack(dkmstress, dstress); 511b55ac660SJames Wright KMUnpack(kmstress, stress); 512b55ac660SJames Wright ViscousEnergyFlux_fwd(context, s.Y, ds.Y, grad_ds, stress, dstress, dFe); 513b55ac660SJames Wright 514b55ac660SJames Wright StateConservative dF_inviscid[3]; 515b55ac660SJames Wright FluxInviscid_fwd(context, s, ds, dF_inviscid); 516b55ac660SJames Wright 5175bce47c7SJames Wright CeedScalar dFlux[5]; 5185bce47c7SJames Wright FluxTotal_Boundary(dF_inviscid, dstress, dFe, norm, dFlux); 519b55ac660SJames Wright 5205bce47c7SJames Wright for (int j = 0; j < 5; j++) v[j][i] = -wdetJb * dFlux[j]; 521b55ac660SJames Wright } // End Quadrature Point Loop 522b55ac660SJames Wright return 0; 523b55ac660SJames Wright } 524b55ac660SJames Wright 5252b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 52620840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromU, StateFromU_fwd); 52720840d50SJames Wright } 52820840d50SJames Wright 5292b730f8bSJeremy L Thompson CEED_QFUNCTION(BoundaryIntegral_Jacobian_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 53020840d50SJames Wright return BoundaryIntegral_Jacobian(ctx, Q, in, out, StateFromY, StateFromY_fwd); 53120840d50SJames Wright } 53220840d50SJames Wright 53388b783a1SJames Wright #endif // newtonian_h 534