PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
statistics_window.c
Go to the documentation of this file.
1/**
2 * @file statistics_window.c
3 * @brief Window lifecycle, scheduling, and weighting for the field-statistics pipeline.
4 *
5 * Full API contract is documented with the declarations in
6 * `include/statistics_window.h`.
7 */
8
9#include "statistics_window.h"
10#include "variables.h"
11#include "logging.h"
13#include "field_catalog.h"
14#include "checksum.h"
15
16/** @brief Tolerance for treating two physical times as the same instant. */
17#define WINDOW_TIME_EPSILON 1.0e-12
18
19/**
20 * @brief Implementation of \ref PicurvWindowStateName().
21 * @see PicurvWindowStateName()
22 */
24{
25 switch (state) {
26 case PICURV_WINDOW_PENDING: return "pending";
27 case PICURV_WINDOW_ACTIVE: return "active";
28 case PICURV_WINDOW_COMPLETE: return "complete";
29 default: return "unknown";
30 }
31}
32
33#undef __FUNCT__
34#define __FUNCT__ "PicurvWindowInit"
35/**
36 * @brief Implementation of \ref PicurvWindowInit().
37 * @see PicurvWindowInit()
38 */
39PetscErrorCode PicurvWindowInit(PicurvWindow *window, const PicurvWindowDefinition *definition)
40{
41 PetscFunctionBeginUser;
43 PetscCheck(window != NULL && definition != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
44 "Window and definition are required.");
45 PetscCheck(definition->name[0] != '\0', PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
46 "Window name must not be empty.");
47 if (definition->cadence_kind == PICURV_CADENCE_STEP) {
48 PetscCheck(definition->step_cadence > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
49 "Window '%s' needs a positive step cadence, got %" PetscInt_FMT ".",
50 definition->name, definition->step_cadence);
51 } else {
52 PetscCheck(definition->time_cadence > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
53 "Window '%s' needs a positive time cadence, got %g.",
54 definition->name, (double)definition->time_cadence);
55 }
56 PetscCheck(!definition->bounded || definition->end_time > definition->start_time,
57 PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
58 "Window '%s' must end after it starts.", definition->name);
59
60 PetscCall(PetscMemzero(window, sizeof(*window)));
61 window->definition = *definition;
63 /* Anchoring the interval origin at the requested start, rather than at the
64 * first accepted state, is what lets the first sample represent the interval
65 * back to the requested bound instead of silently dropping it. */
66 window->effective_start = definition->start_time;
67 window->effective_end = definition->start_time;
68 window->last_accepted_time = definition->start_time;
69 window->activation_step = -1;
70 window->last_event_step = PETSC_MIN_INT;
71 window->next_time_target = 0;
73 PetscFunctionReturn(0);
74}
75
76/**
77 * @brief Internal helper: reports whether a state is due under the window's schedule.
78 * @details Local to this translation unit. Advances no state.
79 */
80static PetscBool WindowStateIsDue(const PicurvWindow *window, PetscInt step, PetscReal time)
81{
83 /* The activation step is itself due; subsequent ones follow the stride. */
84 if (window->activation_step < 0) return PETSC_TRUE;
85 return (PetscBool)(((step - window->activation_step) % window->definition.step_cadence) == 0);
86 }
87 /* Time cadence: targets sit on the absolute grid effective_start + k*cadence, so
88 * the schedule cannot drift as dt varies. A state is due once it reaches the
89 * next outstanding target. */
90 {
91 const PetscReal target = window->effective_start +
92 (PetscReal)window->next_time_target * window->definition.time_cadence;
93 return (PetscBool)(time >= target - WINDOW_TIME_EPSILON);
94 }
95}
96
97/**
98 * @brief Internal helper: advances the time-cadence target past the accepted time.
99 * @details Local to this translation unit. A single large step may overshoot several
100 * targets; they are consumed at once, because the accepted state's weight is
101 * the actual elapsed interval and so already accounts for the whole span.
102 */
103static void WindowAdvanceTimeTarget(PicurvWindow *window, PetscReal time)
104{
105 if (window->definition.cadence_kind != PICURV_CADENCE_TIME) return;
106 while (window->effective_start +
107 (PetscReal)window->next_time_target * window->definition.time_cadence
108 <= time + WINDOW_TIME_EPSILON) {
109 window->next_time_target += 1;
110 }
111}
112
113/**
114 * @brief Implementation of \ref PicurvWindowOfferState().
115 * @see PicurvWindowOfferState()
116 */
117PetscErrorCode PicurvWindowOfferState(PicurvWindow *window, PetscInt step, PetscReal time,
118 PetscBool *accepted, PetscReal *weight)
119{
120 PetscReal interval = 0.0;
121 PetscReal right_edge = 0.0;
122 PetscBool closes = PETSC_FALSE;
123
124 PetscFunctionBeginUser;
125 PetscCheck(window != NULL && accepted != NULL && weight != NULL,
126 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
127 "Window, acceptance flag, and weight output are required.");
128 *accepted = PETSC_FALSE;
129 *weight = 0.0;
130
131 if (window->state == PICURV_WINDOW_COMPLETE) PetscFunctionReturn(0);
132 /* A completed state is accepted at most once, so a step already seen is
133 * rejected outright rather than double counted. */
134 if (step == window->last_event_step) PetscFunctionReturn(0);
135 if (time < window->definition.start_time - WINDOW_TIME_EPSILON) PetscFunctionReturn(0);
136
137 /* First observation: a window resumed later than its requested start cannot
138 * claim represented time it never saw, so the origin moves forward. */
139 if (window->state == PICURV_WINDOW_PENDING) {
140 if (time > window->definition.start_time + WINDOW_TIME_EPSILON) {
141 window->effective_start = time;
142 window->last_accepted_time = time;
143 }
144 window->state = PICURV_WINDOW_ACTIVE;
145 window->activation_step = step;
146 window->effective_end = window->effective_start;
147 window->next_time_target = 0;
149 }
150
151 if (!WindowStateIsDue(window, step, time)) {
152 /* An active off-schedule state changes no scientific state. */
153 PetscFunctionReturn(0);
154 }
155 window->last_event_step = step;
156
157 /* Clip the final represented interval to the requested bound. */
158 right_edge = time;
159 if (window->definition.bounded && time >= window->definition.end_time - WINDOW_TIME_EPSILON) {
160 right_edge = window->definition.end_time;
161 closes = PETSC_TRUE;
162 }
163
164 interval = right_edge - window->last_accepted_time;
165 WindowAdvanceTimeTarget(window, time);
166
167 if (interval <= WINDOW_TIME_EPSILON) {
168 /* A zero-length interval is not a sample. It still anchors the origin, which
169 * is what makes initial-state handling identical under both weightings. */
170 window->last_accepted_time = right_edge;
171 window->effective_end = right_edge;
172 if (closes) window->state = PICURV_WINDOW_COMPLETE;
173 PetscFunctionReturn(0);
174 }
175
176 *weight = (window->definition.weighting == PICURV_WEIGHTING_SAMPLE) ? 1.0 : interval;
177 *accepted = PETSC_TRUE;
178
179 window->last_accepted_time = right_edge;
180 window->effective_end = right_edge;
181 window->sample_count += 1;
182 window->total_weight += *weight;
183 window->represented_time += interval;
184 if (closes) window->state = PICURV_WINDOW_COMPLETE;
185 PetscFunctionReturn(0);
186}
187
188/** @brief Stable names of the hashed property groups, in serialization order. */
190 "name", "start_time", "weighting", "cadence", "fields", "covariances", "mask", "target"
191};
192
193/**
194 * @brief Implementation of \ref PicurvWindowHashGroupName().
195 * @see PicurvWindowHashGroupName()
196 */
197const char *PicurvWindowHashGroupName(PetscInt group)
198{
199 if (group < 0 || group >= PICURV_WINDOW_HASH_GROUP_COUNT) return "unknown";
200 return kHashGroupNames[group];
201}
202
203/**
204 * @brief Internal helper: orders request indices so listing order cannot change the hash.
205 * @details Local to this translation unit. Insertion sort over at most
206 * `PICURV_WINDOW_MAX_REQUESTS` entries, keyed on a primary and secondary
207 * integer so the same routine serves both fields and covariance pairs.
208 */
209static void SortRequestOrder(PetscInt count, const PetscInt *primary, const PetscInt *secondary,
210 PetscInt *order)
211{
212 for (PetscInt n = 0; n < count; ++n) order[n] = n;
213 for (PetscInt n = 1; n < count; ++n) {
214 const PetscInt candidate = order[n];
215 PetscInt m = n - 1;
216
217 while (m >= 0 &&
218 (primary[order[m]] > primary[candidate] ||
219 (primary[order[m]] == primary[candidate] &&
220 secondary[order[m]] > secondary[candidate]))) {
221 order[m + 1] = order[m];
222 --m;
223 }
224 order[m + 1] = candidate;
225 }
226}
227
228#undef __FUNCT__
229#define __FUNCT__ "PicurvWindowComputeHash"
230/**
231 * @brief Implementation of \ref PicurvWindowComputeHash().
232 * @see PicurvWindowComputeHash()
233 */
234PetscErrorCode PicurvWindowComputeHash(const PicurvWindowDefinition *definition,
235 char digest_hex[65],
236 char group_digest_hex[][PICURV_WINDOW_HASH_GROUP_LENGTH])
237{
239 PetscInt field_primary[PICURV_WINDOW_MAX_REQUESTS];
240 PetscInt field_secondary[PICURV_WINDOW_MAX_REQUESTS];
241 PetscInt field_order[PICURV_WINDOW_MAX_REQUESTS];
242 PetscInt pair_primary[PICURV_WINDOW_MAX_REQUESTS];
243 PetscInt pair_secondary[PICURV_WINDOW_MAX_REQUESTS];
244 PetscInt pair_order[PICURV_WINDOW_MAX_REQUESTS];
245
246 PetscFunctionBeginUser;
248 PetscCheck(definition != NULL && digest_hex != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
249 "Definition and digest output are required.");
250 PetscCheck(definition->field_count >= 0 && definition->field_count <= PICURV_WINDOW_MAX_REQUESTS,
251 PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
252 "Window '%s' requests %" PetscInt_FMT " fields; at most %d are supported.",
253 definition->name, definition->field_count, PICURV_WINDOW_MAX_REQUESTS);
254 PetscCheck(definition->covariance_count >= 0 &&
256 PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
257 "Window '%s' requests %" PetscInt_FMT " covariances; at most %d are supported.",
258 definition->name, definition->covariance_count, PICURV_WINDOW_MAX_REQUESTS);
259
260 for (PetscInt field_index = 0; field_index < definition->field_count; ++field_index) {
261 field_primary[field_index] = definition->fields[field_index].field_id;
262 field_secondary[field_index] = 0;
263 }
264 SortRequestOrder(definition->field_count, field_primary, field_secondary, field_order);
265 for (PetscInt pair_index = 0; pair_index < definition->covariance_count; ++pair_index) {
266 const PetscInt a = definition->covariances[pair_index].first;
267 const PetscInt b = definition->covariances[pair_index].second;
268
269 /* Covariance is symmetric, so the pair is canonicalized here rather than
270 * requiring the user to list its members in catalog order. */
271 pair_primary[pair_index] = PetscMin(a, b);
272 pair_secondary[pair_index] = PetscMax(a, b);
273 }
274 SortRequestOrder(definition->covariance_count, pair_primary, pair_secondary, pair_order);
275
276 PicurvSHA256Init(&whole);
277 for (PetscInt group = 0; group < PICURV_WINDOW_HASH_GROUP_COUNT; ++group) {
278 char text[1024];
279 char group_digest[65];
281 size_t used = 0;
282 size_t length = 0;
283
284 text[0] = '\0';
285 switch (group) {
286 case 0:
287 PetscCall(PetscSNPrintf(text, sizeof(text), "name=%s\n", definition->name));
288 break;
289 case 1:
290 PetscCall(PetscSNPrintf(text, sizeof(text), "start_time=%.17g\n",
291 (double)definition->start_time));
292 break;
293 case 2:
294 PetscCall(PetscSNPrintf(text, sizeof(text), "weighting=%s\n",
296 ? "sample" : "physical_time"));
297 break;
298 case 3:
299 if (definition->cadence_kind == PICURV_CADENCE_STEP) {
300 PetscCall(PetscSNPrintf(text, sizeof(text), "cadence=step:%" PetscInt_FMT "\n",
301 definition->step_cadence));
302 } else {
303 PetscCall(PetscSNPrintf(text, sizeof(text), "cadence=time:%.17g\n",
304 (double)definition->time_cadence));
305 }
306 break;
307 case 4:
308 for (PetscInt n = 0; n < definition->field_count; ++n) {
309 const PicurvWindowFieldRequest *request = &definition->fields[field_order[n]];
310 const char *name = FieldCanonicalName((FieldId)request->field_id);
311
312 PetscCheck(name != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
313 "Window '%s' requests unknown field id %" PetscInt_FMT ".",
314 definition->name, request->field_id);
315 PetscCall(PetscStrlen(text, &used));
316 PetscCall(PetscSNPrintf(text + used, sizeof(text) - used, "field=%s:%s\n",
317 name, request->want_second ? "first,second" : "first"));
318 }
319 break;
320 case 5:
321 for (PetscInt n = 0; n < definition->covariance_count; ++n) {
322 const PetscInt index = pair_order[n];
323 const char *first = FieldCanonicalName((FieldId)pair_primary[index]);
324 const char *second = FieldCanonicalName((FieldId)pair_secondary[index]);
325
326 PetscCheck(first != NULL && second != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
327 "Window '%s' requests a covariance over an unknown field id.",
328 definition->name);
329 PetscCall(PetscStrlen(text, &used));
330 PetscCall(PetscSNPrintf(text + used, sizeof(text) - used, "covariance=%s,%s\n",
331 first, second));
332 }
333 break;
334 case 6:
335 /* Exactly one mask is resolved, so this group hashes a constant. It
336 * exists so that a future mask key extends this group instead of
337 * renumbering every group after it and invalidating saved state. */
338 PetscCall(PetscSNPrintf(text, sizeof(text), "mask=fluid\n"));
339 break;
340 default:
341 PetscCall(PetscSNPrintf(text, sizeof(text), "target=pointwise\n"));
342 for (PetscInt n = 0; n < definition->field_count; ++n) {
343 const PicurvWindowFieldRequest *request = &definition->fields[field_order[n]];
344 const FieldDescriptor *descriptor = NULL;
345
346 PetscCall(FieldGetDescriptor((FieldId)request->field_id, &descriptor));
347 PetscCall(PetscStrlen(text, &used));
348 PetscCall(PetscSNPrintf(text + used, sizeof(text) - used, "layout=%s:%s\n",
349 descriptor->canonical_name,
350 FieldLayoutName(descriptor->layout)));
351 }
352 break;
353 }
354
355 PetscCall(PetscStrlen(text, &length));
356 PicurvSHA256Update(&whole, text, length);
357 if (group_digest_hex) {
358 PicurvSHA256Init(&part);
359 PicurvSHA256Update(&part, text, length);
360 PicurvSHA256FinalHex(&part, group_digest);
361 PetscCall(PetscStrncpy(group_digest_hex[group], group_digest,
363 }
364 }
365 PicurvSHA256FinalHex(&whole, digest_hex);
367 PetscFunctionReturn(0);
368}
369
370/**
371 * @brief Implementation of \ref PicurvWindowFirstHashDifference().
372 * @see PicurvWindowFirstHashDifference()
373 */
375 const char *saved_group_digests,
376 PetscInt *group)
377{
378 char digest[65];
380 const char *cursor = saved_group_digests;
381
382 PetscFunctionBeginUser;
383 PetscCheck(definition != NULL && group != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
384 "Definition and group output are required.");
385 *group = -1;
386 if (!saved_group_digests) PetscFunctionReturn(0);
387 PetscCall(PicurvWindowComputeHash(definition, digest, current));
388
389 for (PetscInt index = 0; index < PICURV_WINDOW_HASH_GROUP_COUNT; ++index) {
390 const char *comma = strchr(cursor, ',');
391 const size_t length = comma ? (size_t)(comma - cursor) : strlen(cursor);
392 size_t expected = 0;
393
394 PetscCall(PetscStrlen(current[index], &expected));
395 /* Every well-formed digest is fixed width, so a short segment means the
396 * saved list is malformed rather than that this property changed. A
397 * malformed list localizes to nothing: reporting the wrong property would
398 * be worse than reporting none. */
399 if (length != expected) PetscFunctionReturn(0);
400 if (strncmp(cursor, current[index], length)) {
401 *group = index;
402 PetscFunctionReturn(0);
403 }
404 if (!comma) PetscFunctionReturn(0);
405 cursor = comma + 1;
406 }
407 PetscFunctionReturn(0);
408}
409
410/**
411 * @brief Implementation of \ref PicurvWindowProgress().
412 * @see PicurvWindowProgress()
413 */
414PetscReal PicurvWindowProgress(const PicurvWindow *window)
415{
416 PetscReal span = 0.0;
417
418 if (window == NULL || !window->definition.bounded) return 0.0;
419 span = window->definition.end_time - window->effective_start;
420 if (span <= 0.0) return 0.0;
421 return PetscMin(1.0, window->represented_time / span);
422}
423
424/**
425 * @brief Implementation of \ref FieldStatisticsIsActive().
426 * @see FieldStatisticsIsActive()
427 */
428PetscBool FieldStatisticsIsActive(const SimCtx *simCtx)
429{
430 if (!simCtx || !simCtx->fieldStatisticsEnabled) return PETSC_FALSE;
431 return (PetscBool)(simCtx->fieldStatisticsWindowCount > 0 &&
432 simCtx->fieldStatisticsWindows != NULL);
433}
434
435#undef __FUNCT__
436#define __FUNCT__ "FieldStatisticsUpdateWindows"
437/**
438 * @brief Implementation of \ref FieldStatisticsUpdateWindows().
439 * @see FieldStatisticsUpdateWindows()
440 */
441PetscErrorCode FieldStatisticsUpdateWindows(SimCtx *simCtx, PetscInt step, PetscReal time)
442{
443 PetscFunctionBeginUser;
445 PetscCheck(simCtx != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL.");
446 if (!FieldStatisticsIsActive(simCtx)) { PROFILE_FUNCTION_END; PetscFunctionReturn(0); }
447
448 for (PetscInt window_index = 0; window_index < simCtx->fieldStatisticsWindowCount; ++window_index) {
449 PicurvWindow *window = &simCtx->fieldStatisticsWindows[window_index];
450 const PicurvWindowState before = window->state;
451 PetscBool accepted = PETSC_FALSE;
452 PetscReal weight = 0.0;
453
454 PetscCall(PicurvWindowOfferState(window, step, time, &accepted, &weight));
455
456 if (before == PICURV_WINDOW_PENDING && window->state == PICURV_WINDOW_ACTIVE) {
458 "Statistics window '%s' active from t=%.6g.\n",
459 window->definition.name, (double)window->effective_start);
460 }
461 if (accepted) {
462 /* Apply the accepted weight to every block's accumulators. Windows share
463 * the source state but own independent accumulator state. */
464 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
465 UserCtx *user = &simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user[bi];
466 if (!user->fieldStatisticsStorage) continue;
467 PetscCall(PicurvWindowAccumulate(user, &window->definition,
468 &user->fieldStatisticsStorage[window_index], weight));
469 }
471 "Statistics window '%s' accepted step %d at t=%.6g with weight %.6g "
472 "(samples=%d, represented=%.6g).\n",
473 window->definition.name, step, (double)time, (double)weight,
474 window->sample_count, (double)window->represented_time);
475 } else if (window->state == PICURV_WINDOW_ACTIVE) {
476 /* An active window that took nothing was either off schedule or offered a
477 * zero-length interval. Both are expected, so this is the level that
478 * explains a sample count without implying anything is wrong. */
480 "Statistics window '%s' did not sample step %d at t=%.6g "
481 "(last accepted t=%.6g, samples=%d).\n",
482 window->definition.name, step, (double)time,
483 (double)window->last_accepted_time, window->sample_count);
484 }
485 if (before != PICURV_WINDOW_COMPLETE && window->state == PICURV_WINDOW_COMPLETE) {
487 "Statistics window '%s' complete: %d sample(s), total weight %.6g, "
488 "represented time %.6g.\n",
489 window->definition.name, window->sample_count,
490 (double)window->total_weight, (double)window->represented_time);
491 if (window->sample_count == 0) {
493 "Statistics window '%s' completed without accepting any sample.\n",
494 window->definition.name);
495 } else {
496 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
497
498 /* A point that was never valid carries no average at all, which a
499 * reader of the mean field cannot see. Report it once, at the only
500 * moment the final coverage is known. The reduction is collective and
501 * runs once per window, not per step. */
502 if (user && user->fieldStatisticsStorage) {
503 PetscReal lowest = 1.0, highest = 0.0;
504
505 PetscCall(PicurvWindowValidFractionRange(user, &window->definition,
506 &user->fieldStatisticsStorage[window_index],
507 window->sample_count, &lowest, &highest));
508 if (lowest <= 0.0) {
510 "Statistics window '%s' completed with points that were never "
511 "valid; their mean and moments are undefined.\n",
512 window->definition.name);
513 } else {
515 "Statistics window '%s' per-point valid fraction spans [%.3f, %.3f].\n",
516 window->definition.name, (double)lowest, (double)highest);
517 }
518 }
519 }
520 }
521 }
523 PetscFunctionReturn(0);
524}
Small dependency-free SHA-256 utility for persistent metadata identity.
void PicurvSHA256Init(PicurvSHA256Context *context)
Initialize an incremental SHA-256 calculation.
Definition checksum.c:62
void PicurvSHA256Update(PicurvSHA256Context *context, const void *data, size_t length)
Add bytes to an incremental SHA-256 calculation.
Definition checksum.c:74
void PicurvSHA256FinalHex(PicurvSHA256Context *context, char digest_hex[65])
Finish a SHA-256 calculation and return a lowercase hexadecimal digest.
Definition checksum.c:98
Incremental SHA-256 state.
Definition checksum.h:14
Authoritative identities and storage metadata for persistent Eulerian fields.
FieldLayout layout
const char * FieldCanonicalName(FieldId field_id)
Return the canonical printable name for an ID.
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.
Logging utilities and macros for PETSc-based applications.
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:894
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:885
Per-window PETSc accumulator storage and pointwise application.
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 PicurvWindowAccumulate(UserCtx *user, const PicurvWindowDefinition *definition, PicurvWindowStorage *storage, PetscReal weight)
Applies one accepted completed state to a window's accumulators.
#define WINDOW_TIME_EPSILON
Tolerance for treating two physical times as the same instant.
PetscErrorCode FieldStatisticsUpdateWindows(SimCtx *simCtx, PetscInt step, PetscReal time)
Implementation of FieldStatisticsUpdateWindows().
PetscErrorCode PicurvWindowComputeHash(const PicurvWindowDefinition *definition, char digest_hex[65], char group_digest_hex[][PICURV_WINDOW_HASH_GROUP_LENGTH])
Implementation of PicurvWindowComputeHash().
const char * PicurvWindowHashGroupName(PetscInt group)
Implementation of PicurvWindowHashGroupName().
static void WindowAdvanceTimeTarget(PicurvWindow *window, PetscReal time)
Internal helper: advances the time-cadence target past the accepted time.
static void SortRequestOrder(PetscInt count, const PetscInt *primary, const PetscInt *secondary, PetscInt *order)
Internal helper: orders request indices so listing order cannot change the hash.
static PetscBool WindowStateIsDue(const PicurvWindow *window, PetscInt step, PetscReal time)
Internal helper: reports whether a state is due under the window's schedule.
static const char *const kHashGroupNames[PICURV_WINDOW_HASH_GROUP_COUNT]
Stable names of the hashed property groups, in serialization order.
PetscBool FieldStatisticsIsActive(const SimCtx *simCtx)
Implementation of FieldStatisticsIsActive().
PetscErrorCode PicurvWindowInit(PicurvWindow *window, const PicurvWindowDefinition *definition)
Implementation of PicurvWindowInit().
PetscErrorCode PicurvWindowOfferState(PicurvWindow *window, PetscInt step, PetscReal time, PetscBool *accepted, PetscReal *weight)
Implementation of PicurvWindowOfferState().
const char * PicurvWindowStateName(PicurvWindowState state)
Implementation of PicurvWindowStateName().
PetscReal PicurvWindowProgress(const PicurvWindow *window)
Implementation of PicurvWindowProgress().
PetscErrorCode PicurvWindowFirstHashDifference(const PicurvWindowDefinition *definition, const char *saved_group_digests, PetscInt *group)
Implementation of PicurvWindowFirstHashDifference().
Window lifecycle, scheduling, and weighting for the field-statistics pipeline.
PetscInt last_event_step
Guards against a step being offered twice.
#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.
PetscInt sample_count
PetscReal last_accepted_time
Right edge of the last represented interval.
PicurvWindowState state
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 effective_end
End of the last represented interval.
PetscReal end_time
Requested end; ignored when bounded is false.
PicurvCadenceKind cadence_kind
PetscReal total_weight
PetscInt step_cadence
Used when cadence_kind is step; must be positive.
PicurvWindowState
Lifecycle state of one window.
@ PICURV_WINDOW_PENDING
Requested start not yet reached.
@ PICURV_WINDOW_COMPLETE
Bounded end reached; accepts nothing further.
@ PICURV_WINDOW_ACTIVE
Accepting due states.
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.
PicurvWindowDefinition definition
PetscInt next_time_target
k in effective_start + k*time_cadence.
PetscReal start_time
Requested start.
PetscInt activation_step
Step at which the window became active.
PetscInt field_id
Catalogued Eulerian field identity.
#define PICURV_WINDOW_MAX_REQUESTS
Maximum fields or covariance pairs one window may request.
@ 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.
Runtime state of one window.
The scientifically immutable definition of one window.
One field a window accumulates.
Main header file for a complex fluid dynamics solver.
PetscInt fieldStatisticsWindowCount
Definition variables.h:939
UserCtx * user
Definition variables.h:736
PetscInt block_number
Definition variables.h:960
UserMG usermg
Definition variables.h:1019
PetscBool fieldStatisticsEnabled
Definition variables.h:938
struct PicurvWindow * fieldStatisticsWindows
Definition variables.h:940
PetscInt mglevels
Definition variables.h:743
struct PicurvWindowStorage * fieldStatisticsStorage
Definition variables.h:1136
MGCtx * mgctx
Definition variables.h:746
The master context for the entire simulation.
Definition variables.h:866
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1073