1*bb8a0c61SJames Wright // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 2*bb8a0c61SJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3*bb8a0c61SJames Wright // 4*bb8a0c61SJames Wright // SPDX-License-Identifier: BSD-2-Clause 5*bb8a0c61SJames Wright // 6*bb8a0c61SJames Wright // This file is part of CEED: http://github.com/ceed 7*bb8a0c61SJames Wright 8*bb8a0c61SJames Wright /// @file 9*bb8a0c61SJames Wright /// Operator for Navier-Stokes example using PETSc 10*bb8a0c61SJames Wright 11*bb8a0c61SJames Wright 12*bb8a0c61SJames Wright #ifndef channel_h 13*bb8a0c61SJames Wright #define channel_h 14*bb8a0c61SJames Wright 15*bb8a0c61SJames Wright #include <math.h> 16*bb8a0c61SJames Wright #include <ceed.h> 17*bb8a0c61SJames Wright #include "../navierstokes.h" 18*bb8a0c61SJames Wright 19*bb8a0c61SJames Wright #ifndef channel_context_struct 20*bb8a0c61SJames Wright #define channel_context_struct 21*bb8a0c61SJames Wright typedef struct ChannelContext_ *ChannelContext; 22*bb8a0c61SJames Wright struct ChannelContext_ { 23*bb8a0c61SJames Wright bool implicit; // !< Using implicit timesteping or not 24*bb8a0c61SJames Wright CeedScalar theta0; // !< Reference temperature 25*bb8a0c61SJames Wright CeedScalar P0; // !< Reference Pressure 26*bb8a0c61SJames Wright CeedScalar umax; // !< Centerline velocity 27*bb8a0c61SJames Wright CeedScalar center; // !< Y Coordinate for center of channel 28*bb8a0c61SJames Wright CeedScalar H; // !< Channel half-height 29*bb8a0c61SJames Wright CeedScalar B; // !< Body-force driving the flow 30*bb8a0c61SJames Wright struct NewtonianIdealGasContext_ newtonian_ctx; 31*bb8a0c61SJames Wright }; 32*bb8a0c61SJames Wright #endif 33*bb8a0c61SJames Wright 34*bb8a0c61SJames Wright CEED_QFUNCTION_HELPER int Exact_Channel(CeedInt dim, CeedScalar time, 35*bb8a0c61SJames Wright const CeedScalar X[], CeedInt Nf, CeedScalar q[], void *ctx) { 36*bb8a0c61SJames Wright 37*bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 38*bb8a0c61SJames Wright const CeedScalar theta0 = context->theta0; 39*bb8a0c61SJames Wright const CeedScalar P0 = context->P0; 40*bb8a0c61SJames Wright const CeedScalar umax = context->umax; 41*bb8a0c61SJames Wright const CeedScalar center = context->center; 42*bb8a0c61SJames Wright const CeedScalar H = context->H; 43*bb8a0c61SJames Wright const CeedScalar cv = context->newtonian_ctx.cv; 44*bb8a0c61SJames Wright const CeedScalar cp = context->newtonian_ctx.cp; 45*bb8a0c61SJames Wright const CeedScalar Rd = cp - cv; 46*bb8a0c61SJames Wright const CeedScalar mu = context->newtonian_ctx.mu; 47*bb8a0c61SJames Wright const CeedScalar k = context->newtonian_ctx.k; 48*bb8a0c61SJames Wright 49*bb8a0c61SJames Wright const CeedScalar y=X[1]; 50*bb8a0c61SJames Wright 51*bb8a0c61SJames Wright const CeedScalar Pr = mu / (cp*k); 52*bb8a0c61SJames Wright const CeedScalar Ec = (umax*umax) / (cp*theta0); 53*bb8a0c61SJames Wright const CeedScalar theta = theta0*( 1 + (Pr*Ec/3)*(1 - pow((y-center)/H,4))); 54*bb8a0c61SJames Wright 55*bb8a0c61SJames Wright const CeedScalar p = P0; 56*bb8a0c61SJames Wright 57*bb8a0c61SJames Wright const CeedScalar rho = p / (Rd*theta); 58*bb8a0c61SJames Wright 59*bb8a0c61SJames Wright q[0] = rho; 60*bb8a0c61SJames Wright q[1] = rho * umax*(1 - pow((y-center)/H,2)); 61*bb8a0c61SJames Wright q[2] = 0; 62*bb8a0c61SJames Wright q[3] = 0; 63*bb8a0c61SJames Wright q[4] = rho * (cv*theta) + .5 * (q[1]*q[1] + q[2]*q[2] + q[3]*q[3]) / rho; 64*bb8a0c61SJames Wright 65*bb8a0c61SJames Wright return 0; 66*bb8a0c61SJames Wright } 67*bb8a0c61SJames Wright 68*bb8a0c61SJames Wright // ***************************************************************************** 69*bb8a0c61SJames Wright // This QFunction sets the initial condition 70*bb8a0c61SJames Wright // ***************************************************************************** 71*bb8a0c61SJames Wright CEED_QFUNCTION(ICsChannel)(void *ctx, CeedInt Q, 72*bb8a0c61SJames Wright const CeedScalar *const *in, CeedScalar *const *out) { 73*bb8a0c61SJames Wright // Inputs 74*bb8a0c61SJames Wright const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 75*bb8a0c61SJames Wright 76*bb8a0c61SJames Wright // Outputs 77*bb8a0c61SJames Wright CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 78*bb8a0c61SJames Wright 79*bb8a0c61SJames Wright // Quadrature Point Loop 80*bb8a0c61SJames Wright CeedPragmaSIMD 81*bb8a0c61SJames Wright for (CeedInt i=0; i<Q; i++) { 82*bb8a0c61SJames Wright const CeedScalar x[] = {X[0][i], X[1][i], X[2][i]}; 83*bb8a0c61SJames Wright CeedScalar q[5] = {0.}; 84*bb8a0c61SJames Wright Exact_Channel(3, 0., x, 5, q, ctx); 85*bb8a0c61SJames Wright 86*bb8a0c61SJames Wright for (CeedInt j=0; j<5; j++) 87*bb8a0c61SJames Wright q0[j][i] = q[j]; 88*bb8a0c61SJames Wright } // End of Quadrature Point Loop 89*bb8a0c61SJames Wright return 0; 90*bb8a0c61SJames Wright } 91*bb8a0c61SJames Wright 92*bb8a0c61SJames Wright // ***************************************************************************** 93*bb8a0c61SJames Wright CEED_QFUNCTION(Channel_Inflow)(void *ctx, CeedInt Q, 94*bb8a0c61SJames Wright const CeedScalar *const *in, 95*bb8a0c61SJames Wright CeedScalar *const *out) { 96*bb8a0c61SJames Wright // *INDENT-OFF* 97*bb8a0c61SJames Wright // Inputs 98*bb8a0c61SJames Wright const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], 99*bb8a0c61SJames Wright (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1], 100*bb8a0c61SJames Wright (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 101*bb8a0c61SJames Wright 102*bb8a0c61SJames Wright // Outputs 103*bb8a0c61SJames Wright CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 104*bb8a0c61SJames Wright // *INDENT-ON* 105*bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 106*bb8a0c61SJames Wright const bool implicit = context->implicit; 107*bb8a0c61SJames Wright const CeedScalar cv = context->newtonian_ctx.cv; 108*bb8a0c61SJames Wright const CeedScalar cp = context->newtonian_ctx.cp; 109*bb8a0c61SJames Wright const CeedScalar gamma = cp/cv; 110*bb8a0c61SJames Wright 111*bb8a0c61SJames Wright CeedPragmaSIMD 112*bb8a0c61SJames Wright // Quadrature Point Loop 113*bb8a0c61SJames Wright for (CeedInt i=0; i<Q; i++) { 114*bb8a0c61SJames Wright // Setup 115*bb8a0c61SJames Wright // -- Interp-to-Interp q_data 116*bb8a0c61SJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 117*bb8a0c61SJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 118*bb8a0c61SJames Wright // We can effect this by swapping the sign on this weight 119*bb8a0c61SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 120*bb8a0c61SJames Wright 121*bb8a0c61SJames Wright // Calcualte prescribed inflow values 122*bb8a0c61SJames Wright const CeedScalar x[3] = {X[0][i], X[1][i], X[2][i]}; 123*bb8a0c61SJames Wright CeedScalar q_exact[5] = {0.}; 124*bb8a0c61SJames Wright Exact_Channel(3, 0., x, 5, q_exact, ctx); 125*bb8a0c61SJames Wright const CeedScalar E_kinetic_exact = 0.5*(q_exact[1]*q_exact[1] + 126*bb8a0c61SJames Wright q_exact[2]*q_exact[2] + 127*bb8a0c61SJames Wright q_exact[3]*q_exact[3]) / q_exact[0]; 128*bb8a0c61SJames Wright const CeedScalar velocity[3] = {q_exact[1]/q_exact[0], 129*bb8a0c61SJames Wright q_exact[2]/q_exact[0], 130*bb8a0c61SJames Wright q_exact[3]/q_exact[0] 131*bb8a0c61SJames Wright }; 132*bb8a0c61SJames Wright const CeedScalar theta = (q_exact[4] - E_kinetic_exact) / (q_exact[0]*cv); 133*bb8a0c61SJames Wright 134*bb8a0c61SJames Wright // Find pressure using state inside the domain 135*bb8a0c61SJames Wright const CeedScalar rho = q[0][i]; 136*bb8a0c61SJames Wright const CeedScalar u[3] = {q[1][i]/rho, q[2][i]/rho, q[3][i]/rho}; 137*bb8a0c61SJames Wright const CeedScalar E_internal = q[4][i] - .5 * rho * (u[0]*u[0] + u[1]*u[1] + 138*bb8a0c61SJames Wright u[2]*u[2]); 139*bb8a0c61SJames Wright const CeedScalar P = E_internal * (gamma - 1.); 140*bb8a0c61SJames Wright 141*bb8a0c61SJames Wright // Find inflow state using calculated P and prescribed velocity, theta0 142*bb8a0c61SJames Wright const CeedScalar e_internal = cv * theta; 143*bb8a0c61SJames Wright const CeedScalar rho_in = P / ((gamma - 1) * e_internal); 144*bb8a0c61SJames Wright const CeedScalar E_kinetic = .5 * rho_in * (velocity[0]*velocity[0] + 145*bb8a0c61SJames Wright velocity[1]*velocity[1] + 146*bb8a0c61SJames Wright velocity[2]*velocity[2]); 147*bb8a0c61SJames Wright const CeedScalar E = rho_in * e_internal + E_kinetic; 148*bb8a0c61SJames Wright // ---- Normal vect 149*bb8a0c61SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], 150*bb8a0c61SJames Wright q_data_sur[2][i], 151*bb8a0c61SJames Wright q_data_sur[3][i] 152*bb8a0c61SJames Wright }; 153*bb8a0c61SJames Wright 154*bb8a0c61SJames Wright // The Physics 155*bb8a0c61SJames Wright // Zero v so all future terms can safely sum into it 156*bb8a0c61SJames Wright for (int j=0; j<5; j++) v[j][i] = 0.; 157*bb8a0c61SJames Wright 158*bb8a0c61SJames Wright const CeedScalar u_normal = norm[0]*velocity[0] + 159*bb8a0c61SJames Wright norm[1]*velocity[1] + 160*bb8a0c61SJames Wright norm[2]*velocity[2]; 161*bb8a0c61SJames Wright 162*bb8a0c61SJames Wright // The Physics 163*bb8a0c61SJames Wright // -- Density 164*bb8a0c61SJames Wright v[0][i] -= wdetJb * rho_in * u_normal; 165*bb8a0c61SJames Wright 166*bb8a0c61SJames Wright // -- Momentum 167*bb8a0c61SJames Wright for (int j=0; j<3; j++) 168*bb8a0c61SJames Wright v[j+1][i] -= wdetJb * (rho_in * u_normal * velocity[j] + 169*bb8a0c61SJames Wright norm[j] * P); 170*bb8a0c61SJames Wright 171*bb8a0c61SJames Wright // -- Total Energy Density 172*bb8a0c61SJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 173*bb8a0c61SJames Wright 174*bb8a0c61SJames Wright } // End Quadrature Point Loop 175*bb8a0c61SJames Wright return 0; 176*bb8a0c61SJames Wright } 177*bb8a0c61SJames Wright 178*bb8a0c61SJames Wright // ***************************************************************************** 179*bb8a0c61SJames Wright CEED_QFUNCTION(Channel_Outflow)(void *ctx, CeedInt Q, 180*bb8a0c61SJames Wright const CeedScalar *const *in, 181*bb8a0c61SJames Wright CeedScalar *const *out) { 182*bb8a0c61SJames Wright // *INDENT-OFF* 183*bb8a0c61SJames Wright // Inputs 184*bb8a0c61SJames Wright const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], 185*bb8a0c61SJames Wright (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1]; 186*bb8a0c61SJames Wright // Outputs 187*bb8a0c61SJames Wright CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 188*bb8a0c61SJames Wright // *INDENT-ON* 189*bb8a0c61SJames Wright 190*bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 191*bb8a0c61SJames Wright const bool implicit = context->implicit; 192*bb8a0c61SJames Wright const CeedScalar P0 = context->P0; 193*bb8a0c61SJames Wright 194*bb8a0c61SJames Wright CeedPragmaSIMD 195*bb8a0c61SJames Wright // Quadrature Point Loop 196*bb8a0c61SJames Wright for (CeedInt i=0; i<Q; i++) { 197*bb8a0c61SJames Wright // Setup 198*bb8a0c61SJames Wright // -- Interp in 199*bb8a0c61SJames Wright const CeedScalar rho = q[0][i]; 200*bb8a0c61SJames Wright const CeedScalar u[3] = {q[1][i] / rho, 201*bb8a0c61SJames Wright q[2][i] / rho, 202*bb8a0c61SJames Wright q[3][i] / rho 203*bb8a0c61SJames Wright }; 204*bb8a0c61SJames Wright const CeedScalar E = q[4][i]; 205*bb8a0c61SJames Wright 206*bb8a0c61SJames Wright // -- Interp-to-Interp q_data 207*bb8a0c61SJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 208*bb8a0c61SJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 209*bb8a0c61SJames Wright // We can effect this by swapping the sign on this weight 210*bb8a0c61SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 211*bb8a0c61SJames Wright 212*bb8a0c61SJames Wright // ---- Normal vect 213*bb8a0c61SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], 214*bb8a0c61SJames Wright q_data_sur[2][i], 215*bb8a0c61SJames Wright q_data_sur[3][i] 216*bb8a0c61SJames Wright }; 217*bb8a0c61SJames Wright 218*bb8a0c61SJames Wright // The Physics 219*bb8a0c61SJames Wright // Zero v so all future terms can safely sum into it 220*bb8a0c61SJames Wright for (int j=0; j<5; j++) v[j][i] = 0.; 221*bb8a0c61SJames Wright 222*bb8a0c61SJames Wright // Implementing outflow condition 223*bb8a0c61SJames Wright const CeedScalar P = P0; // pressure 224*bb8a0c61SJames Wright const CeedScalar u_normal = norm[0]*u[0] + norm[1]*u[1] + 225*bb8a0c61SJames Wright norm[2]*u[2]; // Normal velocity 226*bb8a0c61SJames Wright // The Physics 227*bb8a0c61SJames Wright // -- Density 228*bb8a0c61SJames Wright v[0][i] -= wdetJb * rho * u_normal; 229*bb8a0c61SJames Wright 230*bb8a0c61SJames Wright // -- Momentum 231*bb8a0c61SJames Wright for (int j=0; j<3; j++) 232*bb8a0c61SJames Wright v[j+1][i] -= wdetJb *(rho * u_normal * u[j] + norm[j] * P); 233*bb8a0c61SJames Wright 234*bb8a0c61SJames Wright // -- Total Energy Density 235*bb8a0c61SJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 236*bb8a0c61SJames Wright 237*bb8a0c61SJames Wright } // End Quadrature Point Loop 238*bb8a0c61SJames Wright return 0; 239*bb8a0c61SJames Wright } 240*bb8a0c61SJames Wright #endif // channel_h 241