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 15d0cce58aSJeremy L Thompson #include <ceed.h> 16bb8a0c61SJames Wright #include <math.h> 17cbe60e31SLeila Ghaffari #include "newtonian_state.h" 18d0cce58aSJeremy L Thompson #include "newtonian_types.h" 19704b8bbeSJames Wright #include "utils.h" 20bb8a0c61SJames Wright 21bb8a0c61SJames Wright typedef struct ChannelContext_ *ChannelContext; 22bb8a0c61SJames Wright struct ChannelContext_ { 23bb8a0c61SJames Wright bool implicit; // !< Using implicit timesteping or not 24bb8a0c61SJames Wright CeedScalar theta0; // !< Reference temperature 25bb8a0c61SJames Wright CeedScalar P0; // !< Reference Pressure 26bb8a0c61SJames Wright CeedScalar umax; // !< Centerline velocity 27bb8a0c61SJames Wright CeedScalar center; // !< Y Coordinate for center of channel 28bb8a0c61SJames Wright CeedScalar H; // !< Channel half-height 29bb8a0c61SJames Wright CeedScalar B; // !< Body-force driving the flow 30bb8a0c61SJames Wright struct NewtonianIdealGasContext_ newtonian_ctx; 31bb8a0c61SJames Wright }; 32bb8a0c61SJames Wright 33cbe60e31SLeila Ghaffari CEED_QFUNCTION_HELPER State Exact_Channel(CeedInt dim, CeedScalar time, 34cbe60e31SLeila Ghaffari const CeedScalar X[], CeedInt Nf, void *ctx) { 35bb8a0c61SJames Wright 36bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 37bb8a0c61SJames Wright const CeedScalar theta0 = context->theta0; 38bb8a0c61SJames Wright const CeedScalar P0 = context->P0; 39bb8a0c61SJames Wright const CeedScalar umax = context->umax; 40bb8a0c61SJames Wright const CeedScalar center = context->center; 41bb8a0c61SJames Wright const CeedScalar H = context->H; 42cbe60e31SLeila Ghaffari NewtonianIdealGasContext gas = &context->newtonian_ctx; 43cbe60e31SLeila Ghaffari const CeedScalar cp = gas->cp; 44cbe60e31SLeila Ghaffari const CeedScalar mu = gas->mu; 45cbe60e31SLeila Ghaffari const CeedScalar k = gas->k; 46cbe60e31SLeila Ghaffari // There is a gravity body force but it is excluded from 47cbe60e31SLeila Ghaffari // the potential energy due to periodicity. 48d1b9ef12SLeila Ghaffari // g = (g, 0, 0) 49d1b9ef12SLeila Ghaffari // x = (0, x_2, x_3) 50d1b9ef12SLeila Ghaffari // e_potential = dot(g, x) = 0 51d1b9ef12SLeila Ghaffari const CeedScalar x[3] = {0, X[1], X[2]}; 52bb8a0c61SJames Wright 53bb8a0c61SJames Wright const CeedScalar Pr = mu / (cp*k); 54bb8a0c61SJames Wright const CeedScalar Ec = (umax*umax) / (cp*theta0); 55c58dce4fSJed Brown const CeedScalar theta = theta0*(1 + (Pr*Ec/3) 56d1b9ef12SLeila Ghaffari * (1 - Square(Square((x[1]-center)/H)))); 57cbe60e31SLeila Ghaffari CeedScalar Y[5] = {0.}; 58cbe60e31SLeila Ghaffari Y[0] = P0; 59d1b9ef12SLeila Ghaffari Y[1] = umax*(1 - Square((x[1]-center)/H)); 60cbe60e31SLeila Ghaffari Y[2] = 0.; 61cbe60e31SLeila Ghaffari Y[3] = 0.; 62cbe60e31SLeila Ghaffari Y[4] = theta; 63bb8a0c61SJames Wright 64d1b9ef12SLeila Ghaffari return StateFromY(gas, Y, x); 65bb8a0c61SJames Wright } 66bb8a0c61SJames Wright 67bb8a0c61SJames Wright // ***************************************************************************** 68cbe60e31SLeila Ghaffari // This QFunction set the initial condition 69bb8a0c61SJames Wright // ***************************************************************************** 70bb8a0c61SJames Wright CEED_QFUNCTION(ICsChannel)(void *ctx, CeedInt Q, 71bb8a0c61SJames Wright const CeedScalar *const *in, CeedScalar *const *out) { 72bb8a0c61SJames Wright // Inputs 73bb8a0c61SJames Wright const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 74bb8a0c61SJames Wright 75bb8a0c61SJames Wright // Outputs 76bb8a0c61SJames Wright CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 77bb8a0c61SJames Wright 78cbe60e31SLeila Ghaffari // Context 79cbe60e31SLeila Ghaffari const ChannelContext context = (ChannelContext)ctx; 80cbe60e31SLeila Ghaffari 81bb8a0c61SJames Wright // Quadrature Point Loop 82bb8a0c61SJames Wright CeedPragmaSIMD 83bb8a0c61SJames Wright for (CeedInt i=0; i<Q; i++) { 84bb8a0c61SJames Wright const CeedScalar x[] = {X[0][i], X[1][i], X[2][i]}; 85cbe60e31SLeila Ghaffari State s = Exact_Channel(3, 0., x, 5, ctx); 86d1b9ef12SLeila Ghaffari CeedScalar q[5] = {0}; 87*3636f6a4SJames Wright switch (context->newtonian_ctx.state_var) { 88*3636f6a4SJames Wright case STATEVAR_CONSERVATIVE: 89d1b9ef12SLeila Ghaffari UnpackState_U(s.U, q); 90*3636f6a4SJames Wright break; 91*3636f6a4SJames Wright case STATEVAR_PRIMITIVE: 92*3636f6a4SJames Wright UnpackState_Y(s.Y, q); 93*3636f6a4SJames Wright break; 94*3636f6a4SJames Wright } 95d1b9ef12SLeila Ghaffari 96d1b9ef12SLeila Ghaffari for (CeedInt j=0; j<5; j++) 97d1b9ef12SLeila Ghaffari q0[j][i] = q[j]; 98bb8a0c61SJames Wright 99bb8a0c61SJames Wright } // End of Quadrature Point Loop 100bb8a0c61SJames Wright return 0; 101bb8a0c61SJames Wright } 102bb8a0c61SJames Wright 103bb8a0c61SJames Wright // ***************************************************************************** 104d1b9ef12SLeila Ghaffari // This QFunction set the inflow boundary condition for conservative variables 105d1b9ef12SLeila Ghaffari // ***************************************************************************** 106bb8a0c61SJames Wright CEED_QFUNCTION(Channel_Inflow)(void *ctx, CeedInt Q, 107bb8a0c61SJames Wright const CeedScalar *const *in, 108bb8a0c61SJames Wright CeedScalar *const *out) { 109bb8a0c61SJames Wright // *INDENT-OFF* 110bb8a0c61SJames Wright // Inputs 111bb8a0c61SJames Wright const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], 112dd64951cSJames Wright (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], 113dd64951cSJames Wright (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 114bb8a0c61SJames Wright 115bb8a0c61SJames Wright // Outputs 116bb8a0c61SJames Wright CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 117bb8a0c61SJames Wright // *INDENT-ON* 118bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 119bb8a0c61SJames Wright const bool implicit = context->implicit; 120d1b9ef12SLeila Ghaffari NewtonianIdealGasContext gas = &context->newtonian_ctx; 121d1b9ef12SLeila Ghaffari const CeedScalar cv = gas->cv; 122d1b9ef12SLeila Ghaffari const CeedScalar cp = gas->cp; 123bb8a0c61SJames Wright const CeedScalar gamma = cp / cv; 124bb8a0c61SJames Wright 125bb8a0c61SJames Wright CeedPragmaSIMD 126bb8a0c61SJames Wright // Quadrature Point Loop 127bb8a0c61SJames Wright for (CeedInt i=0; i<Q; i++) { 128bb8a0c61SJames Wright // Setup 129bb8a0c61SJames Wright // -- Interp-to-Interp q_data 130bb8a0c61SJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 131bb8a0c61SJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 132bb8a0c61SJames Wright // We can effect this by swapping the sign on this weight 133bb8a0c61SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 134bb8a0c61SJames Wright 135d1b9ef12SLeila Ghaffari // There is a gravity body force but it is excluded from 136d1b9ef12SLeila Ghaffari // the potential energy due to periodicity. 137d1b9ef12SLeila Ghaffari // g = (g, 0, 0) 138d1b9ef12SLeila Ghaffari // x = (0, x_2, x_3) 139d1b9ef12SLeila Ghaffari // e_potential = dot(g, x) = 0 140d1b9ef12SLeila Ghaffari const CeedScalar x[3] = {0, X[1][i], X[2][i]}; 141d1b9ef12SLeila Ghaffari 142bb8a0c61SJames Wright // Calcualte prescribed inflow values 143d1b9ef12SLeila Ghaffari State s_exact = Exact_Channel(3, 0., x, 5, ctx); 144bb8a0c61SJames Wright CeedScalar q_exact[5] = {0.}; 145d1b9ef12SLeila Ghaffari UnpackState_U(s_exact.U, q_exact); 146bb8a0c61SJames Wright 147bb8a0c61SJames Wright // Find pressure using state inside the domain 148d1b9ef12SLeila Ghaffari CeedScalar q_inside[5] = {0}; 1498ed70ad9SJames Wright for (CeedInt j=0; j<5; j++) 150d1b9ef12SLeila Ghaffari q_inside[j] = q[j][i]; 151d1b9ef12SLeila Ghaffari State s_inside = StateFromU(gas, q_inside, x); 152d1b9ef12SLeila Ghaffari const CeedScalar P = s_inside.Y.pressure; 153bb8a0c61SJames Wright 154bb8a0c61SJames Wright // Find inflow state using calculated P and prescribed velocity, theta0 155d1b9ef12SLeila Ghaffari const CeedScalar e_internal = cv * s_exact.Y.temperature; 156bb8a0c61SJames Wright const CeedScalar rho_in = P / ((gamma - 1) * e_internal); 157d1b9ef12SLeila Ghaffari const CeedScalar E_kinetic = .5 * rho_in * Dot3(s_exact.Y.velocity, 158d1b9ef12SLeila Ghaffari s_exact.Y.velocity); 159bb8a0c61SJames Wright const CeedScalar E = rho_in * e_internal + E_kinetic; 160d1b9ef12SLeila Ghaffari 161bb8a0c61SJames Wright // ---- Normal vect 162bb8a0c61SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], 163bb8a0c61SJames Wright q_data_sur[2][i], 164bb8a0c61SJames Wright q_data_sur[3][i] 165bb8a0c61SJames Wright }; 166bb8a0c61SJames Wright // The Physics 167bb8a0c61SJames Wright // Zero v so all future terms can safely sum into it 168493642f1SJames Wright for (CeedInt j=0; j<5; j++) v[j][i] = 0.; 169bb8a0c61SJames Wright 170d1b9ef12SLeila Ghaffari const CeedScalar u_normal = Dot3(norm, s_exact.Y.velocity); 171bb8a0c61SJames Wright 172bb8a0c61SJames Wright // The Physics 173bb8a0c61SJames Wright // -- Density 174bb8a0c61SJames Wright v[0][i] -= wdetJb * rho_in * u_normal; 175bb8a0c61SJames Wright 176bb8a0c61SJames Wright // -- Momentum 177493642f1SJames Wright for (CeedInt j=0; j<3; j++) 178d1b9ef12SLeila Ghaffari v[j+1][i] -= wdetJb * (rho_in * u_normal * s_exact.Y.velocity[j] + 179bb8a0c61SJames Wright norm[j] * P); 180bb8a0c61SJames Wright 181bb8a0c61SJames Wright // -- Total Energy Density 182bb8a0c61SJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 183bb8a0c61SJames Wright 184bb8a0c61SJames Wright } // End Quadrature Point Loop 185bb8a0c61SJames Wright return 0; 186bb8a0c61SJames Wright } 187bb8a0c61SJames Wright 188bb8a0c61SJames Wright // ***************************************************************************** 189d1b9ef12SLeila Ghaffari // This QFunction set the outflow boundary condition for conservative variables 190d1b9ef12SLeila Ghaffari // ***************************************************************************** 191bb8a0c61SJames Wright CEED_QFUNCTION(Channel_Outflow)(void *ctx, CeedInt Q, 192bb8a0c61SJames Wright const CeedScalar *const *in, 193bb8a0c61SJames Wright CeedScalar *const *out) { 194bb8a0c61SJames Wright // *INDENT-OFF* 195bb8a0c61SJames Wright // Inputs 196bb8a0c61SJames Wright const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], 197dd64951cSJames Wright (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 198dd64951cSJames Wright 199bb8a0c61SJames Wright // Outputs 200bb8a0c61SJames Wright CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 201bb8a0c61SJames Wright // *INDENT-ON* 202bb8a0c61SJames Wright 203bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 204bb8a0c61SJames Wright const bool implicit = context->implicit; 205bb8a0c61SJames Wright const CeedScalar P0 = context->P0; 206bb8a0c61SJames Wright 207bb8a0c61SJames Wright CeedPragmaSIMD 208bb8a0c61SJames Wright // Quadrature Point Loop 209bb8a0c61SJames Wright for (CeedInt i=0; i<Q; i++) { 210bb8a0c61SJames Wright // Setup 211bb8a0c61SJames Wright // -- Interp in 212bb8a0c61SJames Wright const CeedScalar rho = q[0][i]; 213bb8a0c61SJames Wright const CeedScalar u[3] = {q[1][i] / rho, 214bb8a0c61SJames Wright q[2][i] / rho, 215bb8a0c61SJames Wright q[3][i] / rho 216bb8a0c61SJames Wright }; 217bb8a0c61SJames Wright const CeedScalar E = q[4][i]; 218bb8a0c61SJames Wright 219bb8a0c61SJames Wright // -- Interp-to-Interp q_data 220bb8a0c61SJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 221bb8a0c61SJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 222bb8a0c61SJames Wright // We can effect this by swapping the sign on this weight 223bb8a0c61SJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 224bb8a0c61SJames Wright 225bb8a0c61SJames Wright // ---- Normal vect 226bb8a0c61SJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], 227bb8a0c61SJames Wright q_data_sur[2][i], 228bb8a0c61SJames Wright q_data_sur[3][i] 229bb8a0c61SJames Wright }; 230bb8a0c61SJames Wright // The Physics 231bb8a0c61SJames Wright // Zero v so all future terms can safely sum into it 232493642f1SJames Wright for (CeedInt j=0; j<5; j++) v[j][i] = 0.; 233bb8a0c61SJames Wright 234bb8a0c61SJames Wright // Implementing outflow condition 235bb8a0c61SJames Wright const CeedScalar P = P0; // pressure 236704b8bbeSJames Wright const CeedScalar u_normal = Dot3(norm, u); // Normal velocity 237bb8a0c61SJames Wright // The Physics 238bb8a0c61SJames Wright // -- Density 239bb8a0c61SJames Wright v[0][i] -= wdetJb * rho * u_normal; 240bb8a0c61SJames Wright 241bb8a0c61SJames Wright // -- Momentum 242493642f1SJames Wright for (CeedInt j=0; j<3; j++) 243bb8a0c61SJames Wright v[j+1][i] -= wdetJb *(rho * u_normal * u[j] + norm[j] * P); 244bb8a0c61SJames Wright 245bb8a0c61SJames Wright // -- Total Energy Density 246bb8a0c61SJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 247bb8a0c61SJames Wright 248bb8a0c61SJames Wright } // End Quadrature Point Loop 249bb8a0c61SJames Wright return 0; 250bb8a0c61SJames Wright } 251cbe60e31SLeila Ghaffari 252cbe60e31SLeila Ghaffari // ***************************************************************************** 253bb8a0c61SJames Wright #endif // channel_h 254