|
PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
|
This page is the detailed reference for boundary-condition authoring in case.yml. It documents what is currently supported by the Python conductor and what is currently wired in C.
case.yml -> boundary_conditions supports:
Face names:
-Xi, +Xi, -Eta, +Eta, -Zeta, +ZetaEvery block must provide all six faces exactly once.
The validator accepts these type/handler pairs:
| Type | Handler | Required params | Optional params | Units expected in YAML |
|---|---|---|---|---|
WALL | noslip | none | none | n/a |
INLET | constant_velocity | vx, vy, vz | none | m/s |
INLET | parabolic | v_max | none | m/s |
INLET | prescribed_flow | source | source.type: file, generated, or field_slice | m/s scalar speeds, generator params, or old-field slice params |
OUTLET | conservation | none | none | n/a |
PERIODIC | geometric | none | none | n/a |
PERIODIC | constant_flux | target_flux | enforce_seam_flux | m^3/s |
PERIODIC | initial_flux | none | enforce_seam_flux | n/a |
Notes:
params.vector and params.velocity are rejected; use scalar vx/vy/vz,constant_flux or initial_flux) must be configured, with the same handler, on both faces of the periodic pair.constant_flux and initial_flux are the same controller wired to different targets, and choosing between them is a question of where the flux comes from.
constant_flux** drives to a flux you prescribe. target_flux is required, and it is a volumetric flux - U_b times the cross-sectional area - not a velocity. Use it when the flux is the thing you are specifying, for instance to match a literature bulk Reynolds number. The target is re-read from the bcs file on every run, so editing it between restart segments takes effect.initial_flux** drives to the flux it measures from the field the run starts with, and then holds that. It takes no target_flux; supplying one is a configuration error rather than something quietly ignored, because the two handlers would otherwise be indistinguishable in a case file. Use it when you have seeded a field whose flux is already what you want - a developed field carried in from a precursor - and you want it preserved rather than restated. The measured target is written to the checkpoint and restored on restart, so a resumed run holds the original target instead of re-measuring a drifted one.enforce_seam_flux is optional on both and defaults to false (apply_trim is accepted as a deprecated alias). It enables a second, local actuator: on top of the body force that sustains the flow everywhere, it adds a correction directly into the face fluxes of the single periodic seam plane to hold the flux through that plane on target. Off by default because it can reintroduce divergence the pressure solve just removed and because it injects the noisy single-plane flux signal into the solution at one location. The correction is recorded in Bcs.Uch whether or not it is applied, so you can inspect whether you need it before enabling it. Full rationale: 5.3 The seam trim (enforce_seam_flux).
Full treatment of the control law, the update cadence and its consequences for both momentum solvers, the restart contract, and the worked validation cases: 5. Driven Periodic Flows.
picurv converts physical BC values to solver-scale values before writing bcs.run:
\[ v^* = \frac{v}{U_{ref}}, \qquad Q^* = \frac{Q}{U_{ref} L_{ref}^{2}}. \]
Specifically:
vx/vy/vz/v_max are divided by properties.scaling.velocity_ref,prescribed_flow PICSLICE scalar speeds are divided by properties.scaling.velocity_ref while staging the solver-side .picslice,target_flux is divided by velocity_ref * length_ref^2.prescribed_flow uses a face-scoped canonical PICSLICE file. It can be supplied directly with source.type: file, generated analytically with source.type: generated, or sliced from an old ufield*.dat with source.type: field_slice. The Python conductor resolves the face/grid context and delegates dimensional profile writes to generators/profile.gen. Generated and field-sliced sources may set optional source.script to a compatible case-relative or absolute override:
The second line is the frame count. Static prescribed profiles require 1. Values are positive scalar speed magnitudes normal to the inlet surface, not Cartesian velocity components and not contravariant fluxes. The C handler uses the existing inlet face sign and metric conversion to populate Ucont and Ubcs.
Expected dimensions follow the existing inlet face loop order:
-Xi/+Xi: (KM - 1, JM - 1), ordered (k, j)-Eta/+Eta: (KM - 1, IM - 1), ordered (k, i)-Zeta/+Zeta: (JM - 1, IM - 1), ordered (j, i)For a case with 64 x 64 x 1024 cells, the corresponding profile dimensions are 64 x 64 for -Zeta/+Zeta, 1024 x 64 for -Xi/+Xi, and 1024 x 64 for -Eta/+Eta.
Copy-paste file-backed inlet example:
For multi-block cases, keep using the existing list-of-lists boundary_conditions shape. Each block face can reference its own .picslice; picurv stages one solver-scale file per block face and writes source_file=... into that block's bcs_block*.run.
Generated profiles currently support analytical square-duct Poiseuille flow:
The face selects the two transverse dimensions automatically:
-Xi/+Xi: (KM - 1, JM - 1), ordered (k, j)-Eta/+Eta: (KM - 1, IM - 1), ordered (k, i)-Zeta/+Zeta: (JM - 1, IM - 1), ordered (j, i)For grid.mode: grid_gen, picurv run --solve generates the grid first, then reads the generated PICGRID header to size the profile. For grid.mode: file, it reads the source PICGRID header. Generated dimensional profiles and profile.info are written under the run config/ directory, then the staged solver-scale .picslice is referenced from bcs.run.
For square_duct_poiseuille, bulk_velocity is the target inlet bulk speed. When a canonical target PICGRID is available, picurv evaluates the analytical profile at target inlet face centers and rescales it using geometric quad face areas so sum(u * area) / sum(area) matches bulk_velocity. profile.info records the normalization mode, sampling mode, area-weighted mean before and after normalization, total inlet area, face-area range, and discrete sample mean. If no target grid is available yet, generation falls back to continuous-area normalization on uniform logical sample points. Exact C metric-vector area matching is a future refinement; the current Python path uses geometric quad areas from the target grid coordinates.
Field-sliced profiles reuse an existing Cartesian velocity field as a new inlet:
field_slice reads old Ucat, computes source and target face normals from canonical PICGRID geometry, projects dot(Ucat, n_hat) to a scalar normal speed, and writes a dimensional .sliced.picslice. orientation: opposite means the old outward normal and new inlet outward normal must oppose each other; use orientation: same only when both outward normals should align. The extractor fails if normal compatibility or flow sign checks fail. V1 requires exact source/target slice dimension matches and does not interpolate.
Validator checks:
(-Xi,+Xi), (-Eta,+Eta), (-Zeta,+Zeta) are both periodic or both non-periodic.constant_flux or initial_flux) must match on both faces of a periodic pair.The C side derives periodic axes from those pairs in DeterminePeriodicity, before DMDA creation. There are no independent YAML periodic flags.
For each active axis, ValidatePeriodicGeometry also requires:
These rules are checked independently for mixed periodic/non-periodic cases. PETSc periodic DMDAs wrap indices; PICurv separately constructs translated coordinate images and synchronizes cell-centered, face-family, and component-staggered Eulerian fields. Particle periodic wrapping is not implemented.
Generated bcs.run lines use:
C ingestion path:
StringToBCFace, StringToBCType, StringToBCHandlerType convert tokens.ValidateBCHandlerForBCType enforces type-handler compatibility.boundary_faces is the canonical in-memory representation. Do not restore or maintain duplicate persistent legacy BC arrays in UserCtx. If a future low-level integration genuinely needs a translated view, add a narrow on-demand adapter only when a concrete consumer exists.
Current factory-wired handlers include:
Important contributor note:
BC_HANDLER_INLET_INTERP_FROM_FILE, which is declared but implemented nowhere),source.type: field_slice is Python-side preprocessing only: it creates the same staged source_file contract used by file-backed and generated profiles.If you add a new BC mode, update all three layers in one change:
picurv_cli/core.py),Constant-velocity inlet + outlet conservation:
Driven periodic flux on Xi:
: malformed BC entry object. -Duplicate face: same face declared twice in one block. -incomplete ... Missing faces: not all 6 faces provided. -Inconsistent periodicity: one side periodic and opposite side non-periodic. -Periodic geometry validation failed: paired surfaces do not differ by one constant nonzero translation, or the periodic axis is too short. -Unknown params`: extra keys not allowed for selected handler.This page describes Boundary Conditions Guide within the PICurv workflow. For CFD users, the most reliable reading strategy is to map the page content to a concrete run decision: what is configured, what runtime stage it influences, and which diagnostics should confirm expected behavior.
Treat this page as both a conceptual reference and a runbook. If you are debugging, pair the method/procedure described here with monitor output, generated runtime artifacts under runs/<run_id>/config, and the associated solver/post logs so numerical intent and implementation behavior stay aligned.