19#define STATISTICS_DERIVED_OUTPUT_LENGTH 256
40_Static_assert(offsetof(
SymTensor, xx) == 0 *
sizeof(PetscReal),
"SymTensor order: xx is component 0");
41_Static_assert(offsetof(
SymTensor, xy) == 1 *
sizeof(PetscReal),
"SymTensor order: xy is component 1");
42_Static_assert(offsetof(
SymTensor, xz) == 2 *
sizeof(PetscReal),
"SymTensor order: xz is component 2");
43_Static_assert(offsetof(
SymTensor, yy) == 3 *
sizeof(PetscReal),
"SymTensor order: yy is component 3");
44_Static_assert(offsetof(
SymTensor, yz) == 4 *
sizeof(PetscReal),
"SymTensor order: yz is component 4");
45_Static_assert(offsetof(
SymTensor, zz) == 5 *
sizeof(PetscReal),
"SymTensor order: zz is component 5");
48static const char *
const kAxisName[3] = {
"x",
"y",
"z"};
58 for (PetscInt c = 0; c < 6; ++c) {
71 PetscFunctionBeginUser;
72 PetscCheck(index >= 0 && index < 6, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
73 "Product component %" PetscInt_FMT
" is outside the symmetric set.", index);
76 PetscFunctionReturn(0);
85 PetscFunctionBeginUser;
86 PetscCheck(count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Count output is required.");
87 PetscCheck(dof == 1 || dof == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
88 "Self-products are supported for scalar and three-vector fields, got dof %" PetscInt_FMT
".", dof);
89 *count = (dof == 1) ? 1 : 6;
90 PetscFunctionReturn(0);
99 PetscFunctionBeginUser;
100 PetscCheck(count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Count output is required.");
103 PetscCheck((dof_a == 1 && dof_b == 1) || (dof_a == 3 && dof_b == 1) || (dof_a == 1 && dof_b == 3),
104 PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
105 "Covariance is supported for scalar-scalar and vector-scalar pairs, got dof %" PetscInt_FMT
106 " and %" PetscInt_FMT
".", dof_a, dof_b);
107 *count = (dof_a == 3 || dof_b == 3) ? 3 : 1;
108 PetscFunctionReturn(0);
117 PetscFunctionBeginUser;
118 PetscCheck(user != NULL && dm != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
119 "Context and DM output are required.");
120 switch (components) {
121 case 1: *dm = user->
da;
break;
122 case 3: *dm = user->
fda;
break;
123 case 6: *dm = user->
fda6;
break;
125 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
126 "No block DM carries %" PetscInt_FMT
" accumulator components.", components);
128 PetscCheck(*dm != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
129 "The block DM for %" PetscInt_FMT
" accumulator components was never created.",
131 PetscFunctionReturn(0);
135#define __FUNCT__ "PicurvWindowStorageCreate"
143 PetscFunctionBeginUser;
145 PetscCheck(user != NULL && definition != NULL && storage != NULL,
146 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Context, definition, and storage are required.");
147 PetscCall(PetscMemzero(storage,
sizeof(*storage)));
152 PetscCall(DMCreateGlobalVector(user->
da, &storage->
count));
153 PetscCall(VecSet(storage->
count, 0.0));
154 PetscCall(DMCreateGlobalVector(user->
da, &storage->
weight));
155 PetscCall(VecSet(storage->
weight, 0.0));
156 PetscCall(DMCreateGlobalVector(user->
da, &storage->
weight_sq));
157 PetscCall(VecSet(storage->
weight_sq, 0.0));
160 PetscCall(PetscCalloc1((
size_t)definition->
field_count, &storage->
mean));
161 PetscCall(PetscCalloc1((
size_t)definition->
field_count, &storage->
m2));
163 for (PetscInt field_index = 0; field_index < definition->
field_count; ++field_index) {
165 PetscInt components = 0;
166 DM product_dm = NULL;
171 PetscCall(DMCreateGlobalVector(view.
dm, &storage->
mean[field_index]));
172 PetscCall(VecSet(storage->
mean[field_index], 0.0));
176 PetscCall(DMCreateGlobalVector(product_dm, &storage->
m2[field_index]));
177 PetscCall(VecSet(storage->
m2[field_index], 0.0));
183 for (PetscInt pair_index = 0; pair_index < definition->
covariance_count; ++pair_index) {
185 PetscInt components = 0;
192 PetscCall(DMCreateGlobalVector(pair_dm, &storage->
cm[pair_index]));
193 PetscCall(VecSet(storage->
cm[pair_index], 0.0));
201 PetscInt payloads = 0;
209 "Statistics window '%s' block %d: %d accumulator vector(s) over %d point(s).\n",
210 definition->
name, (
int)user->
_this, (
int)payloads, (
int)points);
213 PetscFunctionReturn(0);
222 PetscFunctionBeginUser;
223 if (storage == NULL) PetscFunctionReturn(0);
224 if (storage->
count) PetscCall(VecDestroy(&storage->
count));
225 if (storage->
weight) PetscCall(VecDestroy(&storage->
weight));
227 for (PetscInt field_index = 0; storage->
mean && field_index < storage->
field_count; ++field_index) {
228 if (storage->
mean[field_index]) PetscCall(VecDestroy(&storage->
mean[field_index]));
230 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
231 if (storage->
m2[field_index]) PetscCall(VecDestroy(&storage->
m2[field_index]));
233 for (PetscInt pair_index = 0; storage->
cm && pair_index < storage->
covariance_count; ++pair_index) {
234 if (storage->
cm[pair_index]) PetscCall(VecDestroy(&storage->
cm[pair_index]));
236 if (storage->
mean) PetscCall(PetscFree(storage->
mean));
237 if (storage->
m2) PetscCall(PetscFree(storage->
m2));
238 if (storage->
cm) PetscCall(PetscFree(storage->
cm));
239 PetscCall(PetscMemzero(storage,
sizeof(*storage)));
240 PetscFunctionReturn(0);
252 PetscFunctionBeginUser;
253 for (PetscInt field_index = 0; field_index < definition->
field_count; ++field_index) {
256 PetscFunctionReturn(0);
259 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
260 "Window '%s' requests a covariance over field '%s', which is not in its field list.",
270 PetscFunctionBeginUser;
271 PetscCheck(storage != NULL && count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
272 "Storage and count output are required.");
276 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
277 if (storage->
m2[field_index]) *count += 1;
279 PetscFunctionReturn(0);
291 PetscInt cursor = index;
293 PetscFunctionBeginUser;
294 PetscCheck(user != NULL && definition != NULL && storage != NULL && payload != NULL,
295 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
296 "Context, definition, storage, and payload output are required.");
298 PetscCheck(index >= 0 && index < total, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
299 "Payload index %" PetscInt_FMT
" is outside [0, %" PetscInt_FMT
").", index, total);
300 PetscCall(PetscMemzero(payload,
sizeof(*payload)));
306 static const char *
const occupancy_name[3] = {
"count",
"weight",
"weight_sq"};
309 occupancy[0] = storage->
count;
310 occupancy[1] = storage->
weight;
312 PetscCall(PetscStrncpy(payload->
name, occupancy_name[cursor],
sizeof(payload->
name)));
313 payload->
vec = occupancy[cursor];
315 payload->
role =
"occupancy";
317 PetscFunctionReturn(0);
321 if (cursor < storage->field_count) {
325 PetscCall(PetscSNPrintf(payload->
name,
sizeof(payload->
name),
"%s_mean",
327 payload->
vec = storage->
mean[cursor];
329 payload->
role =
"mean";
331 PetscFunctionReturn(0);
336 PetscInt product_count = 0;
339 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
340 if (storage->
m2[field_index]) ++product_count;
342 if (cursor < product_count) {
343 for (PetscInt field_index = 0; field_index < storage->
field_count; ++field_index) {
346 if (!storage->
m2[field_index])
continue;
347 if (seen++ != cursor)
continue;
349 PetscCall(PetscSNPrintf(payload->
name,
sizeof(payload->
name),
"%s_m2",
351 payload->
vec = storage->
m2[field_index];
353 payload->
role =
"second_moment";
355 PetscFunctionReturn(0);
358 cursor -= product_count;
365 PetscCheck(cursor >= 0 && cursor < storage->covariance_count, PETSC_COMM_SELF, PETSC_ERR_PLIB,
366 "Payload index %" PetscInt_FMT
" fell through the storage enumeration.", index);
369 PetscCall(PetscSNPrintf(payload->
name,
sizeof(payload->
name),
"%s_%s_cm",
371 payload->
vec = storage->
cm[cursor];
373 payload->
role =
"co_moment";
376 PetscFunctionReturn(0);
391 "mean",
"reynolds_stress",
"rms",
"tke",
"flux"
420 char *cursor = buffer;
422 PetscFunctionBeginUser;
424 PetscCheck(outputs != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Output list is required.");
425 PetscCall(PetscStrncpy(buffer, outputs,
sizeof(buffer)));
427 while (cursor && *cursor) {
428 char *comma = strchr(cursor,
',');
429 PetscBool matched = PETSC_FALSE;
431 if (comma) *comma =
'\0';
433 if (cursor[0] !=
'\0') {
436 wanted[k] = PETSC_TRUE;
437 matched = PETSC_TRUE;
440 PetscCheck(matched, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
441 "Unknown field-statistics output '%s'. Available outputs are "
442 "mean, reynolds_stress, rms, tke, and flux.", cursor);
444 cursor = comma ? comma + 1 : NULL;
446 PetscFunctionReturn(0);
459 PetscFunctionBeginUser;
467 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
469 PetscInt components = 0;
471 if (!storage->
m2[field_index])
continue;
482 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
485 if (!storage->
m2[field_index])
continue;
487 if (descriptor->
dof == 3) *count += 1;
494 PetscFunctionReturn(0);
503 const char *outputs, PetscInt *count)
507 PetscFunctionBeginUser;
508 PetscCheck(definition != NULL && storage != NULL && count != NULL,
509 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Definition, storage, and count are required.");
515 if (!wanted[k])
continue;
519 PetscFunctionReturn(0);
531 PetscFunctionBeginUser;
532 if (variance >= 0.0) {
533 *result = PetscSqrtReal(variance);
534 PetscFunctionReturn(0);
537 "Derived variance for '%s' is %g, which is too negative to be floating-point "
538 "cancellation; the accumulated state is inconsistent.", label, (
double)variance);
540 PetscFunctionReturn(0);
551 PetscInt index,
DerivedKind *kind, PetscInt *offset)
553 PetscFunctionBeginUser;
557 if (!wanted[k])
continue;
559 if (index < extent) {
562 PetscFunctionReturn(0);
566 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
567 "Derived index is past the end of the requested output set.");
571#define __FUNCT__ "PicurvWindowDerive"
578 PetscInt index, Vec scalar_target, Vec vector_target,
584 PetscReal ***weight_arr = NULL, ***weight_sq_arr = NULL, ***count_arr = NULL;
585 PetscScalar ****source = NULL, ****target = NULL;
588 Vec source_vec = NULL;
589 PetscInt offset = 0, slot = 0, member = 0;
592 PetscReal dimensional_factor = 1.0;
595 PetscInt source_components = 0;
597 PetscFunctionBeginUser;
599 PetscCheck(user != NULL && definition != NULL && storage != NULL && field != NULL,
600 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
601 "Context, definition, storage, and output are required.");
602 PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
603 "Derived index %" PetscInt_FMT
" is negative.", index);
604 PetscCall(PetscMemzero(field,
sizeof(*field)));
615 source_vec = storage->
mean[slot];
617 source_components = descriptor->
dof;
618 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_mean",
622 for (slot = 0; slot < storage->
field_count; ++slot) {
623 if (!storage->
m2[slot])
continue;
625 if (descriptor->
dof != 3)
continue;
626 if (offset-- == 0)
break;
628 source_vec = storage->
m2[slot];
631 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_tke",
644 source_vec = storage->
cm[slot];
646 PetscReal first_scale = 1.0, second_scale = 1.0;
650 &first_scale, NULL, 0));
652 &second_scale, NULL, 0));
653 dimensional_factor = first_scale * second_scale;
655 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_%s_flux",
662 for (slot = 0; slot < storage->
field_count; ++slot) {
665 if (!storage->
m2[slot])
continue;
669 if (offset < extent) { member = offset;
break; }
672 source_vec = storage->
m2[slot];
676 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_rms%s",
679 }
else if (descriptor->
dof == 1) {
680 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_variance",
686 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_R_%s",
696 Vec destination = (field->
components == 1) ? scalar_target : vector_target;
697 DM destination_dm = NULL;
699 PetscCheck(destination != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
700 "Derived field '%s' needs a %d-component destination.",
703 PetscCall(VecZeroEntries(destination));
705 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
weight, &weight_arr));
706 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
weight_sq, &weight_sq_arr));
707 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
count, &count_arr));
708 PetscCall(DMDAVecGetArrayDOFRead(source_dm, source_vec, &source));
709 PetscCall(DMDAVecGetArrayDOF(destination_dm, destination, &target));
711 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
712 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
713 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
718 if (weight_arr[k][j][i] <= 0.0)
continue;
719 pair.
count = count_arr[k][j][i];
720 pair.
weight = weight_arr[k][j][i];
726 for (PetscInt c = 0; c < field->
components; ++c) {
727 target[k][j][i][c] = source[k][j][i][c];
732 PetscReal trace = 0.0;
734 for (PetscInt c = 0; c < 3; ++c) {
738 target[k][j][i][0] = 0.5 * trace;
740 PetscReal deviation = 0.0;
742 pair.
cm = source[k][j][i][(descriptor->
dof == 1)
745 field->
name, &deviation));
746 target[k][j][i][0] = deviation;
748 for (PetscInt c = 0; c < field->
components; ++c) {
749 pair.
cm = source[k][j][i][c];
753 pair.
cm = source[k][j][i][member];
760 PetscCall(DMDAVecRestoreArrayDOF(destination_dm, destination, &target));
761 PetscCall(DMDAVecRestoreArrayDOFRead(source_dm, source_vec, &source));
762 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
count, &count_arr));
763 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
weight_sq, &weight_sq_arr));
764 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
weight, &weight_arr));
770 PetscReal base = 1.0;
776 if (PetscAbsReal(dimensional_factor - 1.0) > PETSC_MACHINE_EPSILON) {
777 PetscCall(VecScale(destination, dimensional_factor));
784 PetscFunctionReturn(0);
788#define __FUNCT__ "PicurvWindowSpatialMean"
799 const PetscBool whole_domain[3] = {PETSC_TRUE, PETSC_TRUE, PETSC_TRUE};
801 PetscFunctionBeginUser;
803 PetscCheck(user != NULL && definition != NULL && storage != NULL && field != NULL && mean != NULL,
804 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
805 "Context, definition, storage, field, and output are required.");
817 whole_domain, PETSC_COMM_WORLD, NULL, mean));
819 PetscFunctionReturn(0);
823#define __FUNCT__ "PicurvWindowValidFractionRange"
830 PetscReal *minimum, PetscReal *maximum)
833 PetscReal ***nvert = NULL;
834 PetscReal ***count_arr = NULL;
835 PetscReal local_min = PETSC_MAX_REAL;
836 PetscReal local_max = 0.0;
837 PetscReal reduced_min = 0.0, reduced_max = 0.0;
839 PetscFunctionBeginUser;
841 PetscCheck(user != NULL && definition != NULL && storage != NULL &&
842 minimum != NULL && maximum != NULL,
843 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Context, definition, storage, and outputs are required.");
850 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Nvert, &nvert));
851 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
count, &count_arr));
852 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
853 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
854 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
858 const PetscReal fraction = count_arr[k][j][i] / (PetscReal)sample_count;
860 local_min = PetscMin(local_min, fraction);
861 local_max = PetscMax(local_max, fraction);
865 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
count, &count_arr));
866 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Nvert, &nvert));
870 PetscCallMPI(MPI_Allreduce(&local_min, &reduced_min, 1, MPIU_REAL, MPIU_MIN, PETSC_COMM_WORLD));
871 PetscCallMPI(MPI_Allreduce(&local_max, &reduced_max, 1, MPIU_REAL, MPIU_MAX, PETSC_COMM_WORLD));
872 *minimum = (reduced_min == PETSC_MAX_REAL) ? 1.0 : reduced_min;
873 *maximum = reduced_max;
875 PetscFunctionReturn(0);
879#define __FUNCT__ "PicurvWindowAccumulate"
888 PetscReal ***nvert = NULL;
889 PetscReal ***count_arr = NULL, ***weight_arr = NULL, ***weight_sq_arr = NULL;
891 PetscFunctionBeginUser;
893 PetscCheck(user != NULL && definition != NULL && storage != NULL,
894 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Context, definition, and storage are required.");
895 PetscCheck(weight > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
896 "Accepted states carry a positive weight, got %g.", (
double)weight);
904 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Nvert, &nvert));
905 PetscCall(DMDAVecGetArray(user->
da, storage->
count, &count_arr));
906 PetscCall(DMDAVecGetArray(user->
da, storage->
weight, &weight_arr));
907 PetscCall(DMDAVecGetArray(user->
da, storage->
weight_sq, &weight_sq_arr));
912 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
913 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
914 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
916 count_arr[k][j][i] += 1.0;
917 weight_arr[k][j][i] += weight;
918 weight_sq_arr[k][j][i] += weight * weight;
928 PetscScalar ****src_a = NULL, ****mean_a = NULL;
929 PetscScalar ****src_b = NULL, ****mean_b = NULL;
930 PetscScalar ****co_moment = NULL;
932 PetscInt slot_a = 0, slot_b = 0, dof_a = 0, dof_b = 0, components = 0;
945 PetscCall(DMDAVecGetArrayDOFRead(view_a.
dm, view_a.
global_vec, &src_a));
946 PetscCall(DMDAVecGetArrayDOFRead(view_a.
dm, storage->
mean[slot_a], &mean_a));
947 PetscCall(DMDAVecGetArrayDOFRead(view_b.
dm, view_b.
global_vec, &src_b));
948 PetscCall(DMDAVecGetArrayDOFRead(view_b.
dm, storage->
mean[slot_b], &mean_b));
949 PetscCall(DMDAVecGetArrayDOF(pair_dm, storage->
cm[pair], &co_moment));
951 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
952 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
953 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
955 for (PetscInt c = 0; c < components; ++c) {
959 const PetscInt component_a = (dof_a == 3) ? c : 0;
960 const PetscInt component_b = (dof_b == 3) ? c : 0;
963 state.
count = count_arr[k][j][i] - 1.0;
964 state.
weight = weight_arr[k][j][i] - weight;
965 state.
weight_sq = weight_sq_arr[k][j][i] - weight * weight;
966 state.
mean_x = mean_a[k][j][i][component_a];
967 state.
mean_y = mean_b[k][j][i][component_b];
968 state.
cm = co_moment[k][j][i][c];
970 src_a[k][j][i][component_a],
971 src_b[k][j][i][component_b], weight));
972 co_moment[k][j][i][c] = state.
cm;
978 PetscCall(DMDAVecRestoreArrayDOF(pair_dm, storage->
cm[pair], &co_moment));
979 PetscCall(DMDAVecRestoreArrayDOFRead(view_b.
dm, storage->
mean[slot_b], &mean_b));
980 PetscCall(DMDAVecRestoreArrayDOFRead(view_b.
dm, view_b.
global_vec, &src_b));
981 PetscCall(DMDAVecRestoreArrayDOFRead(view_a.
dm, storage->
mean[slot_a], &mean_a));
982 PetscCall(DMDAVecRestoreArrayDOFRead(view_a.
dm, view_a.
global_vec, &src_a));
989 for (PetscInt field_index = 0; field_index < definition->
field_count; ++field_index) {
991 PetscScalar ****src = NULL, ****mean = NULL, ****product = NULL;
992 DM product_dm = NULL;
993 PetscInt dof = 0, components = 0;
998 PetscCall(DMDAVecGetArrayDOFRead(view.
dm, view.
global_vec, &src));
999 PetscCall(DMDAVecGetArrayDOF(view.
dm, storage->
mean[field_index], &mean));
1003 PetscCall(DMDAVecGetArrayDOF(product_dm, storage->
m2[field_index], &product));
1006 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
1007 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
1008 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
1009 PetscReal prior_weight = 0.0;
1010 PetscReal prior_weight_sq = 0.0;
1011 PetscReal prior_count = 0.0;
1015 prior_weight = weight_arr[k][j][i] - weight;
1016 prior_weight_sq = weight_sq_arr[k][j][i] - weight * weight;
1017 prior_count = count_arr[k][j][i] - 1.0;
1021 for (PetscInt c = 0; c < components; ++c) {
1026 state.
count = prior_count;
1027 state.
weight = prior_weight;
1029 state.
mean_x = mean[k][j][i][a];
1030 state.
mean_y = mean[k][j][i][b];
1031 state.
cm = product[k][j][i][c];
1033 src[k][j][i][b], weight));
1034 product[k][j][i][c] = state.
cm;
1037 for (PetscInt c = 0; c < dof; ++c) {
1040 moment.
count = prior_count;
1041 moment.
weight = prior_weight;
1043 moment.
mean = mean[k][j][i][c];
1046 mean[k][j][i][c] = moment.
mean;
1052 if (second) PetscCall(DMDAVecRestoreArrayDOF(product_dm, storage->
m2[field_index], &product));
1053 PetscCall(DMDAVecRestoreArrayDOF(view.
dm, storage->
mean[field_index], &mean));
1054 PetscCall(DMDAVecRestoreArrayDOFRead(view.
dm, view.
global_vec, &src));
1057 PetscCall(DMDAVecRestoreArray(user->
da, storage->
weight_sq, &weight_sq_arr));
1058 PetscCall(DMDAVecRestoreArray(user->
da, storage->
weight, &weight_arr));
1059 PetscCall(DMDAVecRestoreArray(user->
da, storage->
count, &count_arr));
1060 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Nvert, &nvert));
1062 PetscFunctionReturn(0);
Authoritative identities and storage metadata for persistent Eulerian fields.
const FieldDescriptor * descriptor
const char * FieldCanonicalName(FieldId field_id)
Return the canonical printable name for an ID.
PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
Resolve the existing DM and global/local vectors for one field.
@ FIELD_LAYOUT_CELL_CENTERED
const char * canonical_name
const char * FieldLayoutName(FieldLayout layout)
Return a stable printable label for a field layout.
PetscErrorCode FieldGetDescriptor(FieldId field_id, const FieldDescriptor **descriptor)
Return immutable metadata for a valid field identifier.
FieldId
Compile-time identity for a catalogued Eulerian field.
Immutable metadata for one field identity.
Non-owning runtime objects resolved for one field and UserCtx.
Public interface for data input/output routines.
PetscErrorCode PicurvFieldReferenceScale(SimCtx *simCtx, const char *field_name, PetscReal *scale, char *description, size_t description_length)
Physical scale one field is multiplied by to leave non-dimensional form.
void TrimWhitespace(char *str)
Removes leading and trailing ASCII whitespace from a mutable string.
Logging utilities and macros for PETSc-based applications.
#define LOCAL
Logging scope definitions for controlling message output.
#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_DEBUG
Detailed debugging information.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
static const PetscInt kProductFirst[6]
Upper-triangular row-major component pairs for a three-vector self-product.
PetscErrorCode PicurvProductComponentCount(PetscInt dof, PetscInt *count)
Implementation of PicurvProductComponentCount().
static const char *const kDerivedKindName[DERIVED_KIND_COUNT]
Recipe spellings of the output kinds.
static const char *const kAxisName[3]
Axis labels indexing the pair table above.
#define STATISTICS_DERIVED_OUTPUT_LENGTH
Longest output list a recipe may request.
static PetscErrorCode ParseDerivedKinds(const char *outputs, PetscBool wanted[DERIVED_KIND_COUNT])
Internal helper: reports which output kinds a recipe requested.
static PetscInt ProductDiagonalIndex(PetscInt component)
Internal helper: the product index carrying one component's own variance.
PetscErrorCode PicurvWindowDerive(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, const char *outputs, PetscInt index, Vec scalar_target, Vec vector_target, PicurvDerivedField *field)
Implementation of PicurvWindowDerive().
static PetscErrorCode FindFieldSlot(const PicurvWindowDefinition *definition, PetscInt field_id, PetscInt *slot)
Internal helper: locates the storage slot holding one field's running mean.
static PetscErrorCode ResolveDerivedIndex(const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, const PetscBool wanted[DERIVED_KIND_COUNT], PetscInt index, DerivedKind *kind, PetscInt *offset)
Internal helper: resolves which kind and member one derived index selects.
DerivedKind
Output kinds a postprocessing recipe may request, in enumeration order.
@ DERIVED_REYNOLDS_STRESS
PetscErrorCode PicurvWindowDerivedCount(const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, const char *outputs, PetscInt *count)
Implementation of PicurvWindowDerivedCount().
static PetscErrorCode ProductComponentLabel(PetscInt index, char *out, size_t size)
Internal helper: writes the two-axis label of one product component.
PetscErrorCode PicurvWindowStorageCreate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage)
Implementation of PicurvWindowStorageCreate().
PetscErrorCode PicurvCovarianceComponentCount(PetscInt dof_a, PetscInt dof_b, PetscInt *count)
Implementation of PicurvCovarianceComponentCount().
PetscErrorCode PicurvWindowStoragePayload(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt index, PicurvStatisticsPayload *payload)
Implementation of PicurvWindowStoragePayload().
static const PetscInt kProductSecond[6]
PetscErrorCode PicurvWindowValidFractionRange(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt sample_count, PetscReal *minimum, PetscReal *maximum)
Implementation of PicurvWindowValidFractionRange().
static const PetscInt kDerivedKindScaleExponent[DERIVED_KIND_COUNT]
Power of the source field's reference scale each derived kind carries.
static PetscErrorCode SafeStandardDeviation(PetscReal variance, const char *label, PetscReal *result)
Internal helper: takes a square root of a variance that may be barely negative.
PetscErrorCode PicurvStatisticsComponentDM(UserCtx *user, PetscInt components, DM *dm)
Implementation of PicurvStatisticsComponentDM().
PetscErrorCode PicurvWindowSpatialMean(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, Vec field, PetscReal *mean)
Implementation of PicurvWindowSpatialMean().
static PetscErrorCode DerivedKindExtent(const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, DerivedKind kind, PetscInt *count)
Internal helper: counts the derived fields each kind contributes.
PetscErrorCode PicurvWindowAccumulate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage, PetscReal weight)
Implementation of PicurvWindowAccumulate().
PetscErrorCode PicurvWindowStorageDestroy(PicurvWindowStorage *storage)
Implementation of PicurvWindowStorageDestroy().
PetscErrorCode PicurvWindowStoragePayloadCount(const PicurvWindowStorage *storage, PetscInt *count)
Implementation of PicurvWindowStoragePayloadCount().
Per-window PETSc accumulator storage and pointwise application.
Vec weight
Per-point valid weight.
PetscInt components
Degrees of freedom the vector carries.
PetscInt components
One or three.
Vec weight_sq
Per-point squared-weight sum.
PetscInt field_count
Fields accumulated.
PetscInt covariance_count
Covariance pairs accumulated.
char name[96]
Output field name, window qualified.
#define PICURV_STATISTICS_VARIANCE_FLOOR
Tolerance within which a negative variance is treated as floating-point noise.
Vec * mean
One per field, matching that field's layout.
Vec vec
Borrowed accumulator vector; never owned by the caller.
Vec * m2
One per field; NULL when no second moment was requested.
const char * role
Inventory role: occupancy, mean, second_moment, co_moment.
Vec count
Per-point accepted sample count.
char name[96]
File basename, no extension.
const char * layout
Catalog layout name for the inventory entry.
Vec * cm
One per covariance pair.
One derived output field, resolved by enumeration index.
One checkpointable accumulator vector, resolved by enumeration index.
Independent accumulator state for one window on one block.
Weighted centered-moment kernels for the field-statistics pipeline.
PetscReal weight_sq
Sum of squared weights W2.
PetscReal weight_sq
Sum of squared weights W2.
PetscErrorCode PicurvCoMomentStateUpdate(PicurvCoMomentState *state, PetscReal value_x, PetscReal value_y, PetscReal weight)
Applies one weighted paired sample to a co-moment accumulator.
PetscReal mean_y
Weighted mean of the second member.
PetscReal weight
Total weight W.
PetscReal count
Number of accepted samples.
PetscReal cm
Centered co-moment sum C.
PetscReal m2
Centered second-moment sum M2.
PetscReal PicurvCoMomentStateCovariance(const PicurvCoMomentState *state)
Returns the weighted covariance C/W, or zero when no weight accumulated.
PetscReal mean
Weighted mean mu.
PetscReal mean_x
Weighted mean of the first member.
PetscErrorCode PicurvMomentStateUpdate(PicurvMomentState *state, PetscReal value, PetscReal weight)
Applies one weighted sample to a scalar moment accumulator.
PetscReal weight
Total weight W.
PetscReal count
Number of accepted samples.
Weighted centered co-moment state for one ordered pair of quantities.
Weighted centered state for one scalar quantity at one point.
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 SpatialTargetPlanGlobalPointCount(const SpatialTargetPlan *plan, MPI_Comm comm, PetscInt *count)
Counts the points contributed across a communicator.
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.
PetscInt first
First member; must also appear in the field list.
PicurvWindowFieldRequest fields[16]
PetscBool want_second
Also keep the centered second moment.
PetscInt second
Second member; must also appear in the field list.
PicurvWindowCovarianceRequest covariances[16]
PetscInt covariance_count
PetscInt field_id
Catalogued Eulerian field identity.
The scientifically immutable definition of one window.
SimCtx * simCtx
Back-pointer to the master simulation context.
PetscBool dimensionalize
Whether derived output leaves non-dimensional form, from global_operations.dimensionalize.
A symmetric second-order tensor stored by its six independent components.
User-defined context containing data specific to a single computational grid level.