1 // Copyright (c) 2017-2023, Lawrence Livermore National Security, LLC and other CEED contributors. 2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 3 // 4 // SPDX-License-Identifier: BSD-2-Clause 5 // 6 // This file is part of CEED: http://github.com/ceed 7 // 8 /// @file 9 /// Implementation of differential filtering 10 11 #include <ceed.h> 12 13 #include "newtonian_state.h" 14 #include "newtonian_types.h" 15 #include "utils.h" 16 17 enum DifferentialFilterStateComponent { 18 DIFF_FILTER_PRESSURE, 19 DIFF_FILTER_VELOCITY_X, 20 DIFF_FILTER_VELOCITY_Y, 21 DIFF_FILTER_VELOCITY_Z, 22 DIFF_FILTER_TEMPERATURE, 23 DIFF_FILTER_STATE_NUM, 24 }; 25 26 enum DifferentialFilterVelocitySquared { 27 DIFF_FILTER_VELOCITY_SQUARED_XX, 28 DIFF_FILTER_VELOCITY_SQUARED_YY, 29 DIFF_FILTER_VELOCITY_SQUARED_ZZ, 30 DIFF_FILTER_VELOCITY_SQUARED_YZ, 31 DIFF_FILTER_VELOCITY_SQUARED_XZ, 32 DIFF_FILTER_VELOCITY_SQUARED_XY, 33 DIFF_FILTER_VELOCITY_SQUARED_NUM, 34 }; 35 36 enum DifferentialFilterDampingFunction { DIFF_FILTER_DAMP_NONE, DIFF_FILTER_DAMP_VAN_DRIEST, DIFF_FILTER_DAMP_MMS }; 37 38 typedef struct DifferentialFilterContext_ *DifferentialFilterContext; 39 struct DifferentialFilterContext_ { 40 bool grid_based_width; 41 CeedScalar width_scaling[3]; 42 CeedScalar kernel_scaling; 43 CeedScalar friction_length; 44 enum DifferentialFilterDampingFunction damping_function; 45 CeedScalar damping_constant; 46 struct NewtonianIdealGasContext_ gas; 47 }; 48 49 CEED_QFUNCTION_HELPER int DifferentialFilter_RHS(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) { 50 const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 51 const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1]; 52 const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 53 CeedScalar(*v0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 54 CeedScalar(*v1)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 55 56 DifferentialFilterContext context = (DifferentialFilterContext)ctx; 57 NewtonianIdealGasContext gas = &context->gas; 58 59 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 60 const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]}; 61 const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 62 const CeedScalar wdetJ = q_data[0][i]; 63 const State s = StateFromQ(gas, qi, state_var); 64 65 v0[DIFF_FILTER_PRESSURE][i] = wdetJ * s.Y.pressure; 66 v0[DIFF_FILTER_VELOCITY_X][i] = wdetJ * s.Y.velocity[0]; 67 v0[DIFF_FILTER_VELOCITY_Y][i] = wdetJ * s.Y.velocity[1]; 68 v0[DIFF_FILTER_VELOCITY_Z][i] = wdetJ * s.Y.velocity[2]; 69 v0[DIFF_FILTER_TEMPERATURE][i] = wdetJ * s.Y.temperature; 70 v1[DIFF_FILTER_VELOCITY_SQUARED_XX][i] = wdetJ * s.Y.velocity[0] * s.Y.velocity[0]; 71 v1[DIFF_FILTER_VELOCITY_SQUARED_YY][i] = wdetJ * s.Y.velocity[1] * s.Y.velocity[1]; 72 v1[DIFF_FILTER_VELOCITY_SQUARED_ZZ][i] = wdetJ * s.Y.velocity[2] * s.Y.velocity[2]; 73 v1[DIFF_FILTER_VELOCITY_SQUARED_YZ][i] = wdetJ * s.Y.velocity[1] * s.Y.velocity[2]; 74 v1[DIFF_FILTER_VELOCITY_SQUARED_XZ][i] = wdetJ * s.Y.velocity[0] * s.Y.velocity[2]; 75 v1[DIFF_FILTER_VELOCITY_SQUARED_XY][i] = wdetJ * s.Y.velocity[0] * s.Y.velocity[1]; 76 } 77 return 0; 78 } 79 80 CEED_QFUNCTION(DifferentialFilter_RHS_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 81 return DifferentialFilter_RHS(ctx, Q, in, out, STATEVAR_CONSERVATIVE); 82 } 83 84 CEED_QFUNCTION(DifferentialFilter_RHS_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 85 return DifferentialFilter_RHS(ctx, Q, in, out, STATEVAR_PRIMITIVE); 86 } 87 88 CEED_QFUNCTION_HELPER CeedScalar VanDriestWallDamping(const CeedScalar wall_dist_plus, const CeedScalar A_plus) { 89 return -expm1(-wall_dist_plus / A_plus); 90 } 91 92 CEED_QFUNCTION_HELPER int DifferentialFilter_LHS_N(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, const CeedInt N) { 93 const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 94 const CeedScalar(*Grad_q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1]; 95 const CeedScalar(*A_ij_delta)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2]; 96 const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3]; 97 const CeedScalar(*q_data) = in[4]; 98 CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 99 CeedScalar(*Grad_v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1]; 100 101 DifferentialFilterContext context = (DifferentialFilterContext)ctx; 102 103 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 104 CeedPragmaSIMD for (CeedInt j = 0; j < N; j++) { 105 const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 106 CeedScalar wdetJ, dXdx[3][3]; 107 QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx); 108 109 CeedScalar Delta_ij[3][3] = {{0.}}; 110 if (context->grid_based_width) { 111 CeedScalar km_A_ij[6] = {A_ij_delta[0][i], A_ij_delta[1][i], A_ij_delta[2][i], A_ij_delta[3][i], A_ij_delta[4][i], A_ij_delta[5][i]}; 112 const CeedScalar delta = A_ij_delta[6][i]; 113 ScaleN(km_A_ij, delta, 6); // Dimensionalize the normalized anisotropy tensor 114 KMUnpack(km_A_ij, Delta_ij); 115 } else { 116 Delta_ij[0][0] = Delta_ij[1][1] = Delta_ij[2][2] = 1; 117 } 118 119 CeedScalar scaling_matrix[3][3] = {{0}}; 120 if (context->damping_function == DIFF_FILTER_DAMP_VAN_DRIEST) { 121 const CeedScalar damping_coeff = VanDriestWallDamping(x_i[1] / context->friction_length, context->damping_constant); 122 scaling_matrix[0][0] = Max(1, damping_coeff * context->width_scaling[0]); 123 scaling_matrix[1][1] = damping_coeff * context->width_scaling[1]; 124 scaling_matrix[2][2] = Max(1, damping_coeff * context->width_scaling[2]); 125 } else if (context->damping_function == DIFF_FILTER_DAMP_NONE) { 126 scaling_matrix[0][0] = context->width_scaling[0]; 127 scaling_matrix[1][1] = context->width_scaling[1]; 128 scaling_matrix[2][2] = context->width_scaling[2]; 129 } else if (context->damping_function == DIFF_FILTER_DAMP_MMS) { 130 const CeedScalar damping_coeff = tanh(60 * x_i[1]); 131 scaling_matrix[0][0] = 1; 132 scaling_matrix[1][1] = damping_coeff; 133 scaling_matrix[2][2] = 1; 134 } 135 136 CeedScalar scaled_Delta_ij[3][3] = {{0.}}; 137 MatMat3(scaling_matrix, Delta_ij, CEED_NOTRANSPOSE, CEED_NOTRANSPOSE, scaled_Delta_ij); 138 CopyMat3(scaled_Delta_ij, Delta_ij); 139 140 CeedScalar alpha_ij[3][3] = {{0.}}; 141 MatMat3(Delta_ij, Delta_ij, CEED_NOTRANSPOSE, CEED_NOTRANSPOSE, alpha_ij); 142 ScaleN((CeedScalar *)alpha_ij, context->kernel_scaling, 9); 143 144 v[j][i] = wdetJ * q[j][i]; 145 CeedScalar dq[3], dq_dXdx[3] = {0.}, dq_dXdx_a[3] = {0.}; 146 for (int k = 0; k < 3; k++) { 147 dq[k] = Grad_q[0 * N + j][i] * dXdx[0][k] + Grad_q[1 * N + j][i] * dXdx[1][k] + Grad_q[2 * N + j][i] * dXdx[2][k]; 148 } 149 MatVec3(dXdx, dq, CEED_NOTRANSPOSE, dq_dXdx); 150 MatVec3(alpha_ij, dq_dXdx, CEED_NOTRANSPOSE, dq_dXdx_a); 151 for (int k = 0; k < 3; k++) { 152 Grad_v[k * N + j][i] = wdetJ * dq_dXdx_a[k]; 153 } 154 } 155 } 156 return 0; 157 } 158 159 CEED_QFUNCTION(DifferentialFilter_LHS_1)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 160 return DifferentialFilter_LHS_N(ctx, Q, in, out, 1); 161 } 162 163 CEED_QFUNCTION(DifferentialFilter_LHS_5)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 164 return DifferentialFilter_LHS_N(ctx, Q, in, out, 5); 165 } 166 167 CEED_QFUNCTION(DifferentialFilter_LHS_6)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 168 return DifferentialFilter_LHS_N(ctx, Q, in, out, 6); 169 } 170 171 CEED_QFUNCTION(DifferentialFilter_LHS_11)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 172 return DifferentialFilter_LHS_N(ctx, Q, in, out, 11); 173 } 174 175 CEED_QFUNCTION_HELPER CeedScalar MMS_Solution(const CeedScalar x_i[3], const CeedScalar omega) { 176 return sin(6 * omega * x_i[0]) + sin(6 * omega * x_i[1]); 177 } 178 179 CEED_QFUNCTION(DifferentialFilter_MMS_RHS)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 180 const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 181 const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1]; 182 CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 183 184 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 185 const CeedScalar wdetJ = q_data[0][i]; 186 v[0][i] = wdetJ * q[0][i]; 187 } 188 return 0; 189 } 190 191 // @brief Generate initial condition such that the solution of the differential filtering is given by MMS_Solution() above 192 // 193 // This requires a *very* specific grid, as the anisotropic filtering is grid dependent. 194 // It's for a 75x75x1 grid on a [0,0.5]x3 domain. 195 // The grid is evenly distributed in x, but distributed based on the analytical mesh distribution \Delta_y = .001 + .01*tanh(6*y). 196 // The MMS test can optionally include a wall damping function (must also be enabled for the differential filtering itself). 197 // It can be run via: 198 // ./navierstokes -options_file tests-output/blasius_test.yaml -diff_filter_monitor -diff_filter_view cgns:filtered_solution.cgns -ts_max_steps 0 199 // -diff_filter_mms -diff_filter_kernel_scaling 1 -diff_filter_wall_damping_function mms -dm_plex_box_upper 0.5,0.5,0.5 -dm_plex_box_faces 75,75,1 200 // -mesh_transform platemesh -platemesh_y_node_locs_path tests-output/diff_filter_mms_y_spacing.dat -platemesh_top_angle 0 201 // -diff_filter_grid_based_width 202 CEED_QFUNCTION(DifferentialFilter_MMS_IC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) { 203 const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0]; 204 CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0]; 205 206 CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) { 207 const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]}; 208 209 const CeedScalar aniso_scale_factor = 1; // Must match the one passed in by -diff_filter_aniso_scale 210 const CeedScalar omega = 2 * M_PI; 211 const CeedScalar omega6 = 6 * omega; 212 const CeedScalar phi_bar = MMS_Solution(x_i, omega); 213 const CeedScalar dx = 0.5 / 75; 214 const CeedScalar dy_analytic = .001 + .01 * tanh(6 * x_i[1]); 215 const CeedScalar dy = dy_analytic; 216 const CeedScalar d_dy_dy = 0.06 * Square(1 / cosh(6 * x_i[1])); // Change of \Delta_y w.r.t. y 217 CeedScalar alpha[2] = {Square(dx) * aniso_scale_factor, Square(dy) * aniso_scale_factor}; 218 bool damping = true; 219 CeedScalar dalpha1dy; 220 if (damping) { 221 CeedScalar damping_coeff = tanh(60 * x_i[1]); 222 CeedScalar d_damping_coeff = 60 / Square(cosh(60 * x_i[1])); 223 dalpha1dy = aniso_scale_factor * 2 * (damping_coeff * dy) * (dy * d_damping_coeff + damping_coeff * d_dy_dy); 224 alpha[1] *= Square(damping_coeff); 225 } else { 226 dalpha1dy = aniso_scale_factor * 2 * dy * d_dy_dy; 227 } 228 229 CeedScalar phi = phi_bar + alpha[0] * Square(omega6) * sin(6 * omega * x_i[0]) + alpha[1] * Square(omega6) * sin(omega6 * x_i[1]); 230 phi -= dalpha1dy * omega6 * cos(omega6 * x_i[1]); 231 232 for (CeedInt j = 0; j < 5; j++) q0[j][i] = phi; 233 } 234 return 0; 235 } 236