|
PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
|
This page documents the first field-infrastructure phase: separate typed identity and metadata catalogs for persistent Eulerian and solver-particle fields. The catalogs remove repeated field-name dispatch from ghost updates, periodic synchronization, field diagnostics, initialization, and Eulerian/particle coupling without changing vector creation, numerical stencil/repair algorithms, checkpoint formats, runtime configuration, or postprocessing recipe syntax.
Phase 1 adds:
FieldId, a compile-time identity for each field formerly recognized by UpdateLocalGhosts;FieldDescriptor, immutable metadata describing name, aliases, degree of freedom, DM family, grid layout, ghost-repair class, availability conditions, capabilities, and the existing UserCtx vector binding;FieldView, a non-owning runtime view of an already-created DM/global/local vector tuple;The Eulerian catalog covers the 38 persistent fields supported by the previous ghost dispatcher. The separate particle catalog covers the ten persistent DMSwarm fields used by the solver, including PETSc-managed particle ID and rank fields. Adding a field to a supported operation now requires metadata and a typed call site rather than another string branch.
Field IDs are not assigned after PETSc vector creation. They are enum constants known when the program is compiled. Storage is still created by the existing setup lifecycle:
Particle identities are likewise compile-time constants. During RegisterParticleFields, PICurv-owned descriptors drive the existing DMSwarm registration helper; PETSc-owned DMSwarm_pid and DMSwarm_rank descriptors are recorded but deliberately not re-registered. Particle IDs do not depend on particle allocation order or on the number of local particles.
This separation is deliberate. FieldId identifies a concept, while FieldView reports whether that concept has storage in a particular UserCtx. Optional fields remain valid catalog entries even when their runtime conditions are disabled; asking for their view then returns a wrong-state error instead of silently dereferencing a null PETSc object.
Each FieldDescriptor records:
| Member | Meaning |
|---|---|
id | Typed identity used by compiled consumers |
canonical_name | Stable printable/configuration-facing name |
alias_1, alias_2 | Existing accepted names resolved only at ingress |
dof | PETSc degrees of freedom per DMDA entry: 1, 2, or 3 |
dm_kind | da, fda, fda2, or PETSc coordinate storage |
layout | node, shifted cell, I/J/K face, or component-staggered |
sync_class | normal-face repair policy after global-to-local scatter |
availability | setup conditions under which storage may exist |
capabilities | operations for which the field is registered |
| vector offsets | binding to the existing global/local UserCtx members |
The availability flags describe requirements; they do not replace runtime state validation. FieldGetView always checks the actual DM and vector handles.
ParticleFieldDescriptor is separate because DMSwarm fields have a different contract: canonical PETSc name, component count, PetscDataType, registration owner, default initialization value, supported operations, and an optional Eulerian scatter target. In particular, particle Psi maps explicitly to Eulerian FIELD_ID_PSI; no name coincidence is used to infer that bridge.
The registered aliases are retained because current diagnostic and boundary surfaces use them: Eddy Viscosity for Nu_t, Cs for CS, Center-Coordinates for Cent, and the X/Y/Z-Face-Centers names for Centx/Centy/Centz. Aliases do not create additional field identities.
The catalog's topology is based on the solver's shifted/staggered architecture, not just PETSc's owned-versus-ghosted partition.
| Catalog layout | Physical interpretation | Logical boundary convention |
|---|---|---|
FIELD_LAYOUT_NODE_CENTERED | grid nodes | direct indices; the extra high-side slot is not a physical node |
FIELD_LAYOUT_CELL_CENTERED | cell-centered value | physical values occupy shifted indices 1..N-1; indices 0 and N are boundary/dummy locations |
FIELD_LAYOUT_I_FACE | one I-face family | node-like in I, cell-like in J and K |
FIELD_LAYOUT_J_FACE | one J-face family | node-like in J, cell-like in I and K |
FIELD_LAYOUT_K_FACE | one K-face family | node-like in K, cell-like in I and J |
FIELD_LAYOUT_COMPONENT_STAGGERED | Ucont-style packed vector | x/y/z components live on I/J/K faces respectively |
Therefore, a local vector may contain two different categories that must not be confused:
UpdateLocalGhosts still calls the established DMGlobalToLocalBegin/End pair. It then uses sync_class, instead of a field name, to select the existing normal-face repair for I-, J-, K-face, or packed component-staggered storage. Standard shifted-cell fields retain the same PETSc scatter behavior.
Periodicity does not create a second identity for a field. It changes the runtime DM topology and which physical boundary repairs are active:
InitializeAllGridDMs still constructs the actual periodic/nonperiodic DMDA;UserCtx;Boundaries.c are unchanged.The periodic cell, single-face-family, and component-staggered synchronizers now accept FieldId arrays. Catalog capabilities reject a field routed to an incompatible synchronizer before the unchanged numerical copy loop runs. Coordinate-face translation is selected through FIELD_CAPABILITY_PERIODIC_GEOMETRY_SHIFT, not a field-name comparison. No string comparison remains in the periodic field dispatcher.
The initial catalog groups fields as follows:
Coordinates;Ucat, P, Nu_t, CS, Diffusivity, DiffusivityGradient, Nvert, Aj, Cent, GridSpace, Phi, Psi, Nvert_o, ParticleCount, K_Omega, and K_Omega_o;Ucont, Ucont_o, and Ucont_rm1;Csi, Centx, ICsi, IEta, IZet, and IAj;Eta, Centy, JCsi, JEta, JZet, and JAj;Zet, Centz, KCsi, KEta, KZet, and KAj.K_Omega entries preserve the compiled RANS call surface, but the catalog does not claim that the current setup path allocates their storage. The runtime view check makes that state explicit.
The particle inventory is: position, velocity, DMSwarm_CellID, weight, Diffusivity, DiffusivityGradient, Psi, DMSwarm_location_status, DMSwarm_pid, and DMSwarm_rank. It is intentionally not mixed into FieldId: particle fields are per-particle DMSwarm arrays, may be integer-valued, and have no persistent UserCtx global/local Vec pair. Dynamic postprocessor fields such as recipe-created ske or disp remain outside the persistent solver-particle catalog.
Compiled code should pass IDs directly:
Code that genuinely receives text should resolve it once at its ingress:
Consumers must not cache a FieldView beyond the lifetime or re-creation of the corresponding UserCtx PETSc objects. A view is non-owning and must never be destroyed independently.
PETSc's DMSwarm API itself remains name-based. Code at that API boundary obtains the canonical text with ParticleFieldName; this does not require assigning particle fields an Eulerian FieldId or wrapping every PETSc access function. Generic gather/restart/output helpers also remain name-based for dynamic postprocessor fields, but query the registered PetscDataType from DMSwarm instead of inferring integer width from a field-name comparison.
This phase does not:
CreateAndInitializeAllVectors, setup ordering, or teardown ordering;Runtime configuration strings and postprocessing recipe keywords are true text ingress and remain textual. Function identity/profiling is intentionally deferred to a later specification; it is not conflated with field identity.
These boundaries prevent a common-infrastructure change from silently becoming a numerical, monitoring, I/O, or statistics change.
make unit-setup contains direct catalog tests for:
FieldId;Psi/Eulerian-Psi bridge;Existing unit-periodic, MPI, postprocessing, and runtime smoke tests remain the behavioral regressions for the unchanged numerical paths.