17#define STATISTICS_DERIVED_OUTPUT_LENGTH 256
32static const char *
const kAxisName[3] = {
"x",
"y",
"z"};
42 for (PetscInt c = 0; c < 6; ++c) {
55 PetscFunctionBeginUser;
56 PetscCheck(index >= 0 && index < 6, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
57 "Product component %" PetscInt_FMT
" is outside the symmetric set.", index);
60 PetscFunctionReturn(0);
69 PetscFunctionBeginUser;
70 PetscCheck(count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Count output is required.");
71 PetscCheck(dof == 1 || dof == 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
72 "Self-products are supported for scalar and three-vector fields, got dof %" PetscInt_FMT
".", dof);
73 *count = (dof == 1) ? 1 : 6;
74 PetscFunctionReturn(0);
83 PetscFunctionBeginUser;
84 PetscCheck(count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Count output is required.");
87 PetscCheck((dof_a == 1 && dof_b == 1) || (dof_a == 3 && dof_b == 1) || (dof_a == 1 && dof_b == 3),
88 PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
89 "Covariance is supported for scalar-scalar and vector-scalar pairs, got dof %" PetscInt_FMT
90 " and %" PetscInt_FMT
".", dof_a, dof_b);
91 *count = (dof_a == 3 || dof_b == 3) ? 3 : 1;
92 PetscFunctionReturn(0);
101 PetscFunctionBeginUser;
102 PetscCheck(user != NULL && dm != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
103 "Context and DM output are required.");
104 switch (components) {
105 case 1: *dm = user->
da;
break;
106 case 3: *dm = user->
fda;
break;
107 case 6: *dm = user->
fda6;
break;
109 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
110 "No block DM carries %" PetscInt_FMT
" accumulator components.", components);
112 PetscCheck(*dm != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
113 "The block DM for %" PetscInt_FMT
" accumulator components was never created.",
115 PetscFunctionReturn(0);
125 PetscFunctionBeginUser;
126 PetscCheck(user != NULL && definition != NULL && storage != NULL,
127 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Context, definition, and storage are required.");
128 PetscCall(PetscMemzero(storage,
sizeof(*storage)));
133 PetscCall(DMCreateGlobalVector(user->
da, &storage->
count));
134 PetscCall(VecSet(storage->
count, 0.0));
135 PetscCall(DMCreateGlobalVector(user->
da, &storage->
weight));
136 PetscCall(VecSet(storage->
weight, 0.0));
137 PetscCall(DMCreateGlobalVector(user->
da, &storage->
weight_sq));
138 PetscCall(VecSet(storage->
weight_sq, 0.0));
141 PetscCall(PetscCalloc1((
size_t)definition->
field_count, &storage->
mean));
142 PetscCall(PetscCalloc1((
size_t)definition->
field_count, &storage->
m2));
144 for (PetscInt field_index = 0; field_index < definition->
field_count; ++field_index) {
146 PetscInt components = 0;
147 DM product_dm = NULL;
152 PetscCall(DMCreateGlobalVector(view.
dm, &storage->
mean[field_index]));
153 PetscCall(VecSet(storage->
mean[field_index], 0.0));
157 PetscCall(DMCreateGlobalVector(product_dm, &storage->
m2[field_index]));
158 PetscCall(VecSet(storage->
m2[field_index], 0.0));
164 for (PetscInt pair_index = 0; pair_index < definition->
covariance_count; ++pair_index) {
166 PetscInt components = 0;
173 PetscCall(DMCreateGlobalVector(pair_dm, &storage->
cm[pair_index]));
174 PetscCall(VecSet(storage->
cm[pair_index], 0.0));
182 PetscInt payloads = 0;
190 "Statistics window '%s' block %d: %d accumulator vector(s) over %d point(s).\n",
191 definition->
name, (
int)user->
_this, (
int)payloads, (
int)points);
193 PetscFunctionReturn(0);
202 PetscFunctionBeginUser;
203 if (storage == NULL) PetscFunctionReturn(0);
204 if (storage->
count) PetscCall(VecDestroy(&storage->
count));
205 if (storage->
weight) PetscCall(VecDestroy(&storage->
weight));
207 for (PetscInt field_index = 0; storage->
mean && field_index < storage->
field_count; ++field_index) {
208 if (storage->
mean[field_index]) PetscCall(VecDestroy(&storage->
mean[field_index]));
210 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
211 if (storage->
m2[field_index]) PetscCall(VecDestroy(&storage->
m2[field_index]));
213 for (PetscInt pair_index = 0; storage->
cm && pair_index < storage->
covariance_count; ++pair_index) {
214 if (storage->
cm[pair_index]) PetscCall(VecDestroy(&storage->
cm[pair_index]));
216 if (storage->
mean) PetscCall(PetscFree(storage->
mean));
217 if (storage->
m2) PetscCall(PetscFree(storage->
m2));
218 if (storage->
cm) PetscCall(PetscFree(storage->
cm));
219 PetscCall(PetscMemzero(storage,
sizeof(*storage)));
220 PetscFunctionReturn(0);
232 PetscFunctionBeginUser;
233 for (PetscInt field_index = 0; field_index < definition->
field_count; ++field_index) {
236 PetscFunctionReturn(0);
239 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
240 "Window '%s' requests a covariance over field '%s', which is not in its field list.",
250 PetscFunctionBeginUser;
251 PetscCheck(storage != NULL && count != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
252 "Storage and count output are required.");
256 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
257 if (storage->
m2[field_index]) *count += 1;
259 PetscFunctionReturn(0);
271 PetscInt cursor = index;
273 PetscFunctionBeginUser;
274 PetscCheck(user != NULL && definition != NULL && storage != NULL && payload != NULL,
275 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
276 "Context, definition, storage, and payload output are required.");
278 PetscCheck(index >= 0 && index < total, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
279 "Payload index %" PetscInt_FMT
" is outside [0, %" PetscInt_FMT
").", index, total);
280 PetscCall(PetscMemzero(payload,
sizeof(*payload)));
286 static const char *
const occupancy_name[3] = {
"count",
"weight",
"weight_sq"};
289 occupancy[0] = storage->
count;
290 occupancy[1] = storage->
weight;
292 PetscCall(PetscStrncpy(payload->
name, occupancy_name[cursor],
sizeof(payload->
name)));
293 payload->
vec = occupancy[cursor];
295 payload->
role =
"occupancy";
297 PetscFunctionReturn(0);
301 if (cursor < storage->field_count) {
305 PetscCall(PetscSNPrintf(payload->
name,
sizeof(payload->
name),
"%s_mean",
307 payload->
vec = storage->
mean[cursor];
309 payload->
role =
"mean";
311 PetscFunctionReturn(0);
316 PetscInt product_count = 0;
319 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
320 if (storage->
m2[field_index]) ++product_count;
322 if (cursor < product_count) {
323 for (PetscInt field_index = 0; field_index < storage->
field_count; ++field_index) {
326 if (!storage->
m2[field_index])
continue;
327 if (seen++ != cursor)
continue;
329 PetscCall(PetscSNPrintf(payload->
name,
sizeof(payload->
name),
"%s_m2",
331 payload->
vec = storage->
m2[field_index];
333 payload->
role =
"second_moment";
335 PetscFunctionReturn(0);
338 cursor -= product_count;
345 PetscCheck(cursor >= 0 && cursor < storage->covariance_count, PETSC_COMM_SELF, PETSC_ERR_PLIB,
346 "Payload index %" PetscInt_FMT
" fell through the storage enumeration.", index);
349 PetscCall(PetscSNPrintf(payload->
name,
sizeof(payload->
name),
"%s_%s_cm",
351 payload->
vec = storage->
cm[cursor];
353 payload->
role =
"co_moment";
356 PetscFunctionReturn(0);
371 "mean",
"reynolds_stress",
"rms",
"tke",
"flux"
381 char *cursor = buffer;
383 PetscFunctionBeginUser;
385 PetscCheck(outputs != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Output list is required.");
386 PetscCall(PetscStrncpy(buffer, outputs,
sizeof(buffer)));
388 while (cursor && *cursor) {
389 char *comma = strchr(cursor,
',');
390 PetscBool matched = PETSC_FALSE;
392 if (comma) *comma =
'\0';
394 if (cursor[0] !=
'\0') {
397 wanted[k] = PETSC_TRUE;
398 matched = PETSC_TRUE;
401 PetscCheck(matched, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
402 "Unknown field-statistics output '%s'. Available outputs are "
403 "mean, reynolds_stress, rms, tke, and flux.", cursor);
405 cursor = comma ? comma + 1 : NULL;
407 PetscFunctionReturn(0);
420 PetscFunctionBeginUser;
428 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
430 PetscInt components = 0;
432 if (!storage->
m2[field_index])
continue;
443 for (PetscInt field_index = 0; storage->
m2 && field_index < storage->
field_count; ++field_index) {
446 if (!storage->
m2[field_index])
continue;
448 if (descriptor->
dof == 3) *count += 1;
455 PetscFunctionReturn(0);
464 const char *outputs, PetscInt *count)
468 PetscFunctionBeginUser;
469 PetscCheck(definition != NULL && storage != NULL && count != NULL,
470 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Definition, storage, and count are required.");
476 if (!wanted[k])
continue;
480 PetscFunctionReturn(0);
492 PetscFunctionBeginUser;
493 if (variance >= 0.0) {
494 *result = PetscSqrtReal(variance);
495 PetscFunctionReturn(0);
498 "Derived variance for '%s' is %g, which is too negative to be floating-point "
499 "cancellation; the accumulated state is inconsistent.", label, (
double)variance);
501 PetscFunctionReturn(0);
512 PetscInt index,
DerivedKind *kind, PetscInt *offset)
514 PetscFunctionBeginUser;
518 if (!wanted[k])
continue;
520 if (index < extent) {
523 PetscFunctionReturn(0);
527 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
528 "Derived index is past the end of the requested output set.");
537 PetscInt index, Vec scalar_target, Vec vector_target,
543 PetscReal ***weight_arr = NULL, ***weight_sq_arr = NULL, ***count_arr = NULL;
544 PetscScalar ****source = NULL, ****target = NULL;
547 Vec source_vec = NULL;
548 PetscInt offset = 0, slot = 0, member = 0;
551 PetscInt source_components = 0;
553 PetscFunctionBeginUser;
554 PetscCheck(user != NULL && definition != NULL && storage != NULL && field != NULL,
555 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
556 "Context, definition, storage, and output are required.");
557 PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
558 "Derived index %" PetscInt_FMT
" is negative.", index);
559 PetscCall(PetscMemzero(field,
sizeof(*field)));
570 source_vec = storage->
mean[slot];
572 source_components = descriptor->
dof;
573 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_mean",
577 for (slot = 0; slot < storage->
field_count; ++slot) {
578 if (!storage->
m2[slot])
continue;
580 if (descriptor->
dof != 3)
continue;
581 if (offset-- == 0)
break;
583 source_vec = storage->
m2[slot];
586 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_tke",
599 source_vec = storage->
cm[slot];
600 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_%s_flux",
607 for (slot = 0; slot < storage->
field_count; ++slot) {
610 if (!storage->
m2[slot])
continue;
614 if (offset < extent) { member = offset;
break; }
617 source_vec = storage->
m2[slot];
621 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_rms%s",
624 }
else if (descriptor->
dof == 1) {
625 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_variance",
631 PetscCall(PetscSNPrintf(field->
name,
sizeof(field->
name),
"%s_%s_R_%s",
641 Vec destination = (field->
components == 1) ? scalar_target : vector_target;
642 DM destination_dm = NULL;
644 PetscCheck(destination != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
645 "Derived field '%s' needs a %d-component destination.",
648 PetscCall(VecZeroEntries(destination));
650 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
weight, &weight_arr));
651 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
weight_sq, &weight_sq_arr));
652 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
count, &count_arr));
653 PetscCall(DMDAVecGetArrayDOFRead(source_dm, source_vec, &source));
654 PetscCall(DMDAVecGetArrayDOF(destination_dm, destination, &target));
656 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
657 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
658 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
663 if (weight_arr[k][j][i] <= 0.0)
continue;
664 pair.
count = count_arr[k][j][i];
665 pair.
weight = weight_arr[k][j][i];
671 for (PetscInt c = 0; c < field->
components; ++c) {
672 target[k][j][i][c] = source[k][j][i][c];
677 PetscReal trace = 0.0;
679 for (PetscInt c = 0; c < 3; ++c) {
683 target[k][j][i][0] = 0.5 * trace;
685 PetscReal deviation = 0.0;
687 pair.
cm = source[k][j][i][(descriptor->
dof == 1)
690 field->
name, &deviation));
691 target[k][j][i][0] = deviation;
693 for (PetscInt c = 0; c < field->
components; ++c) {
694 pair.
cm = source[k][j][i][c];
698 pair.
cm = source[k][j][i][member];
705 PetscCall(DMDAVecRestoreArrayDOF(destination_dm, destination, &target));
706 PetscCall(DMDAVecRestoreArrayDOFRead(source_dm, source_vec, &source));
707 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
count, &count_arr));
708 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
weight_sq, &weight_sq_arr));
709 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
weight, &weight_arr));
711 PetscFunctionReturn(0);
723 const PetscReal ***values = NULL;
724 PetscReal ***weight_arr = NULL;
725 PetscReal local_sum = 0.0;
726 PetscReal local_count = 0.0;
727 PetscReal totals[2] = {0.0, 0.0};
728 PetscReal reduced[2] = {0.0, 0.0};
730 PetscFunctionBeginUser;
731 PetscCheck(user != NULL && definition != NULL && storage != NULL && field != NULL && mean != NULL,
732 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
733 "Context, definition, storage, field, and output are required.");
735 if (definition->
field_count == 0) PetscFunctionReturn(0);
739 PetscCall(DMDAVecGetArrayRead(user->
da, field, &values));
740 PetscCall(DMDAVecGetArray(user->
da, storage->
weight, &weight_arr));
741 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
742 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
743 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
746 if (weight_arr[k][j][i] <= 0.0)
continue;
747 local_sum += values[k][j][i];
752 PetscCall(DMDAVecRestoreArray(user->
da, storage->
weight, &weight_arr));
753 PetscCall(DMDAVecRestoreArrayRead(user->
da, field, &values));
755 totals[0] = local_sum;
756 totals[1] = local_count;
757 PetscCallMPI(MPI_Allreduce(totals, reduced, 2, MPIU_REAL, MPIU_SUM, PETSC_COMM_WORLD));
758 if (reduced[1] > 0.0) *mean = reduced[0] / reduced[1];
759 PetscFunctionReturn(0);
768 PetscReal *minimum, PetscReal *maximum)
771 PetscReal ***nvert = NULL;
772 PetscReal ***count_arr = NULL;
773 PetscReal local_min = PETSC_MAX_REAL;
774 PetscReal local_max = 0.0;
775 PetscReal reduced_min = 0.0, reduced_max = 0.0;
777 PetscFunctionBeginUser;
778 PetscCheck(user != NULL && definition != NULL && storage != NULL &&
779 minimum != NULL && maximum != NULL,
780 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Context, definition, storage, and outputs are required.");
783 if (definition->
field_count == 0 || sample_count <= 0) PetscFunctionReturn(0);
787 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Nvert, &nvert));
788 PetscCall(DMDAVecGetArrayRead(user->
da, storage->
count, &count_arr));
789 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
790 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
791 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
795 const PetscReal fraction = count_arr[k][j][i] / (PetscReal)sample_count;
797 local_min = PetscMin(local_min, fraction);
798 local_max = PetscMax(local_max, fraction);
802 PetscCall(DMDAVecRestoreArrayRead(user->
da, storage->
count, &count_arr));
803 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Nvert, &nvert));
807 PetscCallMPI(MPI_Allreduce(&local_min, &reduced_min, 1, MPIU_REAL, MPIU_MIN, PETSC_COMM_WORLD));
808 PetscCallMPI(MPI_Allreduce(&local_max, &reduced_max, 1, MPIU_REAL, MPIU_MAX, PETSC_COMM_WORLD));
809 *minimum = (reduced_min == PETSC_MAX_REAL) ? 1.0 : reduced_min;
810 *maximum = reduced_max;
811 PetscFunctionReturn(0);
822 PetscReal ***nvert = NULL;
823 PetscReal ***count_arr = NULL, ***weight_arr = NULL, ***weight_sq_arr = NULL;
825 PetscFunctionBeginUser;
826 PetscCheck(user != NULL && definition != NULL && storage != NULL,
827 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"Context, definition, and storage are required.");
828 PetscCheck(weight > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
829 "Accepted states carry a positive weight, got %g.", (
double)weight);
830 if (definition->
field_count == 0) PetscFunctionReturn(0);
837 PetscCall(DMDAVecGetArrayRead(user->
da, user->
Nvert, &nvert));
838 PetscCall(DMDAVecGetArray(user->
da, storage->
count, &count_arr));
839 PetscCall(DMDAVecGetArray(user->
da, storage->
weight, &weight_arr));
840 PetscCall(DMDAVecGetArray(user->
da, storage->
weight_sq, &weight_sq_arr));
845 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
846 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
847 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
849 count_arr[k][j][i] += 1.0;
850 weight_arr[k][j][i] += weight;
851 weight_sq_arr[k][j][i] += weight * weight;
861 PetscScalar ****src_a = NULL, ****mean_a = NULL;
862 PetscScalar ****src_b = NULL, ****mean_b = NULL;
863 PetscScalar ****co_moment = NULL;
865 PetscInt slot_a = 0, slot_b = 0, dof_a = 0, dof_b = 0, components = 0;
878 PetscCall(DMDAVecGetArrayDOFRead(view_a.
dm, view_a.
global_vec, &src_a));
879 PetscCall(DMDAVecGetArrayDOFRead(view_a.
dm, storage->
mean[slot_a], &mean_a));
880 PetscCall(DMDAVecGetArrayDOFRead(view_b.
dm, view_b.
global_vec, &src_b));
881 PetscCall(DMDAVecGetArrayDOFRead(view_b.
dm, storage->
mean[slot_b], &mean_b));
882 PetscCall(DMDAVecGetArrayDOF(pair_dm, storage->
cm[pair], &co_moment));
884 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
885 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
886 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
888 for (PetscInt c = 0; c < components; ++c) {
892 const PetscInt component_a = (dof_a == 3) ? c : 0;
893 const PetscInt component_b = (dof_b == 3) ? c : 0;
896 state.
count = count_arr[k][j][i] - 1.0;
897 state.
weight = weight_arr[k][j][i] - weight;
898 state.
weight_sq = weight_sq_arr[k][j][i] - weight * weight;
899 state.
mean_x = mean_a[k][j][i][component_a];
900 state.
mean_y = mean_b[k][j][i][component_b];
901 state.
cm = co_moment[k][j][i][c];
903 src_a[k][j][i][component_a],
904 src_b[k][j][i][component_b], weight));
905 co_moment[k][j][i][c] = state.
cm;
911 PetscCall(DMDAVecRestoreArrayDOF(pair_dm, storage->
cm[pair], &co_moment));
912 PetscCall(DMDAVecRestoreArrayDOFRead(view_b.
dm, storage->
mean[slot_b], &mean_b));
913 PetscCall(DMDAVecRestoreArrayDOFRead(view_b.
dm, view_b.
global_vec, &src_b));
914 PetscCall(DMDAVecRestoreArrayDOFRead(view_a.
dm, storage->
mean[slot_a], &mean_a));
915 PetscCall(DMDAVecRestoreArrayDOFRead(view_a.
dm, view_a.
global_vec, &src_a));
922 for (PetscInt field_index = 0; field_index < definition->
field_count; ++field_index) {
924 PetscScalar ****src = NULL, ****mean = NULL, ****product = NULL;
925 DM product_dm = NULL;
926 PetscInt dof = 0, components = 0;
931 PetscCall(DMDAVecGetArrayDOFRead(view.
dm, view.
global_vec, &src));
932 PetscCall(DMDAVecGetArrayDOF(view.
dm, storage->
mean[field_index], &mean));
936 PetscCall(DMDAVecGetArrayDOF(product_dm, storage->
m2[field_index], &product));
939 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k) {
940 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j) {
941 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) {
942 PetscReal prior_weight = 0.0;
943 PetscReal prior_weight_sq = 0.0;
944 PetscReal prior_count = 0.0;
948 prior_weight = weight_arr[k][j][i] - weight;
949 prior_weight_sq = weight_sq_arr[k][j][i] - weight * weight;
950 prior_count = count_arr[k][j][i] - 1.0;
954 for (PetscInt c = 0; c < components; ++c) {
959 state.
count = prior_count;
960 state.
weight = prior_weight;
962 state.
mean_x = mean[k][j][i][a];
963 state.
mean_y = mean[k][j][i][b];
964 state.
cm = product[k][j][i][c];
966 src[k][j][i][b], weight));
967 product[k][j][i][c] = state.
cm;
970 for (PetscInt c = 0; c < dof; ++c) {
973 moment.
count = prior_count;
974 moment.
weight = prior_weight;
976 moment.
mean = mean[k][j][i][c];
979 mean[k][j][i][c] = moment.
mean;
985 if (second) PetscCall(DMDAVecRestoreArrayDOF(product_dm, storage->
m2[field_index], &product));
986 PetscCall(DMDAVecRestoreArrayDOF(view.
dm, storage->
mean[field_index], &mean));
987 PetscCall(DMDAVecRestoreArrayDOFRead(view.
dm, view.
global_vec, &src));
990 PetscCall(DMDAVecRestoreArray(user->
da, storage->
weight_sq, &weight_sq_arr));
991 PetscCall(DMDAVecRestoreArray(user->
da, storage->
weight, &weight_arr));
992 PetscCall(DMDAVecRestoreArray(user->
da, storage->
count, &count_arr));
993 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
Nvert, &nvert));
994 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.
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 LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
@ LOG_DEBUG
Detailed debugging information.
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 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.
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.
User-defined context containing data specific to a single computational grid level.