26 memset(&d, 0,
sizeof(d));
38static PetscErrorCode
SetUniform(
UserCtx *user, PetscReal x, PetscReal y, PetscReal z, PetscReal p)
41 PetscReal ***pp = NULL;
42 const DMDALocalInfo info = user->
info;
44 PetscFunctionBeginUser;
45 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &ucat));
46 PetscCall(DMDAVecGetArray(user->
da, user->
P, &pp));
47 for (PetscInt k = info.zs; k < info.zs + info.zm; ++k)
48 for (PetscInt j = info.ys; j < info.ys + info.ym; ++j)
49 for (PetscInt i = info.xs; i < info.xs + info.xm; ++i) {
50 ucat[k][j][i].
x = x; ucat[k][j][i].
y = y; ucat[k][j][i].
z = z;
53 PetscCall(DMDAVecRestoreArray(user->
da, user->
P, &pp));
54 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &ucat));
55 PetscFunctionReturn(0);
59static PetscErrorCode
ReadScalarAt(
UserCtx *user, Vec v, PetscInt i, PetscInt j, PetscInt k, PetscReal *out)
61 PetscReal ***a = NULL;
62 PetscFunctionBeginUser;
63 PetscCall(DMDAVecGetArrayRead(user->
da, v, &a));
65 PetscCall(DMDAVecRestoreArrayRead(user->
da, v, &a));
66 PetscFunctionReturn(0);
71 PetscInt i, PetscInt j, PetscInt k, PetscReal *out)
73 PetscScalar ****a = NULL;
75 PetscFunctionBeginUser;
77 PetscCall(DMDAVecGetArrayDOFRead(dm, v, &a));
78 *out = a[k][j][i][component];
79 PetscCall(DMDAVecRestoreArrayDOFRead(dm, v, &a));
80 PetscFunctionReturn(0);
87 PetscErrorCode bad = 0;
89 PetscFunctionBeginUser;
93 PetscCall(
PicurvAssertIntEqual(6, n,
"a three-vector self-product has six symmetric components"));
99 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
101 PetscCall(PetscPopErrorHandler());
103 "vector-vector cross products are an explicit non-goal"));
104 PetscFunctionReturn(0);
116 PetscFunctionBeginUser;
124 PetscCall(VecGetBlockSize(storage.
m2[0], &bs));
126 PetscCall(VecGetBlockSize(storage.
m2[1], &bs));
130 PetscCall(VecGetBlockSize(storage.
mean[0], &bs));
132 PetscCall(VecGetBlockSize(storage.
mean[1], &bs));
137 PetscCall(
PicurvAssertBool((PetscBool)(storage.
mean == NULL),
"destroy releases the mean array"));
142 PetscFunctionReturn(0);
152 const PetscReal series[3][3] = {{1.0, 2.0, 3.0}, {3.0, 6.0, 5.0}, {5.0, 4.0, 7.0}};
153 const PetscReal scalars[3] = {1.0, 2.0, 6.0};
154 const PetscReal expected_product[6] = {8.0, 4.0, 8.0, 8.0, 4.0, 8.0};
155 const char *labels[6] = {
"xx",
"xy",
"xz",
"yy",
"yz",
"zz"};
156 Cmpnts ***mean_vec = NULL;
157 PetscReal value = 0.0;
160 PetscFunctionBeginUser;
162 PetscCall(VecSet(user->
Nvert, 0.0));
165 for (PetscInt s = 0; s < 3; ++s) {
166 PetscCall(
SetUniform(user, series[s][0], series[s][1], series[s][2], scalars[s]));
179 PetscCall(DMDAVecGetArrayRead(user->
fda, storage.
mean[0], &mean_vec));
183 PetscCall(DMDAVecRestoreArrayRead(user->
fda, storage.
mean[0], &mean_vec));
186 for (PetscInt c = 0; c < 6; ++c) {
188 PetscCall(PetscSNPrintf(context,
sizeof(context),
"Ucat centered product %s", labels[c]));
200 PetscFunctionReturn(0);
217 PetscReal ***nvert = NULL;
218 PetscReal lowest = 0.0, highest = 0.0;
220 PetscFunctionBeginUser;
222 PetscCall(VecSet(user->
Nvert, 0.0));
224 PetscCall(
SetUniform(user, 1.0, 2.0, 3.0, 7.0));
228 PetscCall(
PicurvAssertRealNear(1.0, lowest, 1.0e-12,
"an unsampled window reports full coverage"));
229 PetscCall(
PicurvAssertRealNear(0.0, highest, 1.0e-12,
"an unsampled window reports no maximum"));
236 PetscCall(
PicurvAssertRealNear(1.0, highest, 1.0e-12,
"a clear domain has no over-counted point"));
239 PetscCall(DMDAVecGetArray(user->
da, user->
Nvert, &nvert));
240 nvert[3][3][3] = 1.0;
241 PetscCall(DMDAVecRestoreArray(user->
da, user->
Nvert, &nvert));
245 "a point blanked for one state trails the rest"));
246 PetscCall(
PicurvAssertRealNear(1.0, highest, 1.0e-12,
"unobstructed points stay fully covered"));
250 PetscFunctionReturn(0);
262 PetscReal ***nvert = NULL;
263 PetscReal lowest = 1.0, highest = 0.0;
265 PetscFunctionBeginUser;
267 PetscCall(VecSet(user->
Nvert, 0.0));
268 PetscCall(DMDAVecGetArray(user->
da, user->
Nvert, &nvert));
269 nvert[3][3][3] = 1.0;
270 PetscCall(DMDAVecRestoreArray(user->
da, user->
Nvert, &nvert));
273 PetscCall(
SetUniform(user, 1.0, 2.0, 3.0, 7.0));
279 "a permanently blanked point reports zero coverage"));
284 PetscFunctionReturn(0);
294 const PetscReal series[3][3] = {{1.0, 2.0, 3.0}, {3.0, 6.0, 5.0}, {5.0, 4.0, 7.0}};
295 const PetscReal scalars[3] = {1.0, 2.0, 6.0};
299 const PetscReal expected[3] = {10.0, 2.0, 10.0};
300 const char *labels[3] = {
"x",
"y",
"z"};
301 PetscReal value = 0.0;
304 PetscFunctionBeginUser;
310 PetscCall(VecSet(user->
Nvert, 0.0));
314 PetscCall(VecGetBlockSize(storage.
cm[0], &bs));
318 for (PetscInt s = 0; s < 3; ++s) {
319 PetscCall(
SetUniform(user, series[s][0], series[s][1], series[s][2], scalars[s]));
323 for (PetscInt c = 0; c < 3; ++c) {
325 PetscCall(PetscSNPrintf(context,
sizeof(context),
"Ucat-P co-moment %s", labels[c]));
331 PetscCall(
PicurvAssertRealNear(3.0, value, 1.0e-12,
"P mean is unaffected by the covariance pass"));
333 PetscCall(
PicurvAssertRealNear(8.0, value, 1.0e-11,
"Ucat xx product is unaffected by the covariance pass"));
337 PetscFunctionReturn(0);
347 const PetscReal scalars[3] = {1.0, 2.0, 6.0};
348 PetscReal co_moment = 0.0;
349 PetscReal second_moment = 0.0;
351 PetscFunctionBeginUser;
360 PetscCall(VecSet(user->
Nvert, 0.0));
363 for (PetscInt s = 0; s < 3; ++s) {
364 PetscCall(
SetUniform(user, 0.0, 0.0, 0.0, scalars[s]));
368 PetscCall(
ReadScalarAt(user, storage.
cm[0], 2, 2, 2, &co_moment));
369 PetscCall(
ReadScalarAt(user, storage.
m2[1], 2, 2, 2, &second_moment));
370 PetscCall(
PicurvAssertRealNear(14.0, co_moment, 1.0e-11,
"P self-covariance equals its centered sum"));
372 "self-covariance and second moment agree bit for bit"));
376 PetscFunctionReturn(0);
386 PetscErrorCode bad = 0;
388 PetscFunctionBeginUser;
396 PetscCall(VecSet(user->
Nvert, 0.0));
398 PetscCall(
SetUniform(user, 1.0, 2.0, 3.0, 4.0));
400 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
402 PetscCall(PetscPopErrorHandler());
404 "a covariance member outside the field list is rejected"));
408 PetscFunctionReturn(0);
425 const PetscReal series[3][3] = {{1.0, 2.0, 3.0}, {3.0, 6.0, 5.0}, {5.0, 4.0, 7.0}};
426 const PetscReal scalars[3] = {1.0, 2.0, 6.0};
427 Vec scalar_target = NULL, vector_target = NULL;
429 PetscReal value = 0.0;
431 PetscFunctionBeginUser;
437 PetscCall(VecSet(user->
Nvert, 0.0));
439 for (PetscInt s = 0; s < 3; ++s) {
440 PetscCall(
SetUniform(user, series[s][0], series[s][1], series[s][2], scalars[s]));
443 PetscCall(DMCreateGlobalVector(user->
da, &scalar_target));
444 PetscCall(DMCreateGlobalVector(user->
fda, &vector_target));
451 for (PetscInt index = 0; index < count; ++index) {
453 PetscBool is_tke = PETSC_FALSE, is_rxx = PETSC_FALSE, is_rmsx = PETSC_FALSE;
454 PetscBool is_flux = PETSC_FALSE, is_pvar = PETSC_FALSE;
457 index, scalar_target, vector_target, &field));
458 PetscCall(PetscStrcmp(field.
name,
"acc_Ucat_tke", &is_tke));
459 PetscCall(PetscStrcmp(field.
name,
"acc_Ucat_R_xx", &is_rxx));
460 PetscCall(PetscStrcmp(field.
name,
"acc_Ucat_rmsx", &is_rmsx));
461 PetscCall(PetscStrcmp(field.
name,
"acc_Ucat_P_flux", &is_flux));
462 PetscCall(PetscStrcmp(field.
name,
"acc_P_variance", &is_pvar));
465 PetscCall(
ReadScalarAt(user, scalar_target, 2, 2, 2, &value));
467 }
else if (is_rmsx) {
468 PetscCall(
ReadScalarAt(user, scalar_target, 2, 2, 2, &value));
470 "RMS is the root of the normal stress"));
472 PetscCall(
ReadScalarAt(user, scalar_target, 2, 2, 2, &value));
474 }
else if (is_pvar) {
475 PetscCall(
ReadScalarAt(user, scalar_target, 2, 2, 2, &value));
477 }
else if (is_flux) {
480 PetscCall(DMDAVecGetArrayRead(user->
fda, vector_target, &flux));
484 PetscCall(DMDAVecRestoreArrayRead(user->
fda, vector_target, &flux));
495 PetscReal ***nvert = NULL;
497 PetscCall(DMDAVecGetArray(user->
da, user->
Nvert, &nvert));
498 nvert[3][3][3] = 1.0;
499 PetscCall(DMDAVecRestoreArray(user->
da, user->
Nvert, &nvert));
502 PetscCall(
SetUniform(user, 1.0, 2.0, 3.0, 4.0));
504 PetscCall(
PicurvWindowDerive(user, &d, &storage,
"tke", 0, scalar_target, vector_target, &field));
505 PetscCall(
ReadScalarAt(user, scalar_target, 3, 3, 3, &value));
507 "a never-sampled point derives to zero, not a division"));
512 PetscErrorCode bad = 0;
514 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
516 PetscCall(PetscPopErrorHandler());
520 PetscCall(VecDestroy(&vector_target));
521 PetscCall(VecDestroy(&scalar_target));
524 PetscFunctionReturn(0);
542 PetscReal ***nvert = NULL;
543 PetscReal mean = 0.0;
544 PetscReal whole_vector_mean = 0.0;
546 PetscInt vector_size = 0;
547 PetscInt targeted = 0;
549 PetscFunctionBeginUser;
551 PetscCall(VecSet(user->
Nvert, 0.0));
553 PetscCall(
SetUniform(user, 1.0, 2.0, 3.0, 4.0));
562 PetscReal ***values = NULL;
564 PetscCall(DMDAVecGetArray(user->
da, user->
PostScalar, &values));
565 for (PetscInt k = plan.
start[2]; k < plan.
end[2]; ++k)
566 for (PetscInt j = plan.
start[1]; j < plan.
end[1]; ++j)
567 for (PetscInt i = plan.
start[0]; i < plan.
end[0]; ++i) values[k][j][i] = 1.0;
568 PetscCall(DMDAVecRestoreArray(user->
da, user->
PostScalar, &values));
573 "the mean over sampled points ignores untargeted entries"));
578 PetscCall(VecGetSize(user->
PostScalar, &vector_size));
579 whole_vector_mean = sum / (PetscReal)vector_size;
581 "the vector is larger than the targeted domain"));
583 "a whole-vector average would understate the result"));
587 PetscCall(DMDAVecGetArray(user->
da, user->
Nvert, &nvert));
588 nvert[3][3][3] = 1.0;
589 PetscCall(DMDAVecRestoreArray(user->
da, user->
Nvert, &nvert));
595 "a never-sampled point is excluded from the average"));
599 PetscFunctionReturn(0);
611 const char *expected[8] = {
612 "count",
"weight",
"weight_sq",
613 "Ucat_mean",
"P_mean",
617 const PetscInt expected_components[8] = {1, 1, 1, 3, 1, 6, 1, 3};
619 PetscErrorCode bad = 0;
621 PetscFunctionBeginUser;
631 for (PetscInt index = 0; index < count; ++index) {
633 PetscBool matches = PETSC_FALSE;
634 PetscInt block_size = 0;
638 PetscCall(PetscStrcmp(payload.
name, expected[index], &matches));
639 PetscCall(PetscSNPrintf(context,
sizeof(context),
"payload %d is named '%s', got '%s'",
640 (
int)index, expected[index], payload.
name));
642 PetscCall(
PicurvAssertBool((PetscBool)(payload.
vec != NULL),
"an enumerated payload has a vector"));
643 PetscCall(
PicurvAssertBool((PetscBool)(payload.
role != NULL),
"an enumerated payload has a role"));
647 PetscCall(VecGetBlockSize(payload.
vec, &block_size));
648 PetscCall(PetscSNPrintf(context,
sizeof(context),
"payload '%s' declares %d components",
649 payload.
name, (
int)expected_components[index]));
652 "the declared component count matches the vector"));
667 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
669 PetscCall(PetscPopErrorHandler());
670 PetscCall(
PicurvAssertBool((PetscBool)(bad != 0),
"an out-of-range payload index is rejected"));
674 PetscFunctionReturn(0);
684 PetscReal value = 0.0;
686 PetscFunctionBeginUser;
688 PetscCall(VecSet(user->
Nvert, 0.0));
692 PetscCall(
SetUniform(user, 0.0, 0.0, 0.0, 1.0));
694 PetscCall(
SetUniform(user, 0.0, 0.0, 0.0, 3.0));
708 PetscFunctionReturn(0);
718 PetscReal ***nvert = NULL;
719 PetscReal value = 0.0;
721 PetscFunctionBeginUser;
723 PetscCall(VecSet(user->
Nvert, 0.0));
725 PetscCall(DMDAVecGetArray(user->
da, user->
Nvert, &nvert));
726 nvert[3][3][3] = 1.0;
727 PetscCall(DMDAVecRestoreArray(user->
da, user->
Nvert, &nvert));
730 PetscCall(
SetUniform(user, 1.0, 2.0, 3.0, 7.0));
741 PetscCall(
PicurvAssertRealNear(0.0, value, 1.0e-12,
"a blanked point keeps an untouched mean"));
745 PetscFunctionReturn(0);
755 PetscReal value = 0.0;
757 PetscFunctionBeginUser;
759 PetscCall(VecSet(user->
Nvert, 0.0));
762 for (PetscInt s = 0; s < 5; ++s) {
763 PetscCall(
SetUniform(user, 2.5, -1.5, 4.0, 9.0));
766 for (PetscInt c = 0; c < 6; ++c) {
769 "a constant field gives bitwise-zero products"));
772 PetscCall(
PicurvAssertRealNear(9.0, value, 1.0e-12,
"a constant field keeps its value as the mean"));
776 PetscFunctionReturn(0);
793 PetscReal value = 0.0;
794 const PetscReal dt = 0.5;
796 PetscFunctionBeginUser;
798 PetscCall(VecSet(user->
Nvert, 0.0));
812 for (PetscInt step = 0; step <= 4; ++step) {
813 PetscCall(
SetUniform(user, 1.0, 2.0, 3.0, (PetscReal)(step + 1)));
822 PetscCall(
PicurvAssertRealNear(2.0, value, 1.0e-12,
"per-point count matches the accepted samples"));
824 PetscCall(
PicurvAssertRealNear(2.0, value, 1.0e-12,
"per-point weight matches the accepted weights"));
828 PetscCall(
PicurvAssertRealNear(4.0, value, 1.0e-12,
"only the scheduled samples contribute to the mean"));
830 PetscCall(
PicurvAssertRealNear(2.0, value, 1.0e-11,
"second moment reflects only the scheduled samples"));
842 PetscFunctionReturn(0);
869 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv statistics accumulator tests");
870 if (ierr)
return (
int)ierr;
871 ierr =
PicurvRunTests(
"unit-statistics-accumulator", cases,
sizeof(cases) /
sizeof(cases[0]));
872 if (ierr) { PetscFinalize();
return (
int)ierr; }
873 ierr = PetscFinalize();
Authoritative identities and storage metadata for persistent Eulerian fields.
Per-window PETSc accumulator storage and pointwise application.
Vec weight
Per-point valid weight.
PetscInt components
Degrees of freedom the vector carries.
PetscErrorCode PicurvProductComponentCount(PetscInt dof, PetscInt *count)
Reports how many symmetric product components a field's second moment needs.
Vec weight_sq
Per-point squared-weight sum.
PetscInt field_count
Fields accumulated.
char name[96]
Output field name, window qualified.
PetscErrorCode PicurvWindowDerive(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, const char *outputs, PetscInt index, Vec scalar_target, Vec vector_target, PicurvDerivedField *field)
Derives one output field from centered accumulator state.
Vec * mean
One per field, matching that field's layout.
Vec vec
Borrowed accumulator vector; never owned by the caller.
PetscErrorCode PicurvWindowDerivedCount(const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, const char *outputs, PetscInt *count)
Reports how many derived fields a requested output set produces.
PetscErrorCode PicurvWindowStorageCreate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage)
Allocates the accumulator state one window owns on one block.
PetscErrorCode PicurvCovarianceComponentCount(PetscInt dof_a, PetscInt dof_b, PetscInt *count)
Reports how many components a covariance between two fields needs.
PetscErrorCode PicurvWindowStoragePayload(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt index, PicurvStatisticsPayload *payload)
Resolves one enumerated payload of a window's storage.
Vec * m2
One per field; NULL when no second moment was requested.
const char * role
Inventory role: occupancy, mean, second_moment, co_moment.
PetscErrorCode PicurvWindowValidFractionRange(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, PetscInt sample_count, PetscReal *minimum, PetscReal *maximum)
Reports the range of per-point valid fraction across a window's domain.
PetscErrorCode PicurvStatisticsComponentDM(UserCtx *user, PetscInt components, DM *dm)
Resolves the DM carrying a given number of accumulator components.
PetscErrorCode PicurvWindowSpatialMean(UserCtx *user, const PicurvWindowDefinition *definition, const PicurvWindowStorage *storage, Vec field, PetscReal *mean)
Reports the spatial mean of a derived field over the points a window sampled.
Vec count
Per-point accepted sample count.
char name[96]
File basename, no extension.
PetscErrorCode PicurvWindowAccumulate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage, PetscReal weight)
Applies one accepted completed state to a window's accumulators.
PetscErrorCode PicurvWindowStorageDestroy(PicurvWindowStorage *storage)
Releases accumulator state previously created for one window.
PetscErrorCode PicurvWindowStoragePayloadCount(const PicurvWindowStorage *storage, PetscInt *count)
Reports how many checkpointable vectors one window's storage holds.
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.
Spatial target resolution for the field-statistics pipeline.
@ 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.
Window lifecycle, scheduling, and weighting for the field-statistics pipeline.
PetscInt first
First member; must also appear in the field list.
PicurvWindowFieldRequest fields[16]
PetscErrorCode FieldStatisticsUpdateWindows(struct SimCtx *simCtx, PetscInt step, PetscReal time)
Offers one completed state to every configured window.
PicurvCadenceKind cadence_kind
PetscInt step_cadence
Used when cadence_kind is step; must be positive.
#define PICURV_WINDOW_NAME_LENGTH
Maximum stored length of a window name, including the terminator.
PetscErrorCode PicurvWindowInit(PicurvWindow *window, const PicurvWindowDefinition *definition)
Validates a definition and initializes a window to the pending state.
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.
@ PICURV_WEIGHTING_PHYSICAL_TIME
Weight is the represented interval.
@ PICURV_WEIGHTING_SAMPLE
Equal weight per accepted state.
@ PICURV_CADENCE_STEP
Every n completed steps from activation.
PicurvWeighting weighting
Runtime state of one window.
The scientifically immutable definition of one window.
static PetscErrorCode TestCovarianceAccumulation(void)
A vector-scalar covariance reproduces its analytically known components.
static PetscErrorCode ReadComponentAt(UserCtx *user, Vec v, PetscInt components, PetscInt component, PetscInt i, PetscInt j, PetscInt k, PetscReal *out)
Reads one component of a multi-component accumulator vector at an interior point.
static PetscErrorCode TestWeightedAccumulation(void)
Unequal weights reproduce the weighted result the kernels define.
static PetscErrorCode TestStorageShape(void)
Storage allocates one mean per field and the right number of product components.
static PetscErrorCode SetUniform(UserCtx *user, PetscReal x, PetscReal y, PetscReal z, PetscReal p)
Sets Ucat to a uniform vector and P to a uniform scalar.
static PetscErrorCode TestValidFractionRange(void)
The valid-fraction range reports mask coverage, including a never-valid point.
int main(int argc, char **argv)
Entry point for the accumulator suite.
static PetscErrorCode TestValidFractionDetectsNeverValidPoint(void)
A point blanked from the start is reported as never valid.
static PetscErrorCode TestRunloopDriverAppliesScheduledStates(void)
The runloop entry point applies exactly the states the schedule accepts.
static PetscErrorCode TestDerivedQuantities(void)
Derived quantities reproduce the analytic values the accumulated state implies.
static PetscErrorCode TestMaskedPointsAreExcluded(void)
Masked points accumulate nothing, and remain distinguishable from unsampled ones.
static PetscErrorCode TestKnownAccumulationAcrossField(void)
Three accepted states reproduce the analytically known moments at every point.
static PetscErrorCode TestScalarSelfCovarianceMatchesSecondMoment(void)
A field's covariance with itself reduces exactly to its own second moment.
static PicurvWindowDefinition AccDefinition(PetscBool want_second)
Builds a definition requesting Ucat and P with second moments.
static PetscErrorCode TestConstantFieldZeroProduct(void)
A constant field yields exactly zero product at every point.
static PetscErrorCode TestSpatialMeanExcludesUnsampledPoints(void)
The spatial mean divides by sampled points, not by the whole vector.
static PetscErrorCode TestPayloadEnumeration(void)
Payload enumeration covers every vector exactly once with stable names.
static PetscErrorCode TestCovarianceRequiresFieldMembership(void)
A covariance member missing from the field list is rejected, not silently skipped.
static PetscErrorCode ReadScalarAt(UserCtx *user, Vec v, PetscInt i, PetscInt j, PetscInt k, PetscReal *out)
Reads one interior point of a scalar accumulator vector.
static PetscErrorCode TestComponentCounts(void)
Component counts follow the documented product shapes.
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
Shared declarations for the PICurv C test fixture and assertion layer.
Named test case descriptor consumed by PicurvRunTests.
PetscInt fieldStatisticsWindowCount
PetscBool fieldStatisticsEnabled
struct PicurvWindow * fieldStatisticsWindows
struct PicurvWindowStorage * fieldStatisticsStorage
A 3D point or vector with PetscScalar components.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.