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. 3a515125bSLeila Ghaffari // 4727da7e7SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 5a515125bSLeila Ghaffari // 6727da7e7SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 7a515125bSLeila Ghaffari 8a515125bSLeila Ghaffari /// @file 9a515125bSLeila Ghaffari /// Advection initial condition and operator for Navier-Stokes example using PETSc 10a515125bSLeila Ghaffari 11a515125bSLeila Ghaffari #ifndef advection_h 12a515125bSLeila Ghaffari #define advection_h 13a515125bSLeila Ghaffari 14493642f1SJames Wright #include <ceed.h> 15d0cce58aSJeremy L Thompson #include <math.h> 16a515125bSLeila Ghaffari 17e88b842aSJames Wright #include "advection_types.h" 18ce192147SJames Wright #include "newtonian_state.h" 19ce192147SJames Wright #include "newtonian_types.h" 20e88b842aSJames Wright #include "stabilization_types.h" 211a74fa30SJames Wright #include "utils.h" 221a74fa30SJames Wright 23a515125bSLeila Ghaffari // ***************************************************************************** 24*9529d636SJames Wright // This QFunction sets the initial conditions and the boundary conditions 25*9529d636SJames Wright // for two test cases: ROTATION and TRANSLATION 26*9529d636SJames Wright // 27*9529d636SJames Wright // -- ROTATION (default) 28*9529d636SJames Wright // Initial Conditions: 29*9529d636SJames Wright // Mass Density: 30*9529d636SJames Wright // Constant mass density of 1.0 31*9529d636SJames Wright // Momentum Density: 32*9529d636SJames Wright // Rotational field in x,y 33*9529d636SJames Wright // Energy Density: 34*9529d636SJames Wright // Maximum of 1. x0 decreasing linearly to 0. as radial distance 35*9529d636SJames Wright // increases to (1.-r/rc), then 0. everywhere else 36*9529d636SJames Wright // 37*9529d636SJames Wright // Boundary Conditions: 38*9529d636SJames Wright // Mass Density: 39*9529d636SJames Wright // 0.0 flux 40*9529d636SJames Wright // Momentum Density: 41*9529d636SJames Wright // 0.0 42*9529d636SJames Wright // Energy Density: 43*9529d636SJames Wright // 0.0 flux 44*9529d636SJames Wright // 45*9529d636SJames Wright // -- TRANSLATION 46*9529d636SJames Wright // Initial Conditions: 47*9529d636SJames Wright // Mass Density: 48*9529d636SJames Wright // Constant mass density of 1.0 49*9529d636SJames Wright // Momentum Density: 50*9529d636SJames Wright // Constant rectilinear field in x,y 51*9529d636SJames Wright // Energy Density: 52*9529d636SJames Wright // Maximum of 1. x0 decreasing linearly to 0. as radial distance 53*9529d636SJames Wright // increases to (1.-r/rc), then 0. everywhere else 54*9529d636SJames Wright // 55*9529d636SJames Wright // Boundary Conditions: 56*9529d636SJames Wright // Mass Density: 57*9529d636SJames Wright // 0.0 flux 58*9529d636SJames Wright // Momentum Density: 59*9529d636SJames Wright // 0.0 60*9529d636SJames Wright // Energy Density: 61*9529d636SJames Wright // Inflow BCs: 62*9529d636SJames Wright // E = E_wind 63*9529d636SJames Wright // Outflow BCs: 64*9529d636SJames Wright // E = E(boundary) 65*9529d636SJames Wright // Both In/Outflow BCs for E are applied weakly in the 66*9529d636SJames Wright // QFunction "Advection2d_Sur" 67*9529d636SJames Wright // 68*9529d636SJames Wright // ***************************************************************************** 69*9529d636SJames Wright 70*9529d636SJames Wright // ***************************************************************************** 71*9529d636SJames Wright // This helper function provides the exact, time-dependent solution and IC formulation for 2D advection 72*9529d636SJames Wright // ***************************************************************************** 73*9529d636SJames Wright CEED_QFUNCTION_HELPER CeedInt Exact_AdvectionGeneric(CeedInt dim, CeedScalar time, const CeedScalar X[], CeedInt Nf, CeedScalar q[], void *ctx) { 74*9529d636SJames Wright const SetupContextAdv context = (SetupContextAdv)ctx; 75*9529d636SJames Wright const CeedScalar rc = context->rc; 76*9529d636SJames Wright const CeedScalar lx = context->lx; 77*9529d636SJames Wright const CeedScalar ly = context->ly; 78*9529d636SJames Wright const CeedScalar lz = dim == 2 ? 0. : context->lz; 79*9529d636SJames Wright const CeedScalar *wind = context->wind; 80*9529d636SJames Wright 81*9529d636SJames Wright const CeedScalar center[3] = {0.5 * lx, 0.5 * ly, 0.5 * lz}; 82*9529d636SJames Wright const CeedScalar theta = dim == 2 ? M_PI / 3 : M_PI; 83*9529d636SJames Wright const CeedScalar x0[3] = {center[0] + .25 * lx * cos(theta + time), center[1] + .25 * ly * sin(theta + time), 0.5 * lz}; 84*9529d636SJames Wright 85*9529d636SJames Wright const CeedScalar x = X[0], y = X[1], z = dim == 2 ? 0. : X[2]; 86*9529d636SJames Wright 87*9529d636SJames Wright CeedScalar r = 0.; 88*9529d636SJames Wright switch (context->initial_condition_type) { 89*9529d636SJames Wright case ADVECTIONIC_BUBBLE_SPHERE: 90*9529d636SJames Wright case ADVECTIONIC_BUBBLE_CYLINDER: 91*9529d636SJames Wright r = sqrt(Square(x - x0[0]) + Square(y - x0[1]) + Square(z - x0[2])); 92*9529d636SJames Wright break; 93*9529d636SJames Wright case ADVECTIONIC_COSINE_HILL: 94*9529d636SJames Wright r = sqrt(Square(x - center[0]) + Square(y - center[1])); 95*9529d636SJames Wright break; 96*9529d636SJames Wright case ADVECTIONIC_SKEW: 97*9529d636SJames Wright break; 98*9529d636SJames Wright } 99*9529d636SJames Wright 100*9529d636SJames Wright switch (context->wind_type) { 101*9529d636SJames Wright case WIND_ROTATION: 102*9529d636SJames Wright q[0] = 1.; 103*9529d636SJames Wright q[1] = -(y - center[1]); 104*9529d636SJames Wright q[2] = (x - center[0]); 105*9529d636SJames Wright q[3] = 0; 106*9529d636SJames Wright break; 107*9529d636SJames Wright case WIND_TRANSLATION: 108*9529d636SJames Wright q[0] = 1.; 109*9529d636SJames Wright q[1] = wind[0]; 110*9529d636SJames Wright q[2] = wind[1]; 111*9529d636SJames Wright q[3] = dim == 2 ? 0. : wind[2]; 112*9529d636SJames Wright break; 113*9529d636SJames Wright default: 114*9529d636SJames Wright return 1; 115*9529d636SJames Wright } 116*9529d636SJames Wright 117*9529d636SJames Wright switch (context->initial_condition_type) { 118*9529d636SJames Wright case ADVECTIONIC_BUBBLE_SPHERE: 119*9529d636SJames Wright case ADVECTIONIC_BUBBLE_CYLINDER: 120*9529d636SJames Wright switch (context->bubble_continuity_type) { 121*9529d636SJames Wright // original continuous, smooth shape 122*9529d636SJames Wright case BUBBLE_CONTINUITY_SMOOTH: 123*9529d636SJames Wright q[4] = r <= rc ? (1. - r / rc) : 0.; 124*9529d636SJames Wright break; 125*9529d636SJames Wright // discontinuous, sharp back half shape 126*9529d636SJames Wright case BUBBLE_CONTINUITY_BACK_SHARP: 127*9529d636SJames Wright q[4] = ((r <= rc) && (y < center[1])) ? (1. - r / rc) : 0.; 128*9529d636SJames Wright break; 129*9529d636SJames Wright // attempt to define a finite thickness that will get resolved under grid refinement 130*9529d636SJames Wright case BUBBLE_CONTINUITY_THICK: 131*9529d636SJames Wright q[4] = ((r <= rc) && (y < center[1])) ? (1. - r / rc) * fmin(1.0, (center[1] - y) / 1.25) : 0.; 132*9529d636SJames Wright break; 133*9529d636SJames Wright case BUBBLE_CONTINUITY_COSINE: 134*9529d636SJames Wright q[4] = r <= rc ? .5 + .5 * cos(r * M_PI / rc) : 0; 135*9529d636SJames Wright break; 136*9529d636SJames Wright } 137*9529d636SJames Wright break; 138*9529d636SJames Wright case ADVECTIONIC_COSINE_HILL: { 139*9529d636SJames Wright CeedScalar half_width = context->lx / 2; 140*9529d636SJames Wright q[4] = r > half_width ? 0. : cos(2 * M_PI * r / half_width + M_PI) + 1.; 141*9529d636SJames Wright } break; 142*9529d636SJames Wright case ADVECTIONIC_SKEW: { 143*9529d636SJames Wright CeedScalar skewed_barrier[3] = {wind[0], wind[1], 0}; 144*9529d636SJames Wright CeedScalar inflow_to_point[3] = {x - context->lx / 2, y, 0}; 145*9529d636SJames Wright CeedScalar cross_product[3] = {0}; 146*9529d636SJames Wright const CeedScalar boundary_threshold = 20 * CEED_EPSILON; 147*9529d636SJames Wright Cross3(skewed_barrier, inflow_to_point, cross_product); 148*9529d636SJames Wright 149*9529d636SJames Wright q[4] = cross_product[2] > boundary_threshold ? 0 : 1; 150*9529d636SJames Wright if ((x < boundary_threshold && wind[0] < boundary_threshold) || // outflow at -x boundary 151*9529d636SJames Wright (y < boundary_threshold && wind[1] < boundary_threshold) || // outflow at -y boundary 152*9529d636SJames Wright (x > context->lx - boundary_threshold && wind[0] > boundary_threshold) || // outflow at +x boundary 153*9529d636SJames Wright (y > context->ly - boundary_threshold && wind[1] > boundary_threshold) // outflow at +y boundary 154*9529d636SJames Wright ) { 155*9529d636SJames Wright q[4] = 0; 156*9529d636SJames Wright } 157*9529d636SJames Wright } break; 158*9529d636SJames Wright } 159*9529d636SJames Wright return 0; 160*9529d636SJames Wright } 161*9529d636SJames Wright 162*9529d636SJames Wright // ***************************************************************************** 163a515125bSLeila Ghaffari // This QFunction sets the initial conditions for 3D advection 164a515125bSLeila Ghaffari // ***************************************************************************** 1652b916ea7SJeremy L Thompson CEED_QFUNCTION(ICsAdvection)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 166a515125bSLeila Ghaffari const CeedScalar(*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 167a515125bSLeila Ghaffari CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 168a515125bSLeila Ghaffari 1693d65b166SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 170a515125bSLeila Ghaffari const CeedScalar x[] = {X[0][i], X[1][i], X[2][i]}; 171139613f2SLeila Ghaffari CeedScalar q[5] = {0.}; 172a515125bSLeila Ghaffari 1730b3a1fabSJames Wright Exact_AdvectionGeneric(3, 0., x, 5, q, ctx); 174a515125bSLeila Ghaffari for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 1750b3a1fabSJames Wright } 176a515125bSLeila Ghaffari return 0; 177a515125bSLeila Ghaffari } 178a515125bSLeila Ghaffari 179a515125bSLeila Ghaffari // ***************************************************************************** 180*9529d636SJames Wright // This QFunction sets the initial conditions for 2D advection 181a515125bSLeila Ghaffari // ***************************************************************************** 182*9529d636SJames Wright CEED_QFUNCTION(ICsAdvection2d)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 183*9529d636SJames Wright const CeedScalar(*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 184*9529d636SJames Wright CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 185*9529d636SJames Wright const SetupContextAdv context = (SetupContextAdv)ctx; 186*9529d636SJames Wright 187*9529d636SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 188*9529d636SJames Wright const CeedScalar x[] = {X[0][i], X[1][i]}; 189*9529d636SJames Wright CeedScalar q[5] = {0.}; 190*9529d636SJames Wright 191*9529d636SJames Wright Exact_AdvectionGeneric(2, context->time, x, 5, q, ctx); 192*9529d636SJames Wright for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 193*9529d636SJames Wright } 194a515125bSLeila Ghaffari return 0; 195a515125bSLeila Ghaffari } 196a515125bSLeila Ghaffari 197*9529d636SJames Wright CEED_QFUNCTION_HELPER void QdataUnpack_ND(CeedInt N, CeedInt Q, CeedInt i, const CeedScalar *q_data, CeedScalar *wdetJ, CeedScalar *dXdx) { 198*9529d636SJames Wright switch (N) { 199*9529d636SJames Wright case 2: 200*9529d636SJames Wright QdataUnpack_2D(Q, i, q_data, wdetJ, (CeedScalar(*)[2])dXdx); 201*9529d636SJames Wright break; 202*9529d636SJames Wright case 3: 203*9529d636SJames Wright QdataUnpack_3D(Q, i, q_data, wdetJ, (CeedScalar(*)[3])dXdx); 204*9529d636SJames Wright break; 205*9529d636SJames Wright } 206*9529d636SJames Wright } 207*9529d636SJames Wright 208*9529d636SJames Wright CEED_QFUNCTION_HELPER int QdataBoundaryUnpack_ND(CeedInt N, CeedInt Q, CeedInt i, const CeedScalar *q_data, CeedScalar *wdetJ, CeedScalar *dXdx, 209*9529d636SJames Wright CeedScalar *normal) { 210*9529d636SJames Wright switch (N) { 211*9529d636SJames Wright case 2: 212*9529d636SJames Wright QdataBoundaryUnpack_2D(Q, i, q_data, wdetJ, normal); 213*9529d636SJames Wright break; 214*9529d636SJames Wright case 3: 215*9529d636SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data, wdetJ, (CeedScalar(*)[3])dXdx, normal); 216*9529d636SJames Wright break; 217*9529d636SJames Wright } 218*9529d636SJames Wright return CEED_ERROR_SUCCESS; 219*9529d636SJames Wright } 220*9529d636SJames Wright 221*9529d636SJames Wright CEED_QFUNCTION_HELPER void StatePhysicalGradientFromReference_ND(CeedInt N, CeedInt Q, CeedInt i, NewtonianIdealGasContext gas, State s, 222*9529d636SJames Wright StateVariable state_var, const CeedScalar *grad_q, const CeedScalar *dXdx, 223*9529d636SJames Wright State *grad_s) { 224*9529d636SJames Wright switch (N) { 225*9529d636SJames Wright case 2: { 226*9529d636SJames Wright for (CeedInt k = 0; k < 2; k++) { 227*9529d636SJames Wright CeedScalar dqi[5]; 228*9529d636SJames Wright for (CeedInt j = 0; j < 5; j++) { 229*9529d636SJames Wright dqi[j] = grad_q[(Q * 5) * 0 + Q * j + i] * dXdx[0 * N + k] + grad_q[(Q * 5) * 1 + Q * j + i] * dXdx[1 * N + k]; 230*9529d636SJames Wright } 231*9529d636SJames Wright grad_s[k] = StateFromQ_fwd(gas, s, dqi, state_var); 232*9529d636SJames Wright } 233*9529d636SJames Wright CeedScalar U[5] = {0.}; 234*9529d636SJames Wright grad_s[2] = StateFromU(gas, U); 235*9529d636SJames Wright } break; 236*9529d636SJames Wright case 3: 237*9529d636SJames Wright StatePhysicalGradientFromReference(Q, i, gas, s, state_var, grad_q, (CeedScalar(*)[3])dXdx, grad_s); 238*9529d636SJames Wright break; 239*9529d636SJames Wright } 240*9529d636SJames Wright } 241*9529d636SJames Wright 242*9529d636SJames Wright // ***************************************************************************** 243*9529d636SJames Wright // This QFunction implements Advection for implicit time stepping method 244*9529d636SJames Wright // ***************************************************************************** 245*9529d636SJames Wright CEED_QFUNCTION_HELPER void IFunction_AdvectionGeneric(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, CeedInt dim) { 246*9529d636SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 247*9529d636SJames Wright const CeedScalar(*grad_q) = in[1]; 248*9529d636SJames Wright const CeedScalar(*q_dot)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 249*9529d636SJames Wright const CeedScalar(*q_data) = in[3]; 250*9529d636SJames Wright 251*9529d636SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 252*9529d636SJames Wright CeedScalar(*grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 253*9529d636SJames Wright CeedScalar *jac_data = out[2]; 254*9529d636SJames Wright 255*9529d636SJames Wright AdvectionContext context = (AdvectionContext)ctx; 256*9529d636SJames Wright const CeedScalar CtauS = context->CtauS; 257*9529d636SJames Wright const CeedScalar zeros[14] = {0.}; 258*9529d636SJames Wright NewtonianIdealGasContext gas; 259*9529d636SJames Wright struct NewtonianIdealGasContext_ gas_struct = {0}; 260*9529d636SJames Wright gas = &gas_struct; 261*9529d636SJames Wright 262*9529d636SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 263*9529d636SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 264*9529d636SJames Wright const State s = StateFromU(gas, qi); 265*9529d636SJames Wright 266*9529d636SJames Wright CeedScalar wdetJ, dXdx[9]; 267*9529d636SJames Wright QdataUnpack_ND(dim, Q, i, q_data, &wdetJ, dXdx); 268*9529d636SJames Wright State grad_s[3]; 269*9529d636SJames Wright StatePhysicalGradientFromReference_ND(dim, Q, i, gas, s, STATEVAR_CONSERVATIVE, grad_q, dXdx, grad_s); 270*9529d636SJames Wright 271*9529d636SJames Wright const CeedScalar Grad_E[3] = {grad_s[0].U.E_total, grad_s[1].U.E_total, grad_s[2].U.E_total}; 272*9529d636SJames Wright 273*9529d636SJames Wright for (CeedInt f = 0; f < 4; f++) { 274*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) grad_v[j][f][i] = 0; // No Change in density or momentum 275*9529d636SJames Wright v[f][i] = wdetJ * q_dot[f][i]; // K Mass/transient term 276*9529d636SJames Wright } 277*9529d636SJames Wright 278*9529d636SJames Wright CeedScalar div_u = 0; 279*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) { 280*9529d636SJames Wright for (CeedInt k = 0; k < dim; k++) { 281*9529d636SJames Wright div_u += grad_s[k].Y.velocity[j]; 282*9529d636SJames Wright } 283*9529d636SJames Wright } 284*9529d636SJames Wright CeedScalar strong_conv = s.U.E_total * div_u + DotN(s.Y.velocity, Grad_E, dim); 285*9529d636SJames Wright CeedScalar strong_res = q_dot[4][i] + strong_conv; 286*9529d636SJames Wright 287*9529d636SJames Wright v[4][i] = wdetJ * q_dot[4][i]; // transient part (ALWAYS) 288*9529d636SJames Wright 289*9529d636SJames Wright CeedScalar uX[3] = {0.}; 290*9529d636SJames Wright MatVecNM(dXdx, s.Y.velocity, dim, dim, CEED_NOTRANSPOSE, uX); 291*9529d636SJames Wright 292*9529d636SJames Wright if (context->strong_form) { // Strong Galerkin convection term: v div(E u) 293*9529d636SJames Wright v[4][i] += wdetJ * strong_conv; 294*9529d636SJames Wright } else { // Weak Galerkin convection term: -dv \cdot (E u) 295*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) grad_v[j][4][i] = -wdetJ * s.U.E_total * uX[j]; 296*9529d636SJames Wright } 297*9529d636SJames Wright 298*9529d636SJames Wright const CeedScalar TauS = CtauS / sqrt(Dot3(uX, uX)); 299*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) switch (context->stabilization) { 300*9529d636SJames Wright case STAB_NONE: 301*9529d636SJames Wright break; 302*9529d636SJames Wright case STAB_SU: 303*9529d636SJames Wright grad_v[j][4][i] += wdetJ * TauS * strong_conv * uX[j]; 304*9529d636SJames Wright break; 305*9529d636SJames Wright case STAB_SUPG: 306*9529d636SJames Wright grad_v[j][4][i] += wdetJ * TauS * strong_res * uX[j]; 307*9529d636SJames Wright break; 308*9529d636SJames Wright } 309*9529d636SJames Wright StoredValuesPack(Q, i, 0, 14, zeros, jac_data); 310*9529d636SJames Wright } 311*9529d636SJames Wright } 312*9529d636SJames Wright 3132b916ea7SJeremy L Thompson CEED_QFUNCTION(IFunction_Advection)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 314bd4b5413SJames Wright IFunction_AdvectionGeneric(ctx, Q, in, out, 3); 315a515125bSLeila Ghaffari return 0; 316a515125bSLeila Ghaffari } 317a515125bSLeila Ghaffari 318*9529d636SJames Wright CEED_QFUNCTION(IFunction_Advection2d)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 319*9529d636SJames Wright IFunction_AdvectionGeneric(ctx, Q, in, out, 2); 320*9529d636SJames Wright return 0; 321*9529d636SJames Wright } 322*9529d636SJames Wright 323*9529d636SJames Wright // ***************************************************************************** 324*9529d636SJames Wright // This QFunction implements Advection for explicit time stepping method 325*9529d636SJames Wright // ***************************************************************************** 326*9529d636SJames Wright CEED_QFUNCTION_HELPER void RHSFunction_AdvectionGeneric(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, CeedInt dim) { 327*9529d636SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 328*9529d636SJames Wright const CeedScalar(*grad_q) = in[1]; 329*9529d636SJames Wright const CeedScalar(*q_data) = in[2]; 330*9529d636SJames Wright 331*9529d636SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 332*9529d636SJames Wright CeedScalar(*grad_v)[5][CEED_Q_VLA] = (CeedScalar(*)[5][CEED_Q_VLA])out[1]; 333*9529d636SJames Wright 334*9529d636SJames Wright AdvectionContext context = (AdvectionContext)ctx; 335*9529d636SJames Wright const CeedScalar CtauS = context->CtauS; 336*9529d636SJames Wright NewtonianIdealGasContext gas; 337*9529d636SJames Wright struct NewtonianIdealGasContext_ gas_struct = {0}; 338*9529d636SJames Wright gas = &gas_struct; 339*9529d636SJames Wright 340*9529d636SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 341*9529d636SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 342*9529d636SJames Wright const State s = StateFromU(gas, qi); 343*9529d636SJames Wright 344*9529d636SJames Wright CeedScalar wdetJ, dXdx[9]; 345*9529d636SJames Wright QdataUnpack_ND(dim, Q, i, q_data, &wdetJ, dXdx); 346*9529d636SJames Wright State grad_s[3]; 347*9529d636SJames Wright StatePhysicalGradientFromReference_ND(dim, Q, i, gas, s, STATEVAR_CONSERVATIVE, grad_q, dXdx, grad_s); 348*9529d636SJames Wright 349*9529d636SJames Wright const CeedScalar Grad_E[3] = {grad_s[0].U.E_total, grad_s[1].U.E_total, grad_s[2].U.E_total}; 350*9529d636SJames Wright 351*9529d636SJames Wright for (CeedInt f = 0; f < 4; f++) { 352*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) grad_v[j][f][i] = 0; // No Change in density or momentum 353*9529d636SJames Wright v[f][i] = 0.; 354*9529d636SJames Wright } 355*9529d636SJames Wright 356*9529d636SJames Wright CeedScalar div_u = 0; 357*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) { 358*9529d636SJames Wright for (CeedInt k = 0; k < dim; k++) { 359*9529d636SJames Wright div_u += grad_s[k].Y.velocity[j]; 360*9529d636SJames Wright } 361*9529d636SJames Wright } 362*9529d636SJames Wright CeedScalar strong_conv = s.U.E_total * div_u + DotN(s.Y.velocity, Grad_E, dim); 363*9529d636SJames Wright 364*9529d636SJames Wright CeedScalar uX[3] = {0.}; 365*9529d636SJames Wright MatVecNM(dXdx, s.Y.velocity, dim, dim, CEED_NOTRANSPOSE, uX); 366*9529d636SJames Wright 367*9529d636SJames Wright if (context->strong_form) { // Strong Galerkin convection term: v div(E u) 368*9529d636SJames Wright v[4][i] = -wdetJ * strong_conv; 369*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) grad_v[j][4][i] = 0; 370*9529d636SJames Wright } else { // Weak Galerkin convection term: -dv \cdot (E u) 371*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) grad_v[j][4][i] = wdetJ * s.U.E_total * uX[j]; 372*9529d636SJames Wright v[4][i] = 0.; 373*9529d636SJames Wright } 374*9529d636SJames Wright 375*9529d636SJames Wright const CeedScalar TauS = CtauS / sqrt(Dot3(uX, uX)); 376*9529d636SJames Wright for (CeedInt j = 0; j < dim; j++) switch (context->stabilization) { 377*9529d636SJames Wright case STAB_NONE: 378*9529d636SJames Wright break; 379*9529d636SJames Wright case STAB_SU: 380*9529d636SJames Wright case STAB_SUPG: 381*9529d636SJames Wright grad_v[j][4][i] += wdetJ * TauS * strong_conv * uX[j]; 382*9529d636SJames Wright break; 383*9529d636SJames Wright } 384*9529d636SJames Wright } 385*9529d636SJames Wright } 386*9529d636SJames Wright 387*9529d636SJames Wright CEED_QFUNCTION(RHS_Advection)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 388*9529d636SJames Wright RHSFunction_AdvectionGeneric(ctx, Q, in, out, 3); 389*9529d636SJames Wright return 0; 390*9529d636SJames Wright } 391*9529d636SJames Wright 392*9529d636SJames Wright CEED_QFUNCTION(RHS_Advection2d)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 393*9529d636SJames Wright RHSFunction_AdvectionGeneric(ctx, Q, in, out, 2); 394*9529d636SJames Wright return 0; 395*9529d636SJames Wright } 396*9529d636SJames Wright 397*9529d636SJames Wright // ***************************************************************************** 398*9529d636SJames Wright // This QFunction implements consistent outflow and inflow BCs 399*9529d636SJames Wright // for advection 400*9529d636SJames Wright // 401*9529d636SJames Wright // Inflow and outflow faces are determined based on sign(dot(wind, normal)): 402*9529d636SJames Wright // sign(dot(wind, normal)) > 0 : outflow BCs 403*9529d636SJames Wright // sign(dot(wind, normal)) < 0 : inflow BCs 404*9529d636SJames Wright // 405*9529d636SJames Wright // Outflow BCs: 406*9529d636SJames Wright // The validity of the weak form of the governing equations is extended to the outflow and the current values of E are applied. 407*9529d636SJames Wright // 408*9529d636SJames Wright // Inflow BCs: 409*9529d636SJames Wright // A prescribed Total Energy (E_wind) is applied weakly. 410*9529d636SJames Wright // ***************************************************************************** 411*9529d636SJames Wright CEED_QFUNCTION(Advection_InOutFlowGeneric)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, CeedInt dim) { 412*9529d636SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 413*9529d636SJames Wright const CeedScalar(*q_data_sur) = in[2]; 414*9529d636SJames Wright 415*9529d636SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 416*9529d636SJames Wright AdvectionContext context = (AdvectionContext)ctx; 417*9529d636SJames Wright const CeedScalar E_wind = context->E_wind; 418*9529d636SJames Wright const CeedScalar strong_form = context->strong_form; 419*9529d636SJames Wright const bool is_implicit = context->implicit; 420*9529d636SJames Wright 421*9529d636SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 422*9529d636SJames Wright const CeedScalar rho = q[0][i]; 423*9529d636SJames Wright const CeedScalar u[3] = {q[1][i] / rho, q[2][i] / rho, q[3][i] / rho}; 424*9529d636SJames Wright const CeedScalar E = q[4][i]; 425*9529d636SJames Wright 426*9529d636SJames Wright CeedScalar wdetJb, norm[3]; 427*9529d636SJames Wright QdataBoundaryUnpack_ND(dim, Q, i, q_data_sur, &wdetJb, NULL, norm); 428*9529d636SJames Wright wdetJb *= is_implicit ? -1. : 1.; 429*9529d636SJames Wright 430*9529d636SJames Wright const CeedScalar u_normal = DotN(norm, u, dim); 431*9529d636SJames Wright 432*9529d636SJames Wright // No Change in density or momentum 433*9529d636SJames Wright for (CeedInt j = 0; j < 4; j++) { 434*9529d636SJames Wright v[j][i] = 0; 435*9529d636SJames Wright } 436*9529d636SJames Wright // Implementing in/outflow BCs 437*9529d636SJames Wright if (u_normal > 0) { // outflow 438*9529d636SJames Wright v[4][i] = -(1 - strong_form) * wdetJb * E * u_normal; 439*9529d636SJames Wright } else { // inflow 440*9529d636SJames Wright v[4][i] = -(1 - strong_form) * wdetJb * E_wind * u_normal; 441*9529d636SJames Wright } 442*9529d636SJames Wright } 443*9529d636SJames Wright return 0; 444*9529d636SJames Wright } 445*9529d636SJames Wright 4462b916ea7SJeremy L Thompson CEED_QFUNCTION(Advection_InOutFlow)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 4478dba1efaSJames Wright Advection_InOutFlowGeneric(ctx, Q, in, out, 3); 448a515125bSLeila Ghaffari return 0; 449a515125bSLeila Ghaffari } 450a515125bSLeila Ghaffari 451*9529d636SJames Wright CEED_QFUNCTION(Advection2d_InOutFlow)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 452*9529d636SJames Wright Advection_InOutFlowGeneric(ctx, Q, in, out, 2); 453*9529d636SJames Wright return 0; 454*9529d636SJames Wright } 455*9529d636SJames Wright 456a515125bSLeila Ghaffari #endif // advection_h 457