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