44 PetscFunctionBeginUser;
47 PetscFunctionReturn(0);
65 PetscFunctionBeginUser;
67 PetscFunctionReturn(0);
89 const DMDALocalInfo info = user->
info;
92 const PetscInt extent[3] = {info.mx, info.my, info.mz};
93 PetscReal ***mask = NULL;
96 PetscFunctionBeginUser;
97 PetscCall(VecSet(inclusion, 1.0));
99 PetscCall(DMDAVecGetArray(user->
da, inclusion, &mask));
100 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; k++)
101 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; j++)
102 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; i++) {
103 const PetscInt coord[3] = {i, j, k};
105 for (PetscInt axis = 0; axis < 3; axis++) {
110 coord[axis] == extent[axis] - 2)) {
116 PetscCall(DMDAVecRestoreArray(user->
da, inclusion, &mask));
117 PetscFunctionReturn(0);
131 periodic[0] = (PetscBool)(simCtx->
i_periodic != 0);
132 periodic[1] = (PetscBool)(simCtx->
j_periodic != 0);
133 periodic[2] = (PetscBool)(simCtx->
k_periodic != 0);
137#define __FUNCT__ "SymTensorSelfOuter"
158#define __FUNCT__ "SymTensorCombine"
169 t.
xx = a * x.
xx + b * y.
xx;
170 t.
xy = a * x.
xy + b * y.
xy;
171 t.
xz = a * x.
xz + b * y.
xz;
172 t.
yy = a * x.
yy + b * y.
yy;
173 t.
yz = a * x.
yz + b * y.
yz;
174 t.
zz = a * x.
zz + b * y.
zz;
179#define __FUNCT__ "SymTensorTrace"
188 return t.
xx + t.
yy + t.
zz;
192#define __FUNCT__ "SymTensorDeviator"
210#define __FUNCT__ "SymTensorContract"
225#define __FUNCT__ "SymTensorTimesVector"
236 result.
x = t.
xx * v.
x + t.
xy * v.
y + t.
xz * v.
z;
237 result.
y = t.
xy * v.
x + t.
yy * v.
y + t.
yz * v.
z;
238 result.
z = t.
xz * v.
x + t.
yz * v.
y + t.
zz * v.
z;
243#define __FUNCT__ "SymTensorNormSq"
260#define __FUNCT__ "StrainRateFromGradients"
272 PetscFunctionBeginUser;
275 s.
xy = 0.5 * (dudx.
y + dvdx.
x);
276 s.
xz = 0.5 * (dudx.
z + dwdx.
x);
278 s.
yz = 0.5 * (dvdx.
z + dwdx.
y);
281 if (strain) *strain = s;
285 PetscFunctionReturn(0);
289#define __FUNCT__ "ComputeCellFilterWidth"
299 double dx = 0.0, dy = 0.0, dz = 0.0;
301 PetscFunctionBeginUser;
302 PetscCheck(delta != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
303 "Filter width destination cannot be NULL.");
304 PetscCheck(aj > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
305 "Cell Jacobian must be positive to define a filter width; received %g.", (
double)aj);
310 *delta = PetscPowReal(1.0 / aj, 1.0 / 3.0);
311 PetscFunctionReturn(0);
322 *delta = PetscMax(dx, PetscMax(dy, dz));
329 const double longest = PetscMax(dx, PetscMax(dy, dz));
330 const double shortest = PetscMin(dx, PetscMin(dy, dz));
331 const double middle = dx + dy + dz - longest - shortest;
332 const double ln_a1 = log(shortest / longest), ln_a2 = log(middle / longest);
333 const double shape = cosh(sqrt((4.0 / 27.0) *
334 (ln_a1 * ln_a1 - ln_a1 * ln_a2 + ln_a2 * ln_a2)));
335 *delta = PetscPowReal(PetscMax(dx * dy * dz,
LES_EPSILON), 1.0 / 3.0) * shape;
340 *delta = PetscPowReal(PetscMax(dx * dy * dz,
LES_EPSILON), 1.0 / 3.0);
344 PetscFunctionReturn(0);
352#define __FUNCT__ "LeonardStress"
367#define __FUNCT__ "GermanoModelTensor"
375 PetscReal strain_magnitude_filtered,
382 strain_filtered, 0.0, strain_filtered);
388 const SymTensor grid_scale = strain_product_filtered;
391 2.0 * delta * delta, grid_scale);
403#define __FUNCT__ "ResolveLESAveragingDirections"
413 PetscInt selected = 0;
414 PetscBool periodic[3];
416 PetscFunctionBeginUser;
417 PetscCheck(direction != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
418 "Averaging direction destination cannot be NULL.");
421 for (PetscInt axis = 0; axis < 3; axis++) direction[axis] = PETSC_FALSE;
426 PetscFunctionReturn(0);
429 for (PetscInt axis = 0; axis < 3; axis++) direction[axis] = PETSC_TRUE;
430 PetscFunctionReturn(0);
434 for (PetscInt axis = 0; axis < 3; axis++) {
436 direction[axis] = PETSC_TRUE;
443 for (PetscInt axis = 0; axis < 3; axis++) {
444 if (periodic[axis]) {
445 direction[axis] = PETSC_TRUE;
450 PetscCheck(selected > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
451 "Homogeneous LES averaging was requested, but this block declares no "
452 "periodic axis and the configuration names no direction. Name the "
453 "homogeneous directions explicitly or select local averaging.");
454 PetscFunctionReturn(0);
459#define __FUNCT__ "ClipModelCoefficient"
468 PetscReal result = coefficient;
476 if (result < 0.0) result = 0.0;
480 if (result < 0.0) result = 0.0;
485 if (limited) *limited = (PetscBool)(result != coefficient);
490#define __FUNCT__ "EddyViscosityFromCoefficient"
498 PetscReal strain_magnitude,
499 PetscReal molecular_viscosity,
500 PetscReal min_viscosity_ratio)
502 PetscReal
nu_t = coefficient * delta * delta * strain_magnitude;
506 const PetscReal floor = (min_viscosity_ratio - 1.0) * molecular_viscosity;
513#define __FUNCT__ "WALEEddyViscosity"
521 PetscReal delta, PetscReal coefficient)
523 const PetscReal g[3][3] = {{dudx.
x, dudx.
y, dudx.
z},
524 {dvdx.
x, dvdx.
y, dvdx.
z},
525 {dwdx.
x, dwdx.
y, dwdx.
z}};
526 PetscReal g2[3][3], sd[3][3], trace = 0.0, ss = 0.0, sdsd = 0.0, denominator;
528 for (PetscInt a = 0; a < 3; ++a)
529 for (PetscInt b = 0; b < 3; ++b) {
531 for (PetscInt c = 0; c < 3; ++c) g2[a][b] += g[a][c] * g[c][b];
533 for (PetscInt a = 0; a < 3; ++a) trace += g2[a][a];
534 for (PetscInt a = 0; a < 3; ++a)
535 for (PetscInt b = 0; b < 3; ++b) {
536 const PetscReal s = 0.5 * (g[a][b] + g[b][a]);
539 sd[a][b] = 0.5 * (g2[a][b] + g2[b][a]) - (a == b ? trace / 3.0 : 0.0);
541 sdsd += sd[a][b] * sd[a][b];
544 denominator = PetscPowReal(ss, 2.5) + PetscPowReal(sdsd, 1.25);
546 return coefficient * coefficient * delta * delta * PetscPowReal(sdsd, 1.5) / denominator;
550#define __FUNCT__ "VremanEddyViscosity"
558 const Cmpnts edges[3], PetscReal coefficient)
560 const Cmpnts gradient[3] = {dudx, dvdx, dwdx};
561 PetscReal beta[3][3] = {{0.0}}, alpha_sq = 0.0, b_beta;
568 for (PetscInt m = 0; m < 3; ++m) {
570 for (PetscInt a = 0; a < 3; ++a)
571 change[a] = edges[m].x * gradient[a].x + edges[m].y * gradient[a].y + edges[m].z * gradient[a].z;
572 for (PetscInt a = 0; a < 3; ++a)
573 for (PetscInt b = 0; b < 3; ++b) beta[a][b] += change[a] * change[b];
575 for (PetscInt a = 0; a < 3; ++a)
576 alpha_sq += gradient[a].x * gradient[a].x + gradient[a].y * gradient[a].y + gradient[a].z * gradient[a].z;
578 b_beta = beta[0][0] * beta[1][1] - beta[0][1] * beta[0][1]
579 + beta[0][0] * beta[2][2] - beta[0][2] * beta[0][2]
580 + beta[1][1] * beta[2][2] - beta[1][2] * beta[1][2];
584 return coefficient * PetscSqrtReal(b_beta / alpha_sq);
588#define __FUNCT__ "SubgridKineticEnergy"
597 return 2.0 * yoshizawa_ci * delta * delta * strain_magnitude * strain_magnitude;
626 if (index == 0)
return periodic ? -2 : 1;
627 if (index == extent - 1)
return periodic ? extent + 1 : extent - 2;
635 Vec strain_diagonal, Vec strain_offdiagonal,
636 Vec strain_magnitude)
638 DM da = user->
da, fda = user->
fda;
641 PetscBool periodic[3];
642 Cmpnts ***diagonal = NULL, ***offdiagonal = NULL;
643 PetscReal ***magnitude = NULL;
645 PetscFunctionBeginUser;
647 PetscCall(DMDAGetLocalInfo(da, &info));
651 PetscCall(DMDAVecGetArray(fda, strain_diagonal, &diagonal));
652 PetscCall(DMDAVecGetArray(fda, strain_offdiagonal, &offdiagonal));
653 PetscCall(DMDAVecGetArray(da, strain_magnitude, &magnitude));
657 for (PetscInt k = plan.
start[2] - 1; k <= plan.
end[2]; k++)
658 for (PetscInt j = plan.
start[1] - 1; j <= plan.
end[1]; j++)
659 for (PetscInt i = plan.
start[0] - 1; i <= plan.
end[0]; i++) {
666 PetscReal strain_abs;
671 diagonal[k][j][i].
x = strain.
xx;
672 diagonal[k][j][i].
y = strain.
yy;
673 diagonal[k][j][i].
z = strain.
zz;
674 offdiagonal[k][j][i].x = strain.
xy;
675 offdiagonal[k][j][i].y = strain.
xz;
676 offdiagonal[k][j][i].z = strain.
yz;
677 magnitude[k][j][i] = strain_abs;
680 PetscCall(DMDAVecRestoreArray(fda, strain_diagonal, &diagonal));
681 PetscCall(DMDAVecRestoreArray(fda, strain_offdiagonal, &offdiagonal));
682 PetscCall(DMDAVecRestoreArray(da, strain_magnitude, &magnitude));
684 PetscFunctionReturn(0);
697 s.
xy = offdiagonal.
x;
698 s.
xz = offdiagonal.
y;
699 s.
yz = offdiagonal.
z;
708#define __FUNCT__ "ComputeSmagorinskyConstant"
719 DM da = user->
da, fda = user->
fda;
721 PetscBool average_direction[3];
724 Vec lStrainDiag, lStrainOff, lStrainAbs, lLM, lMM, lCsq;
725 Vec lWallMask = NULL;
727 Cmpnts ***ucat = NULL, ***strain_diag = NULL, ***strain_off = NULL;
728 Cmpnts ***csi = NULL, ***eta = NULL, ***zet = NULL;
729 PetscReal ***strain_abs = NULL, ***nvert = NULL, ***aj = NULL;
730 PetscReal ***lm = NULL, ***mm = NULL, ***csq = NULL, ***cs_out = NULL;
734 PetscFunctionBeginUser;
738 "The dynamic procedure runs only for the dynamic Smagorinsky model. The "
739 "constant model prescribes its coefficient from configuration and holds "
740 "no coefficient field.");
745 PetscCall(VecSet(user->
CS, 0.0));
749 "Holding the dynamic coefficient at zero for the opening steps (step=%d).\n",
752 PetscFunctionReturn(0);
771 PetscCall(VecDuplicate(user->
lUcat, &lStrainDiag));
772 PetscCall(VecDuplicate(user->
lUcat, &lStrainOff));
773 PetscCall(VecDuplicate(user->
lNvert, &lStrainAbs));
774 PetscCall(VecDuplicate(user->
lNvert, &lLM));
775 PetscCall(VecDuplicate(user->
lNvert, &lMM));
776 PetscCall(VecDuplicate(user->
lNvert, &lCsq));
777 PetscCall(VecSet(lStrainDiag, 0.0));
778 PetscCall(VecSet(lStrainOff, 0.0));
779 PetscCall(VecSet(lStrainAbs, 0.0));
780 PetscCall(VecSet(lLM, 0.0));
781 PetscCall(VecSet(lMM, 0.0));
782 PetscCall(VecSet(lCsq, 0.0));
786 PetscCall(VecDuplicate(user->
lNvert, &lWallMask));
790 PetscCall(DMDAVecGetArray(fda, user->
lUcat, &ucat));
795 PetscCall(DMDAVecGetArrayRead(fda, lStrainDiag, &strain_diag));
796 PetscCall(DMDAVecGetArrayRead(fda, lStrainOff, &strain_off));
797 PetscCall(DMDAVecGetArrayRead(da, lStrainAbs, &strain_abs));
798 PetscCall(DMDAVecGetArrayRead(fda, user->
lCsi, &csi));
799 PetscCall(DMDAVecGetArrayRead(fda, user->
lEta, &eta));
800 PetscCall(DMDAVecGetArrayRead(fda, user->
lZet, &zet));
801 PetscCall(DMDAVecGetArrayRead(da, user->
lNvert, &nvert));
802 PetscCall(DMDAVecGetArrayRead(da, user->
lAj, &aj));
803 PetscCall(DMDAVecGetArray(da, lLM, &lm));
804 PetscCall(DMDAVecGetArray(da, lMM, &mm));
807 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; k++)
808 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; j++)
809 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; i++) {
810 double velocity_x[3][3][3], velocity_y[3][3][3], velocity_z[3][3][3];
811 double strain_abs_stencil[3][3][3], weights[3][3][3];
812 SymTensor strain_stencil[3][3][3], product_stencil[3][3][3], velocity_product[3][3][3];
814 SymTensor strain_filtered, product_filtered, velocity_product_filtered;
816 PetscReal strain_abs_filtered, delta, volume;
825 for (PetscInt r = -1; r <= 1; r++)
826 for (PetscInt q = -1; q <= 1; q++)
827 for (PetscInt p = -1; p <= 1; p++) {
828 const PetscInt R = r + 1, Q = q + 1, P = p + 1;
829 const PetscInt KK = k + r, JJ = j + q, II = i + p;
831 const PetscReal strain_abs_here = strain_abs[KK][JJ][II];
833 velocity_x[R][Q][P] = ucat[KK][JJ][II].
x;
834 velocity_y[R][Q][P] = ucat[KK][JJ][II].
y;
835 velocity_z[R][Q][P] = ucat[KK][JJ][II].
z;
837 strain_stencil[R][Q][P] = strain;
838 strain_abs_stencil[R][Q][P] = strain_abs_here;
843 product_stencil[R][Q][P] =
SymTensorCombine(strain_abs_here, strain, 0.0, strain);
846 weights[R][Q][P] = aj[KK][JJ][II];
859 leonard =
LeonardStress(velocity_filtered, velocity_product_filtered);
862 csi[k][j][i], eta[k][j][i], zet[k][j][i], &delta));
864 model =
GermanoModelTensor(delta, alpha, strain_abs_filtered, strain_filtered, product_filtered);
871 volume = 1.0 / aj[k][j][i];
876 PetscCall(DMDAVecRestoreArrayRead(fda, lStrainDiag, &strain_diag));
877 PetscCall(DMDAVecRestoreArrayRead(fda, lStrainOff, &strain_off));
878 PetscCall(DMDAVecRestoreArray(da, lLM, &lm));
879 PetscCall(DMDAVecRestoreArray(da, lMM, &mm));
880 PetscCall(DMDAVecRestoreArray(fda, user->
lUcat, &ucat));
886 PetscObjectComm((PetscObject)da), lCsq, NULL));
889 PetscCall(DMDAVecGetArrayRead(da, lLM, &lm));
890 PetscCall(DMDAVecGetArrayRead(da, lMM, &mm));
891 PetscCall(DMDAVecGetArrayRead(da, lCsq, &csq));
892 PetscCall(DMDAVecGetArray(da, user->
CS, &cs_out));
894 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; k++)
895 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; j++)
896 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; i++) {
897 PetscBool limited = PETSC_FALSE;
898 PetscReal weight, raw;
901 cs_out[k][j][i] = 0.0;
905 weight = 1.0 / aj[k][j][i];
919 PetscCall(DMDAVecRestoreArrayRead(da, lLM, &lm));
920 PetscCall(DMDAVecRestoreArrayRead(da, lMM, &mm));
921 PetscCall(DMDAVecRestoreArrayRead(da, lCsq, &csq));
922 PetscCall(DMDAVecRestoreArray(da, user->
CS, &cs_out));
923 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lCsi, &csi));
924 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lEta, &eta));
925 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lZet, &zet));
926 PetscCall(DMDAVecRestoreArrayRead(da, user->
lNvert, &nvert));
927 PetscCall(DMDAVecRestoreArrayRead(da, user->
lAj, &aj));
929 PetscCall(VecDestroy(&lStrainDiag));
930 PetscCall(VecDestroy(&lStrainOff));
931 PetscCall(VecDestroy(&lStrainAbs));
932 PetscCall(VecDestroy(&lLM));
933 PetscCall(VecDestroy(&lMM));
934 PetscCall(VecDestroy(&lCsq));
935 if (lWallMask) PetscCall(VecDestroy(&lWallMask));
941 PetscFunctionReturn(0);
945#define __FUNCT__ "ComputeEddyViscosityLES"
956 DM da = user->
da, fda = user->
fda;
958 const PetscReal molecular_viscosity = 1.0 / simCtx->
ren;
965 Cmpnts ***ucat = NULL, ***csi = NULL, ***eta = NULL, ***zet = NULL;
966 PetscReal ***coefficient = NULL, ***
nu_t = NULL, ***nvert = NULL, ***aj = NULL;
968 PetscFunctionBeginUser;
973 PetscCall(DMDAVecGetArrayRead(fda, user->
lUcat, &ucat));
974 PetscCall(DMDAVecGetArrayRead(fda, user->
lCsi, &csi));
975 PetscCall(DMDAVecGetArrayRead(fda, user->
lEta, &eta));
976 PetscCall(DMDAVecGetArrayRead(fda, user->
lZet, &zet));
977 PetscCall(DMDAVecGetArray(da, user->
Nu_t, &
nu_t));
978 PetscCall(DMDAVecGetArrayRead(da, user->
lNvert, &nvert));
979 PetscCall(DMDAVecGetArrayRead(da, user->
lAj, &aj));
980 if (coefficient_is_field) PetscCall(DMDAVecGetArrayRead(da, user->
lCs, &coefficient));
982 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; k++)
983 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; j++)
984 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; i++) {
986 PetscReal strain_magnitude, delta, model_coefficient;
1004 csi[k][j][i], eta[k][j][i], zet[k][j][i], &delta));
1011 model_coefficient = coefficient_is_field ? coefficient[k][j][i] : prescribed_coefficient;
1017 if (coefficient_is_field) PetscCall(DMDAVecRestoreArrayRead(da, user->
lCs, &coefficient));
1018 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lUcat, &ucat));
1019 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lCsi, &csi));
1020 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lEta, &eta));
1021 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lZet, &zet));
1022 PetscCall(DMDAVecRestoreArray(da, user->
Nu_t, &
nu_t));
1023 PetscCall(DMDAVecRestoreArrayRead(da, user->
lNvert, &nvert));
1024 PetscCall(DMDAVecRestoreArrayRead(da, user->
lAj, &aj));
1034 PetscFunctionReturn(0);
1038#define __FUNCT__ "LogLESDiagnostics"
1049 DM da = user->
da, fda = user->
fda;
1056 const PetscBool has_coefficient =
1062 PetscReal local_sum[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
1063 PetscReal global_sum[7];
1064 PetscReal local_max[2] = {0.0, 0.0}, global_max[2];
1065 PetscReal local_min_coefficient = PETSC_MAX_REAL, global_min_coefficient;
1066 PetscReal contraction[2], global_contraction[2];
1068 Cmpnts ***ucat = NULL, ***csi = NULL, ***eta = NULL, ***zet = NULL;
1069 PetscReal ***coefficient = NULL, ***
nu_t = NULL, ***nvert = NULL, ***aj = NULL;
1071 PetscFunctionBeginUser;
1078 PetscCall(PetscObjectGetComm((PetscObject)da, &comm));
1080 PetscCall(DMDAVecGetArrayRead(fda, user->
lUcat, &ucat));
1081 PetscCall(DMDAVecGetArrayRead(fda, user->
lCsi, &csi));
1082 PetscCall(DMDAVecGetArrayRead(fda, user->
lEta, &eta));
1083 PetscCall(DMDAVecGetArrayRead(fda, user->
lZet, &zet));
1084 PetscCall(DMDAVecGetArrayRead(da, user->
lNu_t, &
nu_t));
1085 PetscCall(DMDAVecGetArrayRead(da, user->
lNvert, &nvert));
1086 PetscCall(DMDAVecGetArrayRead(da, user->
lAj, &aj));
1087 if (dynamic) PetscCall(DMDAVecGetArrayRead(da, user->
lCs, &coefficient));
1089 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; k++)
1090 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; j++)
1091 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; i++) {
1093 PetscReal strain_magnitude, delta, weight, value;
1097 weight = 1.0 / aj[k][j][i];
1098 value = dynamic ? coefficient[k][j][i]
1104 csi[k][j][i], eta[k][j][i], zet[k][j][i], &delta));
1106 local_sum[0] += weight;
1107 local_sum[3] += weight *
nu_t[k][j][i];
1109 local_max[1] = PetscMax(local_max[1],
nu_t[k][j][i]);
1110 if (has_coefficient) {
1111 local_sum[1] += weight * value;
1112 local_sum[2] += weight * value * value;
1113 local_max[0] = PetscMax(local_max[0], value);
1114 local_min_coefficient = PetscMin(local_min_coefficient, value);
1118 if (dynamic) PetscCall(DMDAVecRestoreArrayRead(da, user->
lCs, &coefficient));
1119 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lUcat, &ucat));
1120 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lCsi, &csi));
1121 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lEta, &eta));
1122 PetscCall(DMDAVecRestoreArrayRead(fda, user->
lZet, &zet));
1123 PetscCall(DMDAVecRestoreArrayRead(da, user->
lNu_t, &
nu_t));
1124 PetscCall(DMDAVecRestoreArrayRead(da, user->
lNvert, &nvert));
1125 PetscCall(DMDAVecRestoreArrayRead(da, user->
lAj, &aj));
1132 PetscCallMPI(MPI_Allreduce(local_sum, global_sum, 7, MPIU_REAL, MPI_SUM, comm));
1133 PetscCallMPI(MPI_Allreduce(local_max, global_max, 2, MPIU_REAL, MPI_MAX, comm));
1134 PetscCallMPI(MPI_Allreduce(&local_min_coefficient, &global_min_coefficient, 1, MPIU_REAL, MPI_MIN, comm));
1135 PetscCallMPI(MPI_Allreduce(contraction, global_contraction, 2, MPIU_REAL, MPI_SUM, comm));
1137 if (simCtx->
rank == 0) {
1138 const PetscReal volume = (global_sum[0] > 0.0) ? global_sum[0] : 1.0;
1139 const PetscReal mean = global_sum[1] / volume;
1140 const PetscReal mean_square = global_sum[2] / volume;
1141 const PetscReal variance = PetscMax(mean_square - mean * mean, 0.0);
1142 const PetscReal molecular = 1.0 / simCtx->
ren;
1143 const PetscReal effective = (global_contraction[1] >
LES_EPSILON)
1144 ? (global_contraction[0] / global_contraction[1]) : 0.0;
1151 const PetscReal cs_effective = (effective >= 0.0) ? PetscSqrtReal(effective)
1152 : -PetscSqrtReal(-effective);
1153 const PetscReal cs_mean = (mean >= 0.0) ? PetscSqrtReal(mean) : -PetscSqrtReal(-mean);
1156 "step,time,cs_effective,cs_mean,coefficient_mean,"
1157 "coefficient_rms,coefficient_min,coefficient_max,"
1158 "nu_t_mean,nu_t_max,nu_t_over_nu_mean,k_sgs_mean,"
1159 "backscatter_fraction,limited_fraction,physical_time", &file));
1160 PetscReal physical_time = 0.0;
1163 "%d,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e\n",
1164 (
int)simCtx->
step, (
double)simCtx->
ti,
1165 has_coefficient ? (
double)cs_effective : (double)NAN,
1166 has_coefficient ? (
double)cs_mean : (double)NAN,
1167 has_coefficient ? (
double)mean : (double)NAN,
1168 has_coefficient ? (
double)PetscSqrtReal(variance) : (double)NAN,
1169 has_coefficient ? (
double)global_min_coefficient : (double)NAN,
1170 has_coefficient ? (
double)global_max[0] : (double)NAN,
1171 (
double)(global_sum[3] / volume), (
double)global_max[1],
1172 (double)(global_sum[3] / volume / molecular),
1173 (double)(global_sum[4] / volume),
1174 (double)(global_sum[5] / volume), (double)(global_sum[6] / volume),
1175 (double)physical_time);
1176 PetscCheck(fclose(file) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
1177 "Unable to close the LES diagnostics file.");
1180 " LES coefficient: Cs_effective=%.4f, nu_t/nu (mean)=%.3e, backscatter=%.1f%%\n",
1181 (
double)cs_effective, (
double)(global_sum[3] / volume / molecular),
1182 (
double)(100.0 * global_sum[5] / volume));
1185 PetscFunctionReturn(0);
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
double ApplyLESTestFilter(LESTestFilterKernel kernel, double values[3][3][3], double weights[3][3][3])
Applies a numerical "test filter" to a 3x3x3 stencil of data points.
PetscErrorCode ApplyLESTestFilterSymTensor(LESTestFilterKernel kernel, SymTensor values[3][3][3], double weights[3][3][3], SymTensor *filtered)
Applies the test filter to all six components of a symmetric tensor.
PetscErrorCode ComputeCellEdgeVectors(PetscReal ajc, Cmpnts csi, Cmpnts eta, Cmpnts zet, Cmpnts edges[3])
Computes a cell's edge vectors along its three grid directions.
PetscErrorCode ComputeCellDirectionalExtents(PetscReal ajc, Cmpnts csi, Cmpnts eta, Cmpnts zet, double *l_xi, double *l_eta, double *l_zeta)
Computes a cell's extent along each of its own grid directions.
FieldId
Compile-time identity for a catalogued Eulerian field.
PetscErrorCode PicurvPhysicalTime(const SimCtx *simCtx, PetscReal solver_time, PetscReal *physical)
Convert a solver time to physical seconds, t * L_ref / U_ref.
Cmpnts SymTensorTimesVector(SymTensor t, Cmpnts v)
Implementation of SymTensorTimesVector().
PetscReal SymTensorNormSq(SymTensor t)
Implementation of SymTensorNormSq().
PetscErrorCode ComputeEddyViscosityLES(UserCtx *user)
Implementation of ComputeEddyViscosityLES().
SymTensor SymTensorCombine(PetscReal a, SymTensor x, PetscReal b, SymTensor y)
Implementation of SymTensorCombine().
SymTensor SymTensorSelfOuter(Cmpnts v)
Implementation of SymTensorSelfOuter().
SymTensor SymTensorDeviator(SymTensor t)
Implementation of SymTensorDeviator().
PetscReal SubgridKineticEnergy(PetscReal yoshizawa_ci, PetscReal delta, PetscReal strain_magnitude)
Implementation of SubgridKineticEnergy().
static void LESPeriodicAxes(const SimCtx *simCtx, PetscBool periodic[3])
Reports the block's per-axis periodicity in (xi, eta, zeta) order.
PetscReal SymTensorTrace(SymTensor t)
Implementation of SymTensorTrace().
PetscReal EddyViscosityFromCoefficient(PetscReal coefficient, PetscReal delta, PetscReal strain_magnitude, PetscReal molecular_viscosity, PetscReal min_viscosity_ratio)
Implementation of EddyViscosityFromCoefficient().
SymTensor GermanoModelTensor(PetscReal delta, PetscReal alpha, PetscReal strain_magnitude_filtered, SymTensor strain_filtered, SymTensor strain_product_filtered)
Implementation of GermanoModelTensor().
PetscReal ClipModelCoefficient(PetscReal coefficient, const LESConfig *config, PetscBool *limited)
Implementation of ClipModelCoefficient().
PetscErrorCode ComputeCellFilterWidth(LESFilterWidthModel model, PetscReal aj, Cmpnts csi, Cmpnts eta, Cmpnts zet, PetscReal *delta)
Implementation of ComputeCellFilterWidth().
PetscErrorCode StrainRateFromGradients(Cmpnts dudx, Cmpnts dvdx, Cmpnts dwdx, SymTensor *strain, PetscReal *magnitude)
Implementation of StrainRateFromGradients().
PetscErrorCode ResolveLESAveragingDirections(UserCtx *user, PetscBool direction[3])
Implementation of ResolveLESAveragingDirections().
SymTensor LeonardStress(Cmpnts velocity_filtered, SymTensor velocity_product_filtered)
Implementation of LeonardStress().
PetscReal SymTensorContract(SymTensor a, SymTensor b)
Implementation of SymTensorContract().
static SymTensor LESStrainAt(Cmpnts diagonal, Cmpnts offdiagonal)
Rebuilds a symmetric strain tensor from its two scratch storage vectors.
static PetscErrorCode FinalizeSmagorinskyConstantField(UserCtx *user)
Synchronizes the completed Smagorinsky coefficient field.
PetscErrorCode LogLESDiagnostics(UserCtx *user)
Implementation of LogLESDiagnostics().
static PetscErrorCode ComputeStrainRateField(UserCtx *user, Cmpnts ***ucat, Vec strain_diagonal, Vec strain_offdiagonal, Vec strain_magnitude)
Fills the strain-rate scratch fields across the computed range and its halo.
static PetscInt LESStrainSampleIndex(PetscInt index, PetscInt extent, PetscBool periodic)
Maps a cell index to the index whose strain rate represents it.
PetscErrorCode ComputeSmagorinskyConstant(UserCtx *user)
Implementation of ComputeSmagorinskyConstant().
static const double LES_EPSILON
static PetscErrorCode LESResolveDomain(UserCtx *user, SpatialTargetPlan *plan)
Resolves the iteration domain the closure computes over.
static PetscErrorCode BuildWallModelExclusionMask(UserCtx *user, Vec inclusion)
Marks the near-wall cells a wall model overwrites, so the procedure skips them.
PetscReal WALEEddyViscosity(Cmpnts dudx, Cmpnts dvdx, Cmpnts dwdx, PetscReal delta, PetscReal coefficient)
Implementation of WALEEddyViscosity().
PetscReal VremanEddyViscosity(Cmpnts dudx, Cmpnts dvdx, Cmpnts dwdx, const Cmpnts edges[3], PetscReal coefficient)
Implementation of VremanEddyViscosity().
#define GLOBAL
Scope for global logging across all processes.
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
@ LOG_INFO
Informational messages about program execution.
@ LOG_DEBUG
Detailed debugging information.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
PetscErrorCode PicurvOpenDiagnosticsCsv(const SimCtx *simCtx, const char *filename, const char *header, FILE **file)
Opens a per-run diagnostics CSV in the run's analysis directory for appending.
PetscErrorCode ComputeVectorFieldDerivatives(UserCtx *user, PetscInt i, PetscInt j, PetscInt k, Cmpnts ***field_data, Cmpnts *dudx, Cmpnts *dvdx, Cmpnts *dwdx)
Computes the derivatives of a cell-centered vector field at a specific grid point.
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Spatial target resolution for the field-statistics pipeline.
PetscBool SpatialTargetPlanMaskAllows(const SpatialTargetPlan *plan, PetscReal nvert_value)
Reports whether a point passes the plan's mask.
@ PICURV_STATISTICS_MASK_FLUID
PetscInt end[3]
Exclusive end per dimension (i, j, k).
PetscInt start[3]
Inclusive start per dimension (i, j, k).
PetscErrorCode SpatialTargetPlanCreate(UserCtx *user, FieldId field_id, PicurvStatisticsMask mask, SpatialTargetPlan *plan)
Resolves the iteration domain for one field on one block.
PetscErrorCode PicurvSpatialRatioAverage(UserCtx *user, const SpatialTargetPlan *plan, Vec numerator, Vec denominator, Vec inclusion, const PetscBool average_direction[3], MPI_Comm comm, Vec ratio, PetscReal *scalar)
Averages two fields over a target domain and divides the results.
Resolved iteration domain for one field on one block.
PetscReal yoshizawa_ci
Yoshizawa constant for the reported SGS kinetic energy.
BoundaryFaceConfig boundary_faces[6]
LESFilterWidthModel filter_width_model
How the grid filter width Delta is derived per cell.
PetscReal contraction_mm
Volume-weighted sum of M_ij M_ij over fluid cells.
LESTestFilterKernel test_filter_kernel
Discrete test-filter stencil.
LESConfig les_config
Parameters of the LES closure selected by les.
SimCtx * simCtx
Back-pointer to the master simulation context.
PetscBool valid
Set once a dynamic update has populated this state.
@ LES_TEST_FILTER_SIMPSON_IK
PetscReal max_cs
Ceiling on Cs under LES_CLIP_CLAMP.
LESClipMode clip_mode
Admissible range for the coefficient.
LESDiagnosticsState les_diagnostics
Pre-clipping statistics from the last dynamic update.
PetscBool averaging_direction[3]
Averaged-over logical directions (xi, eta, zeta).
PetscReal wale_coefficient
Model constant C_w for WALE (Nicoud & Ducros 1999).
PetscReal limited_volume
Fluid volume whose coefficient the clip modified.
PetscReal fluid_volume
Total fluid volume sampled.
PetscReal contraction_lm
Volume-weighted sum of L_ij M_ij over fluid cells.
PetscInt diagnostics_cadence
Steps between diagnostic rows.
PetscReal min_viscosity_ratio
Enforce nu + nu_t >= ratio * nu.
PetscInt wallfunction
Enable wall functions on WALL faces.
@ LES_AVERAGING_HOMOGENEOUS
PetscBool diagnostics_enabled
Append per-step coefficient statistics to the run log directory.
PetscReal constant_cs
Fixed Cs for CONSTANT_SMAGORINSKY; unused by the dynamic model.
PetscReal test_filter_width_ratio
Test-to-grid ratio per filtered direction; alpha is its square for the box, ratio^(4/3) for Simpson.
LESAveragingMode averaging_mode
Averaging set for the Germano contractions.
PetscReal vreman_coefficient
Model constant c for VREMAN (Vreman 2004: 2.5 Cs^2).
PetscInt les
Active LES closure; an LESModelType value.
PetscReal backscatter_volume
Fluid volume whose raw coefficient was negative.
LESFilterWidthModel
Selects how a cell's grid filter width is derived from its metrics.
@ LES_FILTER_WIDTH_SCOTTI
@ LES_FILTER_WIDTH_GEOMETRIC_MEAN
@ LES_FILTER_WIDTH_CUBE_ROOT_VOLUME
@ LES_FILTER_WIDTH_MAX_EDGE
BCFace
Identifies the six logical faces of a structured computational block.
A 3D point or vector with PetscScalar components.
Every user-selectable parameter of the LES closure.
Pre-clipping volume statistics captured by one dynamic-coefficient update.
The master context for the entire simulation.
A symmetric second-order tensor stored by its six independent components.
User-defined context containing data specific to a single computational grid level.
double nu_t(double yplus)
Computes turbulent eddy viscosity ratio (ν_t / ν)