PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
field_catalog.c
Go to the documentation of this file.
1/**
2 * @file field_catalog.c
3 * @brief Authoritative persistent-Eulerian-field catalog and runtime view resolver.
4 */
5
6#include "field_catalog.h"
7
8#define FIELD_NO_VEC_OFFSET ((size_t)-1)
9
10#define FIELD_ENTRY(field_id_, name_, alias1_, alias2_, dof_, dm_, layout_, sync_, availability_, capabilities_, global_member_, local_member_) \
11 [field_id_] = { \
12 field_id_, name_, alias1_, alias2_, dof_, dm_, layout_, sync_, availability_, capabilities_, \
13 offsetof(UserCtx, global_member_), offsetof(UserCtx, local_member_) \
14 }
15
16#define FIELD_COORDINATE_ENTRY(field_id_, name_, dof_, layout_, capabilities_) \
17 [field_id_] = { \
18 field_id_, name_, NULL, NULL, dof_, FIELD_DM_COORDINATES, layout_, \
19 FIELD_SYNC_STANDARD, FIELD_AVAILABILITY_ALWAYS, capabilities_, \
20 FIELD_NO_VEC_OFFSET, FIELD_NO_VEC_OFFSET \
21 }
22
29 FIELD_CAPABILITY_CHECKPOINT, Ucat, lUcat),
33 FIELD_CAPABILITY_CHECKPOINT, Ucont, lUcont),
36 FIELD_CAPABILITY_GHOST_UPDATE, Ucont_o, lUcont_o),
44 FIELD_ENTRY(FIELD_ID_NU_T, "Nu_t", "Eddy Viscosity", NULL, 1, FIELD_DM_DA, FIELD_LAYOUT_CELL_CENTERED,
47 FIELD_CAPABILITY_CHECKPOINT, Nu_t, lNu_t),
48 /* Holds the model coefficient C that multiplies Delta^2 |S|, which is Cs^2 in the
49 classical notation and is signed once backscatter is admitted. Exists only for
50 the dynamic model; the constant model prescribes its coefficient from config. */
55 /* Wall-model friction velocity, nonzero only in the first interior cell of a WALL
56 face. It is the quantity a wall model is scored against, so it is checkpointed and
57 exposed to postprocessing rather than being recomputed from the corrected velocity,
58 which no longer carries the law that produced it. */
59 FIELD_ENTRY(FIELD_ID_U_TAU, "Utau", "Friction Velocity", NULL, 1, FIELD_DM_DA,
63 FIELD_CAPABILITY_CHECKPOINT, Friction_Velocity, lFriction_Velocity),
64 /* The wall model's effective eddy viscosity at its own wall face. A wall-resolved
65 run has no such face and carries zero here; the field exists so the viscous flux
66 can deliver the modelled stress without re-deriving the wall distance and
67 tangential speed that produced it. Derived state, so not checkpointed. */
68 FIELD_ENTRY(FIELD_ID_NU_WALL, "NuWall", "Wall Eddy Viscosity", NULL, 1, FIELD_DM_DA,
72 Nu_Wall, lNu_Wall),
76 FIELD_ENTRY(FIELD_ID_DIFFUSIVITY_GRADIENT, "DiffusivityGradient", NULL, NULL, 3, FIELD_DM_FDA,
78 FIELD_CAPABILITY_GHOST_UPDATE, DiffusivityGradient, lDiffusivityGradient),
91 FIELD_CAPABILITY_CHECKPOINT, Nvert, lNvert),
95 FIELD_ENTRY(FIELD_ID_CENT, "Cent", "Center-Coordinates", NULL, 3, FIELD_DM_FDA, FIELD_LAYOUT_CELL_CENTERED,
99 FIELD_ENTRY(FIELD_ID_CENTX, "Centx", "X-Face-Centers", NULL, 3, FIELD_DM_FDA, FIELD_LAYOUT_I_FACE,
103 FIELD_ENTRY(FIELD_ID_CENTY, "Centy", "Y-Face-Centers", NULL, 3, FIELD_DM_FDA, FIELD_LAYOUT_J_FACE,
107 FIELD_ENTRY(FIELD_ID_CENTZ, "Centz", "Z-Face-Centers", NULL, 3, FIELD_DM_FDA, FIELD_LAYOUT_K_FACE,
155 FIELD_CAPABILITY_GHOST_UPDATE, Nvert_o, lNvert_o),
158 FIELD_CAPABILITY_GHOST_UPDATE | FIELD_CAPABILITY_CHECKPOINT, ParticleCount, lParticleCount),
159 /* Corner-staging workspace. Node-centered by construction: the interpolation
160 * writes cell-centered data onto grid corners. Not checkpointed, since it is
161 * transient scratch rebuilt on every conversion. */
162 FIELD_ENTRY(FIELD_ID_CELL_SCALAR_AT_CORNER, "CellScalarAtCorner", NULL, NULL, 1,
165 FIELD_CAPABILITY_GHOST_UPDATE, CellScalarAtCorner, lCellScalarAtCorner),
166 FIELD_ENTRY(FIELD_ID_CELL_VECTOR_AT_CORNER, "CellVectorAtCorner", NULL, NULL, 3,
169 FIELD_CAPABILITY_GHOST_UPDATE, CellVectorAtCorner, lCellVectorAtCorner),
170 /* Post-processing staging fields. A derived statistic is config-counted and so
171 * has no compile-time offset of its own; staging the result here lets the
172 * existing ghost, nodal-average, and logging paths address it by name instead
173 * of each growing a second, view-based entry point. */
174 FIELD_ENTRY(FIELD_ID_POST_SCALAR, "PostScalar", NULL, NULL, 1,
177 FIELD_CAPABILITY_GHOST_UPDATE, PostScalar, lPostScalar),
178 FIELD_ENTRY(FIELD_ID_POST_VECTOR, "PostVector", NULL, NULL, 3,
181 FIELD_CAPABILITY_GHOST_UPDATE, PostVector, lPostVector),
182 /* The Q-criterion is computed at cell centres. It is catalogued only so the nodal
183 * average can refresh its ghosts by name: a cell value written as point data sits
184 * half a cell away from the node the file assigns it. Post-processor only. */
185 FIELD_ENTRY(FIELD_ID_QCRIT, "Qcrit", NULL, NULL, 1,
188 FIELD_CAPABILITY_GHOST_UPDATE, Qcrit, lQcrit)
189};
190
191_Static_assert(sizeof(gFieldCatalog) / sizeof(gFieldCatalog[0]) == FIELD_ID_COUNT,
192 "Field catalog must contain one entry per FieldId.");
193
194/**
195 * @brief Returns the immutable catalog descriptor for one typed field identity.
196 * @details Validates the enum range and the table's ID/index invariant before
197 * exposing the catalog-owned descriptor.
198 * @see FieldGetDescriptor()
199 */
200PetscErrorCode FieldGetDescriptor(FieldId field_id, const FieldDescriptor **descriptor)
201{
202 PetscFunctionBeginUser;
203 PetscCheck(descriptor != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
204 "Field descriptor output cannot be NULL.");
205 PetscCheck(field_id >= 0 && field_id < FIELD_ID_COUNT, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
206 "Invalid FieldId value %d.", (int)field_id);
207 PetscCheck(gFieldCatalog[field_id].id == field_id, PETSC_COMM_SELF, PETSC_ERR_PLIB,
208 "Field catalog entry %d is not initialized consistently.", (int)field_id);
209
210 *descriptor = &gFieldCatalog[field_id];
211 PetscFunctionReturn(0);
212}
213
214/**
215 * @brief Resolves a canonical field name or registered alias to a typed identity.
216 * @details Name comparison is intentionally confined to ingress; numerical
217 * consumers receive the resolved @ref FieldId.
218 * @see FieldIdFromName()
219 */
220PetscErrorCode FieldIdFromName(const char *field_name, FieldId *field_id)
221{
222 PetscFunctionBeginUser;
223 PetscCheck(field_name != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
224 "Field name cannot be NULL.");
225 PetscCheck(field_id != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
226 "FieldId output cannot be NULL.");
227
228 for (PetscInt index = 0; index < FIELD_ID_COUNT; ++index) {
229 const FieldDescriptor *descriptor = &gFieldCatalog[index];
230 PetscBool match = PETSC_FALSE;
231
232 PetscCall(PetscStrcasecmp(field_name, descriptor->canonical_name, &match));
233 if (!match && descriptor->alias_1) PetscCall(PetscStrcasecmp(field_name, descriptor->alias_1, &match));
234 if (!match && descriptor->alias_2) PetscCall(PetscStrcasecmp(field_name, descriptor->alias_2, &match));
235 if (match) {
236 *field_id = descriptor->id;
237 PetscFunctionReturn(0);
238 }
239 }
240
241 *field_id = FIELD_ID_INVALID;
242 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE,
243 "Field name '%s' is not registered in the Eulerian field catalog.", field_name);
244}
245
246/**
247 * @brief Returns catalog-owned printable text for a field identity.
248 * @details Invalid enum values return a non-null diagnostic sentinel string.
249 * @see FieldCanonicalName()
250 */
251const char *FieldCanonicalName(FieldId field_id)
252{
253 if (field_id < 0 || field_id >= FIELD_ID_COUNT) return "InvalidField";
254 if (gFieldCatalog[field_id].id != field_id) return "InvalidField";
255 return gFieldCatalog[field_id].canonical_name;
256}
257
258/**
259 * @brief Converts layout metadata to the stable diagnostic label used by field loggers.
260 * @see FieldLayoutName()
261 */
262const char *FieldLayoutName(FieldLayout layout)
263{
264 switch (layout) {
265 case FIELD_LAYOUT_NODE_CENTERED: return "Node-Centered";
266 case FIELD_LAYOUT_CELL_CENTERED: return "Cell-Centered";
267 case FIELD_LAYOUT_I_FACE: return "I-Face";
268 case FIELD_LAYOUT_J_FACE: return "J-Face";
269 case FIELD_LAYOUT_K_FACE: return "K-Face";
270 case FIELD_LAYOUT_COMPONENT_STAGGERED: return "Component-Staggered";
271 default: return "Invalid-Layout";
272 }
273}
274
275/**
276 * @brief Binds one descriptor to the PETSc objects already owned by a UserCtx.
277 * @details Resolves DM and Vec handles without allocating, referencing, or
278 * destroying PETSc storage.
279 * @see FieldGetView()
280 */
281PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
282{
283 const FieldDescriptor *descriptor = NULL;
284
285 PetscFunctionBeginUser;
286 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
287 "UserCtx cannot be NULL when resolving a field view.");
288 PetscCheck(view != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
289 "Field view output cannot be NULL.");
290 PetscCall(FieldGetDescriptor(field_id, &descriptor));
291
292 view->descriptor = descriptor;
293 view->dm = NULL;
294 view->global_vec = NULL;
295 view->local_vec = NULL;
296
297 switch (descriptor->dm_kind) {
298 case FIELD_DM_DA:
299 view->dm = user->da;
300 break;
301 case FIELD_DM_FDA:
302 view->dm = user->fda;
303 break;
305 view->dm = user->fda;
306 PetscCheck(user->da != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
307 "Coordinate DM is unavailable for field '%s'.", descriptor->canonical_name);
308 PetscCall(DMGetCoordinates(user->da, &view->global_vec));
309 PetscCall(DMGetCoordinatesLocal(user->da, &view->local_vec));
310 break;
311 default:
312 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB,
313 "Field '%s' has an invalid DM selector.", descriptor->canonical_name);
314 }
315
316 if (descriptor->dm_kind != FIELD_DM_COORDINATES) {
317 view->global_vec = *(Vec *)((char *)user + descriptor->global_vec_offset);
318 view->local_vec = *(Vec *)((char *)user + descriptor->local_vec_offset);
319 }
320
321 PetscCheck(view->dm != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
322 "DM for field '%s' is unavailable in this UserCtx.", descriptor->canonical_name);
323 PetscCheck(view->global_vec != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
324 "Global vector for field '%s' is unavailable in this UserCtx.", descriptor->canonical_name);
325 PetscCheck(view->local_vec != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
326 "Local vector for field '%s' is unavailable in this UserCtx.", descriptor->canonical_name);
327
328 PetscFunctionReturn(0);
329}
330
331#undef FIELD_COORDINATE_ENTRY
332#undef FIELD_ENTRY
333#undef FIELD_NO_VEC_OFFSET
PetscErrorCode FieldIdFromName(const char *field_name, FieldId *field_id)
Resolves a canonical field name or registered alias to a typed identity.
#define FIELD_ENTRY(field_id_, name_, alias1_, alias2_, dof_, dm_, layout_, sync_, availability_, capabilities_, global_member_, local_member_)
static const FieldDescriptor gFieldCatalog[FIELD_ID_COUNT]
const char * FieldCanonicalName(FieldId field_id)
Returns catalog-owned printable text for a field identity.
PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
Binds one descriptor to the PETSc objects already owned by a UserCtx.
const char * FieldLayoutName(FieldLayout layout)
Converts layout metadata to the stable diagnostic label used by field loggers.
#define FIELD_COORDINATE_ENTRY(field_id_, name_, dof_, layout_, capabilities_)
PetscErrorCode FieldGetDescriptor(FieldId field_id, const FieldDescriptor **descriptor)
Returns the immutable catalog descriptor for one typed field identity.
Authoritative identities and storage metadata for persistent Eulerian fields.
const char * alias_1
@ FIELD_CAPABILITY_CHECKPOINT
@ FIELD_CAPABILITY_GHOST_UPDATE
@ FIELD_CAPABILITY_PERIODIC_GEOMETRY_SHIFT
@ FIELD_CAPABILITY_PERIODIC_CELL_SYNC
@ FIELD_CAPABILITY_PERIODIC_FACE_SYNC
@ FIELD_CAPABILITY_PERIODIC_STAGGERED_SYNC
@ FIELD_AVAILABILITY_WALL_MODEL
@ FIELD_AVAILABILITY_FINEST_LEVEL
@ FIELD_AVAILABILITY_PARTICLES
@ FIELD_AVAILABILITY_TURBULENCE
@ FIELD_AVAILABILITY_LES_DYNAMIC
@ FIELD_AVAILABILITY_ALWAYS
@ FIELD_SYNC_STANDARD
@ FIELD_SYNC_K_FACE
@ FIELD_SYNC_J_FACE
@ FIELD_SYNC_COMPONENT_STAGGERED
@ FIELD_SYNC_I_FACE
const FieldDescriptor * descriptor
FieldDMKind dm_kind
FieldLayout
Logical storage topology of a field.
@ FIELD_LAYOUT_K_FACE
@ FIELD_LAYOUT_I_FACE
@ FIELD_LAYOUT_CELL_CENTERED
@ FIELD_LAYOUT_COMPONENT_STAGGERED
@ FIELD_LAYOUT_NODE_CENTERED
@ FIELD_LAYOUT_J_FACE
const char * canonical_name
const char * alias_2
@ FIELD_DM_FDA
@ FIELD_DM_COORDINATES
@ FIELD_DM_DA
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_PSI
@ FIELD_ID_JETA
@ FIELD_ID_CENTZ
@ FIELD_ID_CSI
@ FIELD_ID_IAJ
@ FIELD_ID_CELL_SCALAR_AT_CORNER
@ FIELD_ID_NVERT
@ FIELD_ID_UCAT
@ FIELD_ID_NVERT_O
@ FIELD_ID_KETA
@ FIELD_ID_JAJ
@ FIELD_ID_COORDINATES
@ FIELD_ID_UCONT_O
@ FIELD_ID_KAJ
@ FIELD_ID_CELL_VECTOR_AT_CORNER
@ FIELD_ID_AJ
@ FIELD_ID_NU_T
@ FIELD_ID_CENTY
@ FIELD_ID_GRID_SPACE
@ FIELD_ID_KZET
@ FIELD_ID_IETA
@ FIELD_ID_DIFFUSIVITY_GRADIENT
@ FIELD_ID_UCONT
@ FIELD_ID_U_TAU
@ FIELD_ID_ICSI
@ FIELD_ID_POST_VECTOR
@ FIELD_ID_ETA
@ FIELD_ID_PHI
@ FIELD_ID_POST_SCALAR
@ FIELD_ID_NU_WALL
@ FIELD_ID_CS
@ FIELD_ID_CENT
@ FIELD_ID_QCRIT
@ FIELD_ID_JCSI
@ FIELD_ID_JZET
@ FIELD_ID_INVALID
@ FIELD_ID_P
@ FIELD_ID_IZET
@ FIELD_ID_UCONT_RM1
@ FIELD_ID_ZET
@ FIELD_ID_KCSI
@ FIELD_ID_CENTX
@ FIELD_ID_PARTICLE_COUNT
@ FIELD_ID_COUNT
@ FIELD_ID_DIFFUSIVITY
Immutable metadata for one field identity.
Non-owning runtime objects resolved for one field and UserCtx.
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1068