188626eedSJames Wright // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 288626eedSJames Wright // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 388626eedSJames Wright // 488626eedSJames Wright // SPDX-License-Identifier: BSD-2-Clause 588626eedSJames Wright // 688626eedSJames Wright // This file is part of CEED: http://github.com/ceed 788626eedSJames Wright 888626eedSJames Wright /// @file 988626eedSJames Wright /// Operator for Navier-Stokes example using PETSc 1088626eedSJames Wright 1188626eedSJames Wright 1288626eedSJames Wright #ifndef channel_h 1388626eedSJames Wright #define channel_h 1488626eedSJames Wright 15c9c2c079SJeremy L Thompson #include <ceed.h> 1688626eedSJames Wright #include <math.h> 17dc805cc4SLeila Ghaffari #include "newtonian_state.h" 18c9c2c079SJeremy L Thompson #include "newtonian_types.h" 1913fa47b2SJames Wright #include "utils.h" 2088626eedSJames Wright 2188626eedSJames Wright typedef struct ChannelContext_ *ChannelContext; 2288626eedSJames Wright struct ChannelContext_ { 2388626eedSJames Wright bool implicit; // !< Using implicit timesteping or not 2488626eedSJames Wright CeedScalar theta0; // !< Reference temperature 2588626eedSJames Wright CeedScalar P0; // !< Reference Pressure 2688626eedSJames Wright CeedScalar umax; // !< Centerline velocity 2788626eedSJames Wright CeedScalar center; // !< Y Coordinate for center of channel 2888626eedSJames Wright CeedScalar H; // !< Channel half-height 2988626eedSJames Wright CeedScalar B; // !< Body-force driving the flow 3088626eedSJames Wright struct NewtonianIdealGasContext_ newtonian_ctx; 3188626eedSJames Wright }; 3288626eedSJames Wright 33dc805cc4SLeila Ghaffari CEED_QFUNCTION_HELPER State Exact_Channel(CeedInt dim, CeedScalar time, 34dc805cc4SLeila Ghaffari const CeedScalar X[], CeedInt Nf, void *ctx) { 3588626eedSJames Wright 3688626eedSJames Wright const ChannelContext context = (ChannelContext)ctx; 3788626eedSJames Wright const CeedScalar theta0 = context->theta0; 3888626eedSJames Wright const CeedScalar P0 = context->P0; 3988626eedSJames Wright const CeedScalar umax = context->umax; 4088626eedSJames Wright const CeedScalar center = context->center; 4188626eedSJames Wright const CeedScalar H = context->H; 42dc805cc4SLeila Ghaffari NewtonianIdealGasContext gas = &context->newtonian_ctx; 43dc805cc4SLeila Ghaffari const CeedScalar cp = gas->cp; 44dc805cc4SLeila Ghaffari const CeedScalar mu = gas->mu; 45dc805cc4SLeila Ghaffari const CeedScalar k = gas->k; 46dc805cc4SLeila Ghaffari // There is a gravity body force but it is excluded from 47dc805cc4SLeila Ghaffari // the potential energy due to periodicity. 482b89d87eSLeila Ghaffari // g = (g, 0, 0) 492b89d87eSLeila Ghaffari // x = (0, x_2, x_3) 502b89d87eSLeila Ghaffari // e_potential = dot(g, x) = 0 512b89d87eSLeila Ghaffari const CeedScalar x[3] = {0, X[1], X[2]}; 5288626eedSJames Wright 5388626eedSJames Wright const CeedScalar Pr = mu / (cp*k); 5488626eedSJames Wright const CeedScalar Ec = (umax*umax) / (cp*theta0); 55c32eb7cbSJed Brown const CeedScalar theta = theta0*(1 + (Pr*Ec/3) 562b89d87eSLeila Ghaffari * (1 - Square(Square((x[1]-center)/H)))); 57dc805cc4SLeila Ghaffari CeedScalar Y[5] = {0.}; 58dc805cc4SLeila Ghaffari Y[0] = P0; 592b89d87eSLeila Ghaffari Y[1] = umax*(1 - Square((x[1]-center)/H)); 60dc805cc4SLeila Ghaffari Y[2] = 0.; 61dc805cc4SLeila Ghaffari Y[3] = 0.; 62dc805cc4SLeila Ghaffari Y[4] = theta; 6388626eedSJames Wright 642b89d87eSLeila Ghaffari return StateFromY(gas, Y, x); 6588626eedSJames Wright } 6688626eedSJames Wright 6788626eedSJames Wright // ***************************************************************************** 68dc805cc4SLeila Ghaffari // This QFunction set the initial condition 6988626eedSJames Wright // ***************************************************************************** 7088626eedSJames Wright CEED_QFUNCTION(ICsChannel)(void *ctx, CeedInt Q, 7188626eedSJames Wright const CeedScalar *const *in, CeedScalar *const *out) { 7288626eedSJames Wright // Inputs 7388626eedSJames Wright const CeedScalar (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 7488626eedSJames Wright 7588626eedSJames Wright // Outputs 7688626eedSJames Wright CeedScalar (*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 7788626eedSJames Wright 78dc805cc4SLeila Ghaffari // Context 79dc805cc4SLeila Ghaffari const ChannelContext context = (ChannelContext)ctx; 80dc805cc4SLeila Ghaffari 8188626eedSJames Wright // Quadrature Point Loop 8288626eedSJames Wright CeedPragmaSIMD 8388626eedSJames Wright for (CeedInt i=0; i<Q; i++) { 8488626eedSJames Wright const CeedScalar x[] = {X[0][i], X[1][i], X[2][i]}; 85dc805cc4SLeila Ghaffari State s = Exact_Channel(3, 0., x, 5, ctx); 862b89d87eSLeila Ghaffari CeedScalar q[5] = {0}; 87*97baf651SJames Wright switch (context->newtonian_ctx.state_var) { 88*97baf651SJames Wright case STATEVAR_CONSERVATIVE: 892b89d87eSLeila Ghaffari UnpackState_U(s.U, q); 90*97baf651SJames Wright break; 91*97baf651SJames Wright case STATEVAR_PRIMITIVE: 92*97baf651SJames Wright UnpackState_Y(s.Y, q); 93*97baf651SJames Wright break; 94*97baf651SJames Wright } 952b89d87eSLeila Ghaffari 962b89d87eSLeila Ghaffari for (CeedInt j=0; j<5; j++) 972b89d87eSLeila Ghaffari q0[j][i] = q[j]; 9888626eedSJames Wright 9988626eedSJames Wright } // End of Quadrature Point Loop 10088626eedSJames Wright return 0; 10188626eedSJames Wright } 10288626eedSJames Wright 10388626eedSJames Wright // ***************************************************************************** 1042b89d87eSLeila Ghaffari // This QFunction set the inflow boundary condition for conservative variables 1052b89d87eSLeila Ghaffari // ***************************************************************************** 10688626eedSJames Wright CEED_QFUNCTION(Channel_Inflow)(void *ctx, CeedInt Q, 10788626eedSJames Wright const CeedScalar *const *in, 10888626eedSJames Wright CeedScalar *const *out) { 10988626eedSJames Wright // *INDENT-OFF* 11088626eedSJames Wright // Inputs 11188626eedSJames Wright const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], 112e8b03feeSJames Wright (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2], 113e8b03feeSJames Wright (*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 11488626eedSJames Wright 11588626eedSJames Wright // Outputs 11688626eedSJames Wright CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 11788626eedSJames Wright // *INDENT-ON* 11888626eedSJames Wright const ChannelContext context = (ChannelContext)ctx; 11988626eedSJames Wright const bool implicit = context->implicit; 1202b89d87eSLeila Ghaffari NewtonianIdealGasContext gas = &context->newtonian_ctx; 1212b89d87eSLeila Ghaffari const CeedScalar cv = gas->cv; 1222b89d87eSLeila Ghaffari const CeedScalar cp = gas->cp; 12388626eedSJames Wright const CeedScalar gamma = cp / cv; 12488626eedSJames Wright 12588626eedSJames Wright CeedPragmaSIMD 12688626eedSJames Wright // Quadrature Point Loop 12788626eedSJames Wright for (CeedInt i=0; i<Q; i++) { 12888626eedSJames Wright // Setup 12988626eedSJames Wright // -- Interp-to-Interp q_data 13088626eedSJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 13188626eedSJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 13288626eedSJames Wright // We can effect this by swapping the sign on this weight 13388626eedSJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 13488626eedSJames Wright 1352b89d87eSLeila Ghaffari // There is a gravity body force but it is excluded from 1362b89d87eSLeila Ghaffari // the potential energy due to periodicity. 1372b89d87eSLeila Ghaffari // g = (g, 0, 0) 1382b89d87eSLeila Ghaffari // x = (0, x_2, x_3) 1392b89d87eSLeila Ghaffari // e_potential = dot(g, x) = 0 1402b89d87eSLeila Ghaffari const CeedScalar x[3] = {0, X[1][i], X[2][i]}; 1412b89d87eSLeila Ghaffari 14288626eedSJames Wright // Calcualte prescribed inflow values 1432b89d87eSLeila Ghaffari State s_exact = Exact_Channel(3, 0., x, 5, ctx); 14488626eedSJames Wright CeedScalar q_exact[5] = {0.}; 1452b89d87eSLeila Ghaffari UnpackState_U(s_exact.U, q_exact); 14688626eedSJames Wright 14788626eedSJames Wright // Find pressure using state inside the domain 1482b89d87eSLeila Ghaffari CeedScalar q_inside[5] = {0}; 1499b7dec89SJames Wright for (CeedInt j=0; j<5; j++) 1502b89d87eSLeila Ghaffari q_inside[j] = q[j][i]; 1512b89d87eSLeila Ghaffari State s_inside = StateFromU(gas, q_inside, x); 1522b89d87eSLeila Ghaffari const CeedScalar P = s_inside.Y.pressure; 15388626eedSJames Wright 15488626eedSJames Wright // Find inflow state using calculated P and prescribed velocity, theta0 1552b89d87eSLeila Ghaffari const CeedScalar e_internal = cv * s_exact.Y.temperature; 15688626eedSJames Wright const CeedScalar rho_in = P / ((gamma - 1) * e_internal); 1572b89d87eSLeila Ghaffari const CeedScalar E_kinetic = .5 * rho_in * Dot3(s_exact.Y.velocity, 1582b89d87eSLeila Ghaffari s_exact.Y.velocity); 15988626eedSJames Wright const CeedScalar E = rho_in * e_internal + E_kinetic; 1602b89d87eSLeila Ghaffari 16188626eedSJames Wright // ---- Normal vect 16288626eedSJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], 16388626eedSJames Wright q_data_sur[2][i], 16488626eedSJames Wright q_data_sur[3][i] 16588626eedSJames Wright }; 16688626eedSJames Wright // The Physics 16788626eedSJames Wright // Zero v so all future terms can safely sum into it 168ba6664aeSJames Wright for (CeedInt j=0; j<5; j++) v[j][i] = 0.; 16988626eedSJames Wright 1702b89d87eSLeila Ghaffari const CeedScalar u_normal = Dot3(norm, s_exact.Y.velocity); 17188626eedSJames Wright 17288626eedSJames Wright // The Physics 17388626eedSJames Wright // -- Density 17488626eedSJames Wright v[0][i] -= wdetJb * rho_in * u_normal; 17588626eedSJames Wright 17688626eedSJames Wright // -- Momentum 177ba6664aeSJames Wright for (CeedInt j=0; j<3; j++) 1782b89d87eSLeila Ghaffari v[j+1][i] -= wdetJb * (rho_in * u_normal * s_exact.Y.velocity[j] + 17988626eedSJames Wright norm[j] * P); 18088626eedSJames Wright 18188626eedSJames Wright // -- Total Energy Density 18288626eedSJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 18388626eedSJames Wright 18488626eedSJames Wright } // End Quadrature Point Loop 18588626eedSJames Wright return 0; 18688626eedSJames Wright } 18788626eedSJames Wright 18888626eedSJames Wright // ***************************************************************************** 1892b89d87eSLeila Ghaffari // This QFunction set the outflow boundary condition for conservative variables 1902b89d87eSLeila Ghaffari // ***************************************************************************** 19188626eedSJames Wright CEED_QFUNCTION(Channel_Outflow)(void *ctx, CeedInt Q, 19288626eedSJames Wright const CeedScalar *const *in, 19388626eedSJames Wright CeedScalar *const *out) { 19488626eedSJames Wright // *INDENT-OFF* 19588626eedSJames Wright // Inputs 19688626eedSJames Wright const CeedScalar (*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0], 197e8b03feeSJames Wright (*q_data_sur)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 198e8b03feeSJames Wright 19988626eedSJames Wright // Outputs 20088626eedSJames Wright CeedScalar (*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 20188626eedSJames Wright // *INDENT-ON* 20288626eedSJames Wright 20388626eedSJames Wright const ChannelContext context = (ChannelContext)ctx; 20488626eedSJames Wright const bool implicit = context->implicit; 20588626eedSJames Wright const CeedScalar P0 = context->P0; 20688626eedSJames Wright 20788626eedSJames Wright CeedPragmaSIMD 20888626eedSJames Wright // Quadrature Point Loop 20988626eedSJames Wright for (CeedInt i=0; i<Q; i++) { 21088626eedSJames Wright // Setup 21188626eedSJames Wright // -- Interp in 21288626eedSJames Wright const CeedScalar rho = q[0][i]; 21388626eedSJames Wright const CeedScalar u[3] = {q[1][i] / rho, 21488626eedSJames Wright q[2][i] / rho, 21588626eedSJames Wright q[3][i] / rho 21688626eedSJames Wright }; 21788626eedSJames Wright const CeedScalar E = q[4][i]; 21888626eedSJames Wright 21988626eedSJames Wright // -- Interp-to-Interp q_data 22088626eedSJames Wright // For explicit mode, the surface integral is on the RHS of ODE q_dot = f(q). 22188626eedSJames Wright // For implicit mode, it gets pulled to the LHS of implicit ODE/DAE g(q_dot, q). 22288626eedSJames Wright // We can effect this by swapping the sign on this weight 22388626eedSJames Wright const CeedScalar wdetJb = (implicit ? -1. : 1.) * q_data_sur[0][i]; 22488626eedSJames Wright 22588626eedSJames Wright // ---- Normal vect 22688626eedSJames Wright const CeedScalar norm[3] = {q_data_sur[1][i], 22788626eedSJames Wright q_data_sur[2][i], 22888626eedSJames Wright q_data_sur[3][i] 22988626eedSJames Wright }; 23088626eedSJames Wright // The Physics 23188626eedSJames Wright // Zero v so all future terms can safely sum into it 232ba6664aeSJames Wright for (CeedInt j=0; j<5; j++) v[j][i] = 0.; 23388626eedSJames Wright 23488626eedSJames Wright // Implementing outflow condition 23588626eedSJames Wright const CeedScalar P = P0; // pressure 23613fa47b2SJames Wright const CeedScalar u_normal = Dot3(norm, u); // Normal velocity 23788626eedSJames Wright // The Physics 23888626eedSJames Wright // -- Density 23988626eedSJames Wright v[0][i] -= wdetJb * rho * u_normal; 24088626eedSJames Wright 24188626eedSJames Wright // -- Momentum 242ba6664aeSJames Wright for (CeedInt j=0; j<3; j++) 24388626eedSJames Wright v[j+1][i] -= wdetJb *(rho * u_normal * u[j] + norm[j] * P); 24488626eedSJames Wright 24588626eedSJames Wright // -- Total Energy Density 24688626eedSJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 24788626eedSJames Wright 24888626eedSJames Wright } // End Quadrature Point Loop 24988626eedSJames Wright return 0; 25088626eedSJames Wright } 251dc805cc4SLeila Ghaffari 252dc805cc4SLeila Ghaffari // ***************************************************************************** 25388626eedSJames Wright #endif // channel_h 254