1*ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors. 2*ae2b091fSJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause 3bb8a0c61SJames Wright 4bb8a0c61SJames Wright /// @file 5bb8a0c61SJames Wright /// Operator for Navier-Stokes example using PETSc 6d0cce58aSJeremy L Thompson #include <ceed.h> 7bb8a0c61SJames Wright #include <math.h> 82b916ea7SJeremy L Thompson 9cbe60e31SLeila Ghaffari #include "newtonian_state.h" 10d0cce58aSJeremy L Thompson #include "newtonian_types.h" 11704b8bbeSJames Wright #include "utils.h" 12bb8a0c61SJames Wright 13bb8a0c61SJames Wright typedef struct ChannelContext_ *ChannelContext; 14bb8a0c61SJames Wright struct ChannelContext_ { 15bb8a0c61SJames Wright bool implicit; // !< Using implicit timesteping or not 16bb8a0c61SJames Wright CeedScalar theta0; // !< Reference temperature 17bb8a0c61SJames Wright CeedScalar P0; // !< Reference Pressure 18bb8a0c61SJames Wright CeedScalar umax; // !< Centerline velocity 19bb8a0c61SJames Wright CeedScalar center; // !< Y Coordinate for center of channel 20bb8a0c61SJames Wright CeedScalar H; // !< Channel half-height 21bb8a0c61SJames Wright CeedScalar B; // !< Body-force driving the flow 22bb8a0c61SJames Wright struct NewtonianIdealGasContext_ newtonian_ctx; 23bb8a0c61SJames Wright }; 24bb8a0c61SJames Wright 252b916ea7SJeremy L Thompson CEED_QFUNCTION_HELPER State Exact_Channel(CeedInt dim, CeedScalar time, const CeedScalar X[], CeedInt Nf, void *ctx) { 26bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 27bb8a0c61SJames Wright const CeedScalar theta0 = context->theta0; 28bb8a0c61SJames Wright const CeedScalar P0 = context->P0; 29bb8a0c61SJames Wright const CeedScalar umax = context->umax; 30bb8a0c61SJames Wright const CeedScalar center = context->center; 31bb8a0c61SJames Wright const CeedScalar H = context->H; 32cbe60e31SLeila Ghaffari NewtonianIdealGasContext gas = &context->newtonian_ctx; 33cbe60e31SLeila Ghaffari const CeedScalar cp = gas->cp; 34cbe60e31SLeila Ghaffari const CeedScalar mu = gas->mu; 35cbe60e31SLeila Ghaffari const CeedScalar k = gas->k; 36cbe60e31SLeila Ghaffari // There is a gravity body force but it is excluded from 37cbe60e31SLeila Ghaffari // the potential energy due to periodicity. 38d1b9ef12SLeila Ghaffari // g = (g, 0, 0) 39d1b9ef12SLeila Ghaffari // x = (0, x_2, x_3) 40d1b9ef12SLeila Ghaffari // e_potential = dot(g, x) = 0 41d1b9ef12SLeila Ghaffari const CeedScalar x[3] = {0, X[1], X[2]}; 42bb8a0c61SJames Wright 43bb8a0c61SJames Wright const CeedScalar Pr = mu / (cp * k); 44bb8a0c61SJames Wright const CeedScalar Ec = (umax * umax) / (cp * theta0); 452b916ea7SJeremy L Thompson const CeedScalar theta = theta0 * (1 + (Pr * Ec / 3) * (1 - Square(Square((x[1] - center) / H)))); 46cbe60e31SLeila Ghaffari CeedScalar Y[5] = {0.}; 47cbe60e31SLeila Ghaffari Y[0] = P0; 48d1b9ef12SLeila Ghaffari Y[1] = umax * (1 - Square((x[1] - center) / H)); 49cbe60e31SLeila Ghaffari Y[2] = 0.; 50cbe60e31SLeila Ghaffari Y[3] = 0.; 51cbe60e31SLeila Ghaffari Y[4] = theta; 52bb8a0c61SJames Wright 53edcfef1bSKenneth E. Jansen return StateFromY(gas, Y); 54bb8a0c61SJames Wright } 55bb8a0c61SJames Wright 56bb8a0c61SJames Wright // ***************************************************************************** 57cbe60e31SLeila Ghaffari // This QFunction set the initial condition 58bb8a0c61SJames Wright // ***************************************************************************** 592b916ea7SJeremy L Thompson CEED_QFUNCTION(ICsChannel)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 60bb8a0c61SJames Wright const CeedScalar(*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 61bb8a0c61SJames Wright CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 62bb8a0c61SJames Wright 63cbe60e31SLeila Ghaffari const ChannelContext context = (ChannelContext)ctx; 649b103f75SJames Wright const NewtonianIdealGasContext gas = &context->newtonian_ctx; 65cbe60e31SLeila Ghaffari 662b916ea7SJeremy L Thompson CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 67bb8a0c61SJames Wright const CeedScalar x[] = {X[0][i], X[1][i], X[2][i]}; 68cbe60e31SLeila Ghaffari State s = Exact_Channel(3, 0., x, 5, ctx); 69a541e550SJames Wright CeedScalar q[5]; 709b103f75SJames Wright StateToQ(gas, s, q, gas->state_var); 712b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 5; j++) q0[j][i] = q[j]; 72b193fadcSJames Wright } 73bb8a0c61SJames Wright return 0; 74bb8a0c61SJames Wright } 75bb8a0c61SJames Wright 76bb8a0c61SJames Wright // ***************************************************************************** 77d1b9ef12SLeila Ghaffari // This QFunction set the inflow boundary condition for conservative variables 78d1b9ef12SLeila Ghaffari // ***************************************************************************** 792b916ea7SJeremy L Thompson CEED_QFUNCTION(Channel_Inflow)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 803d65b166SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 81ade49511SJames Wright const CeedScalar(*q_data_sur) = in[2]; 823d65b166SJames Wright const CeedScalar(*X)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 83bb8a0c61SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 843d65b166SJames Wright 85bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 86ade49511SJames Wright const bool is_implicit = context->implicit; 87d1b9ef12SLeila Ghaffari NewtonianIdealGasContext gas = &context->newtonian_ctx; 883d65b166SJames Wright const CeedScalar gamma = HeatCapacityRatio(&context->newtonian_ctx); 89bb8a0c61SJames Wright 903d65b166SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 91ade49511SJames Wright CeedScalar wdetJb, norm[3]; 92ade49511SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, norm); 93ade49511SJames Wright wdetJb *= is_implicit ? -1. : 1.; 94bb8a0c61SJames Wright 95d1b9ef12SLeila Ghaffari // There is a gravity body force but it is excluded from 96d1b9ef12SLeila Ghaffari // the potential energy due to periodicity. 97d1b9ef12SLeila Ghaffari // g = (g, 0, 0) 98d1b9ef12SLeila Ghaffari // x = (0, x_2, x_3) 99d1b9ef12SLeila Ghaffari // e_potential = dot(g, x) = 0 100d1b9ef12SLeila Ghaffari const CeedScalar x[3] = {0, X[1][i], X[2][i]}; 101d1b9ef12SLeila Ghaffari 1024b96a86bSJames Wright // Calculate prescribed inflow values 103d1b9ef12SLeila Ghaffari State s_exact = Exact_Channel(3, 0., x, 5, ctx); 104bb8a0c61SJames Wright CeedScalar q_exact[5] = {0.}; 105d1b9ef12SLeila Ghaffari UnpackState_U(s_exact.U, q_exact); 106bb8a0c61SJames Wright 107bb8a0c61SJames Wright // Find pressure using state inside the domain 108d1b9ef12SLeila Ghaffari CeedScalar q_inside[5] = {0}; 1092b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 5; j++) q_inside[j] = q[j][i]; 110edcfef1bSKenneth E. Jansen State s_inside = StateFromU(gas, q_inside); 111d1b9ef12SLeila Ghaffari const CeedScalar P = s_inside.Y.pressure; 112bb8a0c61SJames Wright 113bb8a0c61SJames Wright // Find inflow state using calculated P and prescribed velocity, theta0 114512c8ec7SJames Wright const CeedScalar e_internal = gas->cv * s_exact.Y.temperature; 115bb8a0c61SJames Wright const CeedScalar rho_in = P / ((gamma - 1) * e_internal); 1162b916ea7SJeremy L Thompson const CeedScalar E_kinetic = .5 * rho_in * Dot3(s_exact.Y.velocity, s_exact.Y.velocity); 117bb8a0c61SJames Wright const CeedScalar E = rho_in * e_internal + E_kinetic; 118d1b9ef12SLeila Ghaffari 119bb8a0c61SJames Wright // The Physics 120bb8a0c61SJames Wright // Zero v so all future terms can safely sum into it 121493642f1SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = 0.; 122bb8a0c61SJames Wright 123d1b9ef12SLeila Ghaffari const CeedScalar u_normal = Dot3(norm, s_exact.Y.velocity); 124bb8a0c61SJames Wright 125bb8a0c61SJames Wright // The Physics 126bb8a0c61SJames Wright // -- Density 127bb8a0c61SJames Wright v[0][i] -= wdetJb * rho_in * u_normal; 128bb8a0c61SJames Wright 129bb8a0c61SJames Wright // -- Momentum 1302b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 3; j++) v[j + 1][i] -= wdetJb * (rho_in * u_normal * s_exact.Y.velocity[j] + norm[j] * P); 131bb8a0c61SJames Wright 132bb8a0c61SJames Wright // -- Total Energy Density 133bb8a0c61SJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 134512c8ec7SJames Wright } 135bb8a0c61SJames Wright return 0; 136bb8a0c61SJames Wright } 137bb8a0c61SJames Wright 138bb8a0c61SJames Wright // ***************************************************************************** 139d1b9ef12SLeila Ghaffari // This QFunction set the outflow boundary condition for conservative variables 140d1b9ef12SLeila Ghaffari // ***************************************************************************** 1412b916ea7SJeremy L Thompson CEED_QFUNCTION(Channel_Outflow)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 1423d65b166SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 143ade49511SJames Wright const CeedScalar(*q_data_sur) = in[2]; 144bb8a0c61SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 145bb8a0c61SJames Wright 146bb8a0c61SJames Wright const ChannelContext context = (ChannelContext)ctx; 147ade49511SJames Wright const bool is_implicit = context->implicit; 148bb8a0c61SJames Wright 1493d65b166SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 150ade49511SJames Wright CeedScalar wdetJb, norm[3]; 151ade49511SJames Wright QdataBoundaryUnpack_3D(Q, i, q_data_sur, &wdetJb, NULL, norm); 152ade49511SJames Wright wdetJb *= is_implicit ? -1. : 1.; 153ade49511SJames Wright 154bb8a0c61SJames Wright const CeedScalar rho = q[0][i]; 1552b916ea7SJeremy L Thompson const CeedScalar u[3] = {q[1][i] / rho, q[2][i] / rho, q[3][i] / rho}; 156bb8a0c61SJames Wright const CeedScalar E = q[4][i]; 157bb8a0c61SJames Wright 158bb8a0c61SJames Wright // The Physics 159bb8a0c61SJames Wright // Zero v so all future terms can safely sum into it 160493642f1SJames Wright for (CeedInt j = 0; j < 5; j++) v[j][i] = 0.; 161bb8a0c61SJames Wright 162bb8a0c61SJames Wright // Implementing outflow condition 163512c8ec7SJames Wright const CeedScalar P = context->P0; // pressure 164704b8bbeSJames Wright const CeedScalar u_normal = Dot3(norm, u); // Normal velocity 165bb8a0c61SJames Wright // The Physics 166bb8a0c61SJames Wright // -- Density 167bb8a0c61SJames Wright v[0][i] -= wdetJb * rho * u_normal; 168bb8a0c61SJames Wright 169bb8a0c61SJames Wright // -- Momentum 1702b916ea7SJeremy L Thompson for (CeedInt j = 0; j < 3; j++) v[j + 1][i] -= wdetJb * (rho * u_normal * u[j] + norm[j] * P); 171bb8a0c61SJames Wright 172bb8a0c61SJames Wright // -- Total Energy Density 173bb8a0c61SJames Wright v[4][i] -= wdetJb * u_normal * (E + P); 174512c8ec7SJames Wright } 175bb8a0c61SJames Wright return 0; 176bb8a0c61SJames Wright } 177