1ae2b091fSJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2ae2b091fSJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
38583b752SJames Wright //
48583b752SJames Wright /// @file
58583b752SJames Wright /// Implementation of differential filtering
63e17a7a1SJames Wright #include <ceed/types.h>
78583b752SJames Wright
87f93c8d1SJames Wright #include "differential_filter_enums.h"
98583b752SJames Wright #include "newtonian_state.h"
108583b752SJames Wright #include "newtonian_types.h"
118583b752SJames Wright #include "utils.h"
128583b752SJames Wright
1325c92e8fSJames Wright enum DifferentialFilterDampingFunction { DIFF_FILTER_DAMP_NONE, DIFF_FILTER_DAMP_VAN_DRIEST, DIFF_FILTER_DAMP_MMS };
141c94e285SJames Wright #ifndef CEED_RUNNING_JIT_PASS
15e5a8cae0SJames Wright extern const char *const DifferentialFilterDampingFunctions[];
161c94e285SJames Wright #endif
17682a9695SJames Wright
188583b752SJames Wright typedef struct DifferentialFilterContext_ *DifferentialFilterContext;
198583b752SJames Wright struct DifferentialFilterContext_ {
2088b07121SJames Wright bool grid_based_width;
2188b07121SJames Wright CeedScalar width_scaling[3];
2288b07121SJames Wright CeedScalar kernel_scaling;
23682a9695SJames Wright CeedScalar friction_length;
24682a9695SJames Wright enum DifferentialFilterDampingFunction damping_function;
25682a9695SJames Wright CeedScalar damping_constant;
26*cde3d787SJames Wright struct NewtonianIdealGasContext_ newt_ctx;
278583b752SJames Wright };
288583b752SJames Wright
DifferentialFilter_RHS(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,StateVariable state_var)298583b752SJames Wright CEED_QFUNCTION_HELPER int DifferentialFilter_RHS(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, StateVariable state_var) {
308583b752SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
318583b752SJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1];
321ed803a2SJames Wright CeedScalar(*v0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
331ed803a2SJames Wright CeedScalar(*v1)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1];
348583b752SJames Wright
358583b752SJames Wright DifferentialFilterContext context = (DifferentialFilterContext)ctx;
36*cde3d787SJames Wright NewtonianIGProperties gas = context->newt_ctx.gas;
378583b752SJames Wright
388583b752SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
398583b752SJames Wright const CeedScalar qi[5] = {q[0][i], q[1][i], q[2][i], q[3][i], q[4][i]};
408583b752SJames Wright const CeedScalar wdetJ = q_data[0][i];
41edcfef1bSKenneth E. Jansen const State s = StateFromQ(gas, qi, state_var);
428583b752SJames Wright
431ed803a2SJames Wright v0[DIFF_FILTER_PRESSURE][i] = wdetJ * s.Y.pressure;
441ed803a2SJames Wright v0[DIFF_FILTER_VELOCITY_X][i] = wdetJ * s.Y.velocity[0];
451ed803a2SJames Wright v0[DIFF_FILTER_VELOCITY_Y][i] = wdetJ * s.Y.velocity[1];
461ed803a2SJames Wright v0[DIFF_FILTER_VELOCITY_Z][i] = wdetJ * s.Y.velocity[2];
471ed803a2SJames Wright v0[DIFF_FILTER_TEMPERATURE][i] = wdetJ * s.Y.temperature;
481ed803a2SJames Wright v1[DIFF_FILTER_VELOCITY_SQUARED_XX][i] = wdetJ * s.Y.velocity[0] * s.Y.velocity[0];
491ed803a2SJames Wright v1[DIFF_FILTER_VELOCITY_SQUARED_YY][i] = wdetJ * s.Y.velocity[1] * s.Y.velocity[1];
501ed803a2SJames Wright v1[DIFF_FILTER_VELOCITY_SQUARED_ZZ][i] = wdetJ * s.Y.velocity[2] * s.Y.velocity[2];
511ed803a2SJames Wright v1[DIFF_FILTER_VELOCITY_SQUARED_YZ][i] = wdetJ * s.Y.velocity[1] * s.Y.velocity[2];
521ed803a2SJames Wright v1[DIFF_FILTER_VELOCITY_SQUARED_XZ][i] = wdetJ * s.Y.velocity[0] * s.Y.velocity[2];
531ed803a2SJames Wright v1[DIFF_FILTER_VELOCITY_SQUARED_XY][i] = wdetJ * s.Y.velocity[0] * s.Y.velocity[1];
548583b752SJames Wright }
558583b752SJames Wright return 0;
568583b752SJames Wright }
578583b752SJames Wright
DifferentialFilter_RHS_Conserv(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)588583b752SJames Wright CEED_QFUNCTION(DifferentialFilter_RHS_Conserv)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
598583b752SJames Wright return DifferentialFilter_RHS(ctx, Q, in, out, STATEVAR_CONSERVATIVE);
608583b752SJames Wright }
618583b752SJames Wright
DifferentialFilter_RHS_Prim(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)628583b752SJames Wright CEED_QFUNCTION(DifferentialFilter_RHS_Prim)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
638583b752SJames Wright return DifferentialFilter_RHS(ctx, Q, in, out, STATEVAR_PRIMITIVE);
648583b752SJames Wright }
658583b752SJames Wright
DifferentialFilter_RHS_Entropy(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)669b103f75SJames Wright CEED_QFUNCTION(DifferentialFilter_RHS_Entropy)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
679b103f75SJames Wright return DifferentialFilter_RHS(ctx, Q, in, out, STATEVAR_ENTROPY);
689b103f75SJames Wright }
699b103f75SJames Wright
VanDriestWallDamping(const CeedScalar wall_dist_plus,const CeedScalar A_plus)70682a9695SJames Wright CEED_QFUNCTION_HELPER CeedScalar VanDriestWallDamping(const CeedScalar wall_dist_plus, const CeedScalar A_plus) {
71682a9695SJames Wright return -expm1(-wall_dist_plus / A_plus);
72682a9695SJames Wright }
73682a9695SJames Wright
DifferentialFilter_LHS_N(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out,const CeedInt N)748583b752SJames Wright CEED_QFUNCTION_HELPER int DifferentialFilter_LHS_N(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out, const CeedInt N) {
758583b752SJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
768583b752SJames Wright const CeedScalar(*Grad_q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1];
778583b752SJames Wright const CeedScalar(*A_ij_delta)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[2];
78682a9695SJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[3];
79ade49511SJames Wright const CeedScalar(*q_data) = in[4];
808583b752SJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
818583b752SJames Wright CeedScalar(*Grad_v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[1];
828583b752SJames Wright
838583b752SJames Wright DifferentialFilterContext context = (DifferentialFilterContext)ctx;
848583b752SJames Wright
858583b752SJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
868583b752SJames Wright CeedPragmaSIMD for (CeedInt j = 0; j < N; j++) {
87682a9695SJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
88ade49511SJames Wright CeedScalar wdetJ, dXdx[3][3];
89ade49511SJames Wright QdataUnpack_3D(Q, i, q_data, &wdetJ, dXdx);
908583b752SJames Wright
918583b752SJames Wright CeedScalar Delta_ij[3][3] = {{0.}};
9288b07121SJames Wright if (context->grid_based_width) {
938583b752SJames Wright 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]};
948583b752SJames Wright const CeedScalar delta = A_ij_delta[6][i];
958583b752SJames Wright ScaleN(km_A_ij, delta, 6); // Dimensionalize the normalized anisotropy tensor
968583b752SJames Wright KMUnpack(km_A_ij, Delta_ij);
9788b07121SJames Wright } else {
9888b07121SJames Wright Delta_ij[0][0] = Delta_ij[1][1] = Delta_ij[2][2] = 1;
998583b752SJames Wright }
1008583b752SJames Wright
101682a9695SJames Wright CeedScalar scaling_matrix[3][3] = {{0}};
102682a9695SJames Wright if (context->damping_function == DIFF_FILTER_DAMP_VAN_DRIEST) {
103682a9695SJames Wright const CeedScalar damping_coeff = VanDriestWallDamping(x_i[1] / context->friction_length, context->damping_constant);
104682a9695SJames Wright scaling_matrix[0][0] = Max(1, damping_coeff * context->width_scaling[0]);
105682a9695SJames Wright scaling_matrix[1][1] = damping_coeff * context->width_scaling[1];
106682a9695SJames Wright scaling_matrix[2][2] = Max(1, damping_coeff * context->width_scaling[2]);
107682a9695SJames Wright } else if (context->damping_function == DIFF_FILTER_DAMP_NONE) {
10888b07121SJames Wright scaling_matrix[0][0] = context->width_scaling[0];
10988b07121SJames Wright scaling_matrix[1][1] = context->width_scaling[1];
11088b07121SJames Wright scaling_matrix[2][2] = context->width_scaling[2];
11125c92e8fSJames Wright } else if (context->damping_function == DIFF_FILTER_DAMP_MMS) {
11225c92e8fSJames Wright const CeedScalar damping_coeff = tanh(60 * x_i[1]);
11325c92e8fSJames Wright scaling_matrix[0][0] = 1;
11425c92e8fSJames Wright scaling_matrix[1][1] = damping_coeff;
11525c92e8fSJames Wright scaling_matrix[2][2] = 1;
116682a9695SJames Wright }
11788b07121SJames Wright
11888b07121SJames Wright CeedScalar scaled_Delta_ij[3][3] = {{0.}};
11988b07121SJames Wright MatMat3(scaling_matrix, Delta_ij, CEED_NOTRANSPOSE, CEED_NOTRANSPOSE, scaled_Delta_ij);
12088b07121SJames Wright CopyMat3(scaled_Delta_ij, Delta_ij);
12188b07121SJames Wright
1228583b752SJames Wright CeedScalar alpha_ij[3][3] = {{0.}};
1238583b752SJames Wright MatMat3(Delta_ij, Delta_ij, CEED_NOTRANSPOSE, CEED_NOTRANSPOSE, alpha_ij);
12488b07121SJames Wright ScaleN((CeedScalar *)alpha_ij, context->kernel_scaling, 9);
1258583b752SJames Wright
1268583b752SJames Wright v[j][i] = wdetJ * q[j][i];
1278583b752SJames Wright CeedScalar dq[3], dq_dXdx[3] = {0.}, dq_dXdx_a[3] = {0.};
1288583b752SJames Wright for (int k = 0; k < 3; k++) {
1298583b752SJames Wright 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];
1308583b752SJames Wright }
1318583b752SJames Wright MatVec3(dXdx, dq, CEED_NOTRANSPOSE, dq_dXdx);
1328583b752SJames Wright MatVec3(alpha_ij, dq_dXdx, CEED_NOTRANSPOSE, dq_dXdx_a);
1338583b752SJames Wright for (int k = 0; k < 3; k++) {
1348583b752SJames Wright Grad_v[k * N + j][i] = wdetJ * dq_dXdx_a[k];
1358583b752SJames Wright }
1368583b752SJames Wright }
1378583b752SJames Wright }
1388583b752SJames Wright return 0;
1398583b752SJames Wright }
1408583b752SJames Wright
DifferentialFilter_LHS_1(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)1418583b752SJames Wright CEED_QFUNCTION(DifferentialFilter_LHS_1)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
1428583b752SJames Wright return DifferentialFilter_LHS_N(ctx, Q, in, out, 1);
1438583b752SJames Wright }
1448583b752SJames Wright
DifferentialFilter_LHS_5(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)1458583b752SJames Wright CEED_QFUNCTION(DifferentialFilter_LHS_5)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
1468583b752SJames Wright return DifferentialFilter_LHS_N(ctx, Q, in, out, 5);
1478583b752SJames Wright }
1488583b752SJames Wright
DifferentialFilter_LHS_6(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)149c5e50263SJames Wright CEED_QFUNCTION(DifferentialFilter_LHS_6)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
150c5e50263SJames Wright return DifferentialFilter_LHS_N(ctx, Q, in, out, 6);
151c5e50263SJames Wright }
152c5e50263SJames Wright
DifferentialFilter_LHS_11(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)1538583b752SJames Wright CEED_QFUNCTION(DifferentialFilter_LHS_11)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
1548583b752SJames Wright return DifferentialFilter_LHS_N(ctx, Q, in, out, 11);
1558583b752SJames Wright }
15625c92e8fSJames Wright
MMS_Solution(const CeedScalar x_i[3],const CeedScalar omega)15725c92e8fSJames Wright CEED_QFUNCTION_HELPER CeedScalar MMS_Solution(const CeedScalar x_i[3], const CeedScalar omega) {
15825c92e8fSJames Wright return sin(6 * omega * x_i[0]) + sin(6 * omega * x_i[1]);
15925c92e8fSJames Wright }
16025c92e8fSJames Wright
DifferentialFilter_MMS_RHS(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)16125c92e8fSJames Wright CEED_QFUNCTION(DifferentialFilter_MMS_RHS)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
16225c92e8fSJames Wright const CeedScalar(*q)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
16325c92e8fSJames Wright const CeedScalar(*q_data)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[1];
16425c92e8fSJames Wright CeedScalar(*v)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
16525c92e8fSJames Wright
16625c92e8fSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
16725c92e8fSJames Wright const CeedScalar wdetJ = q_data[0][i];
16825c92e8fSJames Wright v[0][i] = wdetJ * q[0][i];
16925c92e8fSJames Wright }
17025c92e8fSJames Wright return 0;
17125c92e8fSJames Wright }
17225c92e8fSJames Wright
17325c92e8fSJames Wright // @brief Generate initial condition such that the solution of the differential filtering is given by MMS_Solution() above
17425c92e8fSJames Wright //
17525c92e8fSJames Wright // This requires a *very* specific grid, as the anisotropic filtering is grid dependent.
17625c92e8fSJames Wright // It's for a 75x75x1 grid on a [0,0.5]x3 domain.
17725c92e8fSJames Wright // The grid is evenly distributed in x, but distributed based on the analytical mesh distribution \Delta_y = .001 + .01*tanh(6*y).
17825c92e8fSJames Wright // The MMS test can optionally include a wall damping function (must also be enabled for the differential filtering itself).
17925c92e8fSJames Wright // It can be run via:
180da4ca0cfSJames Wright // ./navierstokes -options_file tests-output/blasius_test.yaml -diff_filter_monitor -diff_filter_view cgns:filtered_solution.cgns -ts_max_steps 0
18125c92e8fSJames Wright // -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
182da4ca0cfSJames Wright // -mesh_transform platemesh -platemesh_y_node_locs_path tests-output/diff_filter_mms_y_spacing.dat -platemesh_top_angle 0
183c029f0c5SJames Wright // -diff_filter_grid_based_width
DifferentialFilter_MMS_IC(void * ctx,CeedInt Q,const CeedScalar * const * in,CeedScalar * const * out)18425c92e8fSJames Wright CEED_QFUNCTION(DifferentialFilter_MMS_IC)(void *ctx, CeedInt Q, const CeedScalar *const *in, CeedScalar *const *out) {
18525c92e8fSJames Wright const CeedScalar(*x)[CEED_Q_VLA] = (const CeedScalar(*)[CEED_Q_VLA])in[0];
18625c92e8fSJames Wright CeedScalar(*q0)[CEED_Q_VLA] = (CeedScalar(*)[CEED_Q_VLA])out[0];
18725c92e8fSJames Wright
18825c92e8fSJames Wright CeedPragmaSIMD for (CeedInt i = 0; i < Q; i++) {
18925c92e8fSJames Wright const CeedScalar x_i[3] = {x[0][i], x[1][i], x[2][i]};
19025c92e8fSJames Wright
19125c92e8fSJames Wright const CeedScalar aniso_scale_factor = 1; // Must match the one passed in by -diff_filter_aniso_scale
19225c92e8fSJames Wright const CeedScalar omega = 2 * M_PI;
19325c92e8fSJames Wright const CeedScalar omega6 = 6 * omega;
19425c92e8fSJames Wright const CeedScalar phi_bar = MMS_Solution(x_i, omega);
19525c92e8fSJames Wright const CeedScalar dx = 0.5 / 75;
19625c92e8fSJames Wright const CeedScalar dy_analytic = .001 + .01 * tanh(6 * x_i[1]);
19725c92e8fSJames Wright const CeedScalar dy = dy_analytic;
19825c92e8fSJames Wright const CeedScalar d_dy_dy = 0.06 * Square(1 / cosh(6 * x_i[1])); // Change of \Delta_y w.r.t. y
19925c92e8fSJames Wright CeedScalar alpha[2] = {Square(dx) * aniso_scale_factor, Square(dy) * aniso_scale_factor};
20025c92e8fSJames Wright bool damping = true;
20125c92e8fSJames Wright CeedScalar dalpha1dy;
20225c92e8fSJames Wright if (damping) {
20325c92e8fSJames Wright CeedScalar damping_coeff = tanh(60 * x_i[1]);
20425c92e8fSJames Wright CeedScalar d_damping_coeff = 60 / Square(cosh(60 * x_i[1]));
20525c92e8fSJames Wright dalpha1dy = aniso_scale_factor * 2 * (damping_coeff * dy) * (dy * d_damping_coeff + damping_coeff * d_dy_dy);
20625c92e8fSJames Wright alpha[1] *= Square(damping_coeff);
20725c92e8fSJames Wright } else {
20825c92e8fSJames Wright dalpha1dy = aniso_scale_factor * 2 * dy * d_dy_dy;
20925c92e8fSJames Wright }
21025c92e8fSJames Wright
21125c92e8fSJames Wright CeedScalar phi = phi_bar + alpha[0] * Square(omega6) * sin(6 * omega * x_i[0]) + alpha[1] * Square(omega6) * sin(omega6 * x_i[1]);
21225c92e8fSJames Wright phi -= dalpha1dy * omega6 * cos(omega6 * x_i[1]);
21325c92e8fSJames Wright
21425c92e8fSJames Wright for (CeedInt j = 0; j < 5; j++) q0[j][i] = phi;
21525c92e8fSJames Wright }
21625c92e8fSJames Wright return 0;
21725c92e8fSJames Wright }
218