22 memset(&d, 0,
sizeof(d));
31 PetscReal *total_weight, PetscInt *count)
33 PetscFunctionBeginUser;
34 for (PetscInt s = 0; s <= steps; ++s) {
35 PetscBool accepted = PETSC_FALSE;
36 PetscReal weight = 0.0;
41 PetscFunctionReturn(0);
54 PetscReal sample_weight = 0.0, time_weight = 0.0;
55 PetscInt sample_count = 0, time_count = 0;
56 const PetscReal dt = 0.25;
57 const PetscInt steps = 20;
59 PetscFunctionBeginUser;
68 PetscCall(
RunUniform(&sample_w, steps, dt, &sample_weight, &sample_count));
69 PetscCall(
RunUniform(&time_w, steps, dt, &time_weight, &time_count));
72 PetscCall(
PicurvAssertIntEqual(steps, sample_count,
"sample weighting counts one per interval"));
75 "both weightings must accept exactly the same states"));
76 PetscCall(
PicurvAssertRealNear((PetscReal)steps, sample_weight, 1.0e-12,
"sample total weight"));
77 PetscCall(
PicurvAssertRealNear((PetscReal)steps * dt, time_weight, 1.0e-12,
"time total weight"));
81 "weights differ only by the constant timestep"));
83 "represented time spans the whole run"));
84 PetscFunctionReturn(0);
93 PetscBool accepted = PETSC_FALSE;
94 PetscReal weight = 0.0;
96 PetscFunctionBeginUser;
102 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"states before the start are ignored"));
107 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"the origin state is not a sample"));
113 PetscCall(
PicurvAssertBool(accepted,
"the state after the origin is a sample"));
114 PetscCall(
PicurvAssertRealNear(0.5, weight, 1.0e-12,
"first sample carries the interval from the origin"));
115 PetscFunctionReturn(0);
124 PetscBool accepted = PETSC_FALSE;
125 PetscReal weight = 0.0;
127 PetscFunctionBeginUser;
131 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"the first observed state anchors the moved origin"));
133 "effective start moves to the first observed time"));
136 PetscCall(
PicurvAssertRealNear(0.5, weight, 1.0e-12,
"weight is measured from the moved origin"));
138 "a window never claims time it did not observe"));
139 PetscFunctionReturn(0);
148 const PetscReal times[4] = {0.0, 0.5, 2.0, 2.25};
149 const PetscReal expected[4] = {0.0, 0.5, 1.5, 0.25};
150 PetscBool accepted = PETSC_FALSE;
151 PetscReal weight = 0.0;
153 PetscFunctionBeginUser;
155 for (PetscInt i = 0; i < 4; ++i) {
158 "variable-dt weight equals the elapsed interval"));
162 PetscFunctionReturn(0);
171 PetscBool accepted = PETSC_FALSE;
172 PetscReal weight = 0.0;
173 const PetscReal dt = 0.1;
175 PetscFunctionBeginUser;
177 for (PetscInt s = 0; s <= 6; ++s) {
182 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"off-schedule states are not sampled"));
184 "an off-schedule state changes no scientific state"));
186 "an off-schedule state records no sample"));
192 "strided weights still cover the full elapsed span"));
193 PetscFunctionReturn(0);
202 PetscBool accepted = PETSC_FALSE;
203 PetscReal weight = 0.0;
205 PetscFunctionBeginUser;
215 PetscCall(
PicurvAssertBool(accepted,
"the overshooting state still contributes its clipped interval"));
216 PetscCall(
PicurvAssertRealNear(0.2, weight, 1.0e-12,
"final interval clips to the requested end"));
219 "represented time equals the requested span exactly"));
224 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"a complete window accepts nothing further"));
226 PetscFunctionReturn(0);
235 PetscBool accepted = PETSC_FALSE;
236 PetscReal weight = 0.0;
238 PetscFunctionBeginUser;
245 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"the same step must not be counted twice"));
248 PetscFunctionReturn(0);
262 PetscBool accepted = PETSC_FALSE;
263 PetscReal weight = 0.0;
265 PetscFunctionBeginUser;
266 memset(&d, 0,
sizeof(d));
274 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"origin anchors under time cadence too"));
278 PetscCall(
PicurvAssertBool(accepted,
"the overshooting state is accepted"));
280 "weight is the actual elapsed interval, not the nominal cadence"));
285 PetscCall(
PicurvAssertBool((PetscBool)!accepted,
"the next target has not been reached yet"));
287 PetscCall(
PicurvAssertBool(accepted,
"the state reaching the 0.5 target is accepted"));
288 PetscCall(
PicurvAssertRealNear(0.06, weight, 1.0e-12,
"weight resumes from the last accepted state"));
290 "no represented time is lost or double counted across the overshoot"));
291 PetscFunctionReturn(0);
298 PetscErrorCode ierr_cadence = 0, ierr_name = 0, ierr_span = 0;
300 PetscFunctionBeginUser;
303 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
305 PetscCall(PetscPopErrorHandler());
307 PetscCall(
PicurvAssertIntEqual(PETSC_ERR_ARG_OUTOFRANGE, ierr_cadence,
"non-positive stride is rejected"));
310 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
312 PetscCall(PetscPopErrorHandler());
314 PetscCall(
PicurvAssertIntEqual(PETSC_ERR_ARG_OUTOFRANGE, ierr_name,
"an empty window name is rejected"));
317 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
319 PetscCall(PetscPopErrorHandler());
322 PetscFunctionReturn(0);
328 PetscBool *same, PetscInt *first_difference)
330 char base_digest[65], variant_digest[65];
334 PetscFunctionBeginUser;
337 PetscCall(PetscStrcmp(base_digest, variant_digest, same));
338 *first_difference = -1;
340 PetscBool group_same = PETSC_FALSE;
342 PetscCall(PetscStrcmp(base_groups[group], variant_groups[group], &group_same));
343 if (!group_same) { *first_difference = group;
break; }
345 PetscFunctionReturn(0);
367 PetscBool same = PETSC_FALSE;
370 PetscFunctionBeginUser;
374 PetscCall(
PicurvAssertBool(same,
"hashing an unchanged definition is stable"));
380 PetscCall(
PicurvAssertBool(same,
"extending end_time does not change the identity"));
387 PetscCall(
PicurvAssertBool(same,
"reordering the field list does not change the identity"));
394 PetscCall(
PicurvAssertBool(same,
"swapping covariance members does not change the identity"));
395 PetscFunctionReturn(0);
403 PetscBool same = PETSC_FALSE;
405 PetscBool named = PETSC_FALSE;
407 PetscFunctionBeginUser;
411 PetscCall(
PicurvAssertBool((PetscBool)!same,
"a renamed window is a different window"));
417 PetscCall(
PicurvAssertBool((PetscBool)!same,
"a moved start is a different window"));
423 PetscCall(
PicurvAssertBool((PetscBool)!same,
"a changed weighting is a different window"));
429 PetscCall(
PicurvAssertBool((PetscBool)!same,
"a changed cadence is a different window"));
436 PetscCall(
PicurvAssertBool((PetscBool)!same,
"a changed moment set is a different window"));
442 PetscCall(
PicurvAssertBool((PetscBool)!same,
"a dropped covariance is a different window"));
448 PetscCall(
PicurvAssertBool((PetscBool)!named,
"every hashed group has a stable name"));
451 PetscCall(
PicurvAssertBool(named,
"an out-of-range group index is named unknown"));
452 PetscFunctionReturn(0);
457 char *out,
size_t out_size)
463 PetscFunctionBeginUser;
467 PetscCall(PetscStrlen(out, &used));
468 PetscCall(PetscSNPrintf(out + used, out_size - used,
"%s%s", group ?
"," :
"", groups[group]));
470 PetscFunctionReturn(0);
487 PetscFunctionBeginUser;
498 PetscCall(
PicurvAssertIntEqual(2, group,
"a changed weighting localizes to the weighting group"));
503 PetscCall(
PicurvAssertIntEqual(5, group,
"a dropped covariance localizes to the covariances group"));
524 "a truncated digest list reports no property rather than a wrong one"));
525 PetscFunctionReturn(0);
549 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv statistics window tests");
550 if (ierr)
return (
int)ierr;
551 ierr =
PicurvRunTests(
"unit-statistics-window", cases,
sizeof(cases) /
sizeof(cases[0]));
552 if (ierr) { PetscFinalize();
return (
int)ierr; }
553 ierr = PetscFinalize();
Authoritative identities and storage metadata for persistent Eulerian fields.
Window lifecycle, scheduling, and weighting for the field-statistics pipeline.
PetscErrorCode PicurvWindowComputeHash(const PicurvWindowDefinition *definition, char digest_hex[65], char group_digest_hex[][17])
Computes the resolved identity hash of one window definition.
#define PICURV_WINDOW_HASH_GROUP_COUNT
Number of independently hashed property groups in a window definition.
#define PICURV_WINDOW_HASH_GROUP_LENGTH
Stored length of one truncated group digest, including the terminator.
PetscReal effective_start
Origin of the first represented interval.
const char * PicurvWindowHashGroupName(PetscInt group)
Returns the stable name of one hashed property group.
PetscInt first
First member; must also appear in the field list.
PicurvWindowFieldRequest fields[16]
PetscReal time_cadence
Used when cadence_kind is time; must be positive.
PetscReal end_time
Requested end; ignored when bounded is false.
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.
@ PICURV_WINDOW_PENDING
Requested start not yet reached.
@ PICURV_WINDOW_COMPLETE
Bounded end reached; accepts nothing further.
@ PICURV_WINDOW_ACTIVE
Accepting due states.
PetscErrorCode PicurvWindowInit(PicurvWindow *window, const PicurvWindowDefinition *definition)
Validates a definition and initializes a window to the pending state.
PetscErrorCode PicurvWindowOfferState(PicurvWindow *window, PetscInt step, PetscReal time, PetscBool *accepted, PetscReal *weight)
Offers one completed state to a window and reports the decision.
PetscBool want_second
Also keep the centered second moment.
PetscInt second
Second member; must also appear in the field list.
PicurvWindowCovarianceRequest covariances[16]
PetscBool bounded
False for an open-ended window.
PetscReal start_time
Requested start.
PetscInt covariance_count
PetscInt field_id
Catalogued Eulerian field identity.
PetscReal PicurvWindowProgress(const PicurvWindow *window)
Reports the fraction of a bounded window's span that has been represented.
PicurvWeighting
How an accepted state's weight is determined.
@ PICURV_WEIGHTING_PHYSICAL_TIME
Weight is the represented interval.
@ PICURV_WEIGHTING_SAMPLE
Equal weight per accepted state.
@ PICURV_CADENCE_TIME
First state at or past each nominal time target.
@ PICURV_CADENCE_STEP
Every n completed steps from activation.
PetscReal represented_time
Physical time the window covers.
PetscErrorCode PicurvWindowFirstHashDifference(const PicurvWindowDefinition *definition, const char *saved_group_digests, PetscInt *group)
Reports which hashed property group first differs from saved group digests.
PicurvWeighting weighting
Runtime state of one window.
The scientifically immutable definition of one window.
static PetscErrorCode TestStrideAndOffScheduleNoOp(void)
Stride skips states, and the accepted weight still spans the whole gap.
static PetscErrorCode TestEndClippingAndCompletion(void)
A bounded window clips its final interval and then accepts nothing.
static PetscErrorCode HashAndCompare(const PicurvWindowDefinition *baseline, const PicurvWindowDefinition *variant, PetscBool *same, PetscInt *first_difference)
Hashes a definition and reports which property group changed against a baseline.
static PetscErrorCode TestDuplicateEventRejected(void)
The same completed step offered twice is counted once.
int main(int argc, char **argv)
Entry point for the window lifecycle suite.
static PetscErrorCode TestInvalidDefinitionsRejected(void)
Invalid definitions are rejected at initialization.
static PetscErrorCode TestOriginStateAnchorsWithoutSampling(void)
A state at the window origin anchors without becoming a sample.
static PetscErrorCode TestLateFirstObservationMovesOrigin(void)
A window first seen after its requested start moves its origin forward.
static PicurvWindowDefinition HashWindow(void)
Builds the hash fixture: a Ucat/P window with a second moment and a covariance.
static PetscErrorCode SerializeGroupDigests(const PicurvWindowDefinition *definition, char *out, size_t out_size)
Serializes a definition's group digests the way a checkpoint records them.
static PetscErrorCode TestHashExclusionsAndStability(void)
The hash is stable, and excludes exactly the properties the spec excludes.
static PetscErrorCode TestVariableTimestepWeighting(void)
Variable timestep weighting follows the actual elapsed intervals.
static PicurvWindowDefinition StepWindow(const char *name, PetscReal start, PetscReal end, PetscBool bounded, PicurvWeighting weighting, PetscInt cadence)
Builds a step-cadence definition.
static PetscErrorCode TestFirstHashDifferenceLocalization(void)
Saved group digests must localize a change to the property that caused it.
static PetscErrorCode TestHashDetectsEachProperty(void)
Every hashed property changes the digest and is named by its group digest.
static PetscErrorCode TestTimeCadenceOvershootAcceptedOnce(void)
A step overshooting several time targets is accepted once, losing no time.
static PetscErrorCode TestWeightingsAgreeAtConstantTimestep(void)
The two weightings must agree on a constant-timestep run.
static PetscErrorCode RunUniform(PicurvWindow *w, PetscInt steps, PetscReal dt, PetscReal *total_weight, PetscInt *count)
Drives a uniform-dt sequence and returns the accumulated weight and count.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
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.