PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
 
Loading...
Searching...
No Matches
Boundaries.h
Go to the documentation of this file.
1#ifndef BOUNDARIES_H
2#define BOUNDARIES_H
3
4#include <petscpf.h>
5#include <petscdmswarm.h>
6#include <stdlib.h>
7#include <time.h>
8#include <math.h>
9#include <petsctime.h>
10#include <petscsys.h>
11#include <petscdmcomposite.h>
12#include <petscsystypes.h>
13
14// Include additional headers
15#include "variables.h" // Shared type definitions
16#include "field_catalog.h" // Typed Eulerian field identities
17#include "ParticleSwarm.h" // Particle swarm functions
18#include "walkingsearch.h" // Particle location functions
19#include "grid.h" // Grid functions
20#include "logging.h" // Logging macros
21#include "io.h" // Data Input and Output functions
22#include "interpolation.h" // Interpolation routines
23#include "ParticleMotion.h" // Functions related to motion of particles
24#include "BC_Handlers.h" // Boundary Handlers
25#include "wallfunction.h" // wall functions for LES
26//================================================================================
27//
28// PUBLIC SYSTEM-LEVEL FUNCTIONS
29//
30// These are the main entry points for interacting with the boundary system.
31//
32//================================================================================
33
34/**
35 * @brief (Public) Validates the consistency and compatibility of the parsed boundary condition system.
36 *
37 * This function is the main entry point for all boundary condition validation. It should be
38 * called from the main setup sequence AFTER the configuration file has been parsed by
39 * `ParseAllBoundaryConditions` but BEFORE any `BoundaryCondition` handler objects are created.
40 *
41 * It acts as a dispatcher, calling specialized private sub-validators for different complex
42 * BC setups (like driven flow) to ensure the combination of `mathematical_type` and `handler_type`
43 * across all six faces is physically and numerically valid. This provides a "fail-fast"
44 * mechanism to prevent users from running improperly configured simulations.
45 *
46 * @param user The UserCtx for a single block, containing the populated `boundary_faces` configuration.
47 * @return PetscErrorCode 0 on success, non-zero PETSc error code on failure.
48 */
49PetscErrorCode BoundarySystem_Validate(UserCtx *user);
50
51/**
52 * @brief (Private) Creates and configures a specific BoundaryCondition handler object.
53 *
54 * This function acts as a factory. Based on the requested handler_type, it allocates
55 * a BoundaryCondition object and populates it with the correct set of function
56 * pointers corresponding to that specific behavior.
57 *
58 * @param handler_type The specific handler to create (e.g., BC_HANDLER_WALL_NOSLIP).
59 * @param[out] new_bc_ptr A pointer to where the newly created BoundaryCondition
60 * object's address will be stored.
61 * @return PetscErrorCode 0 on success.
62 */
63
64PetscErrorCode BoundaryCondition_Create(BCHandlerType handler_type, BoundaryCondition **new_bc_ptr);
65
66/**
67 * @brief Initializes the entire boundary system.
68 *
69 * @param[in,out] user Finest-level block context receiving parsed face configuration.
70 * @param bcs_filename Path to the generated boundary-condition definition file.
71 * @return PetscErrorCode 0 on success.
72 */
73PetscErrorCode BoundarySystem_Initialize(UserCtx *user, const char *bcs_filename);
74
75/**
76 * @brief Propagates boundary condition configuration from finest to all coarser multigrid levels.
77 *
78 * Coarser levels need BC type information for geometric operations (e.g., periodic corrections)
79 * but do NOT need full handler objects since timestepping only occurs at the finest level.
80 * This function copies the boundary_faces configuration down the hierarchy.
81 *
82 * @param simCtx The master SimCtx containing the multigrid hierarchy
83 * @return PetscErrorCode 0 on success
84 */
86
87/**
88 * @brief Executes one full boundary condition update cycle for a time step.
89 *
90 * @param[in,out] user Block context whose boundary handlers update target values and fluxes.
91 * @return PetscErrorCode 0 on success.
92 */
93PetscErrorCode BoundarySystem_ExecuteStep(UserCtx *user);
94
95/**
96 * @brief (Private) A lightweight execution engine that calls the UpdateUbcs() method on all relevant handlers.
97 *
98 * This function's sole purpose is to re-evaluate the target boundary values (`ubcs`) for
99 * flow-dependent boundary conditions (e.g., Symmetry, Outlets) after the interior
100 * velocity field has changed, such as after the projection step.
101 *
102 * It operates based on a "pull" model: it iterates through all boundary handlers and
103 * executes their `UpdateUbcs` method only if the handler has provided one. This makes the
104 * system extensible, as new flow-dependent handlers can be added without changing this
105 * engine. Handlers for fixed boundary conditions (e.g., a wall with a constant velocity)
106 * will have their `UpdateUbcs` pointer set to `NULL` and will be skipped automatically.
107 *
108 * @note This function is a critical part of the post-projection refresh. It intentionally
109 * does NOT modify `ucont` and does NOT perform flux balancing.
110 *
111 * @param user The main UserCtx struct.
112 * @return PetscErrorCode 0 on success.
113 */
114PetscErrorCode BoundarySystem_RefreshUbcs(UserCtx *user);
115
116/**
117 * @brief Cleans up and destroys all boundary system resources.
118 *
119 * @param[in,out] user Block context whose boundary handlers and temporary state are released.
120 * @return PetscErrorCode 0 on success.
121 */
122PetscErrorCode BoundarySystem_Destroy(UserCtx *user);
123
124/**
125 * @brief Determines if the current MPI rank owns any part of the globally defined inlet face,
126 * making it responsible for placing particles on that portion of the surface.
127 *
128 * The determination is based on the rank's owned nodes (from `DMDALocalInfo`) and
129 * the global node counts, in conjunction with the `user->identifiedInletBCFace`.
130 * A rank can service an inlet face if it owns the cells adjacent to that global boundary
131 * and has a non-zero extent (owns cells) in the tangential dimensions of that face.
132 *
133 * @param user Pointer to the UserCtx structure, containing `identifiedInletBCFace`.
134 * @param info Pointer to the DMDALocalInfo for the current rank's DA (node-based).
135 * @param IM_nodes_global Global number of nodes in the I-direction (e.g., user->IM + 1 if user->IM is cell count).
136 * @param JM_nodes_global Global number of nodes in the J-direction.
137 * @param KM_nodes_global Global number of nodes in the K-direction.
138 * @param[out] can_service_inlet_out Pointer to a PetscBool; set to PETSC_TRUE if the rank
139 * services (part of) the inlet, PETSC_FALSE otherwise.
140 * @return PetscErrorCode 0 on success, non-zero on failure.
141 */
142PetscErrorCode CanRankServiceInletFace(UserCtx *user, const DMDALocalInfo *info,
143 PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global,
144 PetscBool *can_service_inlet_out);
145
146/**
147 * @brief Determines if the current MPI rank owns any part of a specified global face.
148 *
149 * This function is a general utility for parallel boundary operations. It checks if the
150 * local domain of the current MPI rank is adjacent to a specified global boundary face.
151 * A rank "services" a face if it owns the cells adjacent to that global boundary and has
152 * a non-zero extent (i.e., owns at least one cell) in the tangential dimensions of that face.
153 *
154 * @param info Pointer to the DMDALocalInfo for the current rank's DA.
155 * @param IM_nodes_global Global number of nodes in the I-direction (e.g., user->IM + 1 if user->IM is cell count).
156 * @param JM_nodes_global Global number of nodes in the J-direction.
157 * @param KM_nodes_global Global number of nodes in the K-direction.
158 * @param face_id The specific global face (e.g., BC_FACE_NEG_Z) to check.
159 * @param[out] can_service_out Pointer to a PetscBool; set to PETSC_TRUE if the rank
160 * services the face, PETSC_FALSE otherwise.
161 * @return PetscErrorCode 0 on success.
162 */
163PetscErrorCode CanRankServiceFace(const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global,
164 BCFace face_id, PetscBool *can_service_out);
165
166/**
167 * @brief Places particles in a deterministic grid/raster pattern on a specified domain face.
168 *
169 * This function creates a set of equidistant, parallel lines of particles near the four
170 * edges of the face specified by user->identifiedInletBCFace. The number of lines drawn
171 * from each edge is hardcoded within this function (default is 2).
172 * For example, if grid_layers=2 on face BC_FACE_NEG_X, the function will create particle lines at:
173 * - y ~ 0*dy, y ~ 1*dy (parallel to the Z-axis, starting from the J=0 edge)
174 * - y ~ y_max, y ~ y_max-dy (parallel to the Z-axis, starting from the J=max edge)
175 * - z ~ 0*dz, z ~ 1*dz (parallel to the Y-axis, starting from the K=0 edge)
176 * - z ~ z_max, z ~ z_max-dz (parallel to the Y-axis, starting from the K=max edge)
177 * The particle's final position is set just inside the target cell face to ensure it is
178 * correctly located. The total number of particles (simCtx->np) is distributed as evenly
179 * as possible among all generated lines.
180 * The function includes extensive validation to stop with an error if the requested grid
181 * placement is geometrically impossible (e.g., in a 2D domain or if layers would overlap).
182 * It also issues warnings for non-fatal but potentially unintended configurations.
183 *
184 * @param user Inlet-boundary context that defines the target face and grid layers.
185 * @param info Local ownership and ghost-range information.
186 * @param xs_gnode_rank Global xi node index at this rank's owned lower corner.
187 * @param ys_gnode_rank Global eta node index at this rank's owned lower corner.
188 * @param zs_gnode_rank Global zeta node index at this rank's owned lower corner.
189 * @param IM_cells_global Global number of xi cells.
190 * @param JM_cells_global Global number of eta cells.
191 * @param KM_cells_global Global number of zeta cells.
192 * @param particle_global_id Global particle ordinal used for deterministic placement.
193 * @param[out] ci_metric_lnode_out Local xi metric-node index of the chosen cell.
194 * @param[out] cj_metric_lnode_out Local eta metric-node index of the chosen cell.
195 * @param[out] ck_metric_lnode_out Local zeta metric-node index of the chosen cell.
196 * @param[out] xi_metric_logic_out Logical xi coordinate within the chosen cell.
197 * @param[out] eta_metric_logic_out Logical eta coordinate within the chosen cell.
198 * @param[out] zta_metric_logic_out Logical zeta coordinate within the chosen cell.
199 * @param[out] placement_successful_out PETSC_TRUE when this rank owns a valid placement.
200 * @return PetscErrorCode 0 on success.
201 */
203 UserCtx *user, const DMDALocalInfo *info,
204 PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank,
205 PetscInt IM_cells_global, PetscInt JM_cells_global, PetscInt KM_cells_global,
206 PetscInt64 particle_global_id,
207 PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out,
208 PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out,
209 PetscBool *placement_successful_out);
210
211
212/**
213 * @brief Assuming the current rank services the inlet face, this function selects a random
214 * cell (owned by this rank on that face) and random logical coordinates within that cell,
215 * suitable for placing a particle on the inlet surface.
216 *
217 * It is the caller's responsibility to ensure CanRankServiceInletFace returned true.
218 *
219 * @param user Pointer to UserCtx.
220 * @param info Pointer to DMDALocalInfo for the current rank (node-based).
221 * @param xs_gnode_rank Local i-start node index (including ghosts) for this rank.
222 * @param ys_gnode_rank Local j-start node index (including ghosts) for this rank.
223 * @param zs_gnode_rank Local k-start node index (including ghosts) for this rank.
224 * @param IM_nodes_global Global node count in i.
225 * @param JM_nodes_global Global node count in j.
226 * @param KM_nodes_global Global node count in k.
227 * @param rand_logic_i_ptr RNG handle for sampling local logical xi.
228 * @param rand_logic_j_ptr RNG handle for sampling local logical eta.
229 * @param rand_logic_k_ptr RNG handle for sampling local logical zta.
230 * @param[out] ci_metric_lnode_out Local i node index of selected cell origin.
231 * @param[out] cj_metric_lnode_out Local j node index of selected cell origin.
232 * @param[out] ck_metric_lnode_out Local k node index of selected cell origin.
233 * @param[out] xi_metric_logic_out Logical xi coordinate in [0,1].
234 * @param[out] eta_metric_logic_out Logical eta coordinate in [0,1].
235 * @param[out] zta_metric_logic_out Logical zta coordinate in [0,1].
236 * @return PetscErrorCode
237 */
239 UserCtx *user, const DMDALocalInfo *info,
240 PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, // Local starting node index (with ghosts) of the rank's DA patch
241 PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global,
242 PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr,
243 PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out,
244 PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out);
245
246/**
247 * @brief Classification of one staggered momentum row (location + component).
248 *
249 * @see ClassifyMomentumRow() for the meaning of each member and for the
250 * single-source-of-truth contract these values participate in.
251 */
252typedef enum {
253 MOM_ROW_PHYSICAL = 0, /**< Independent unknown governed by the momentum equation. */
254 MOM_ROW_FIXED_CONDITIONED, /**< Strong Dirichlet row; the value comes from ApplyBoundaryConditions(). */
255 MOM_ROW_FIXED_HOMOGENEOUS, /**< Dummy/tangential row carrying no unknown at all. */
256 MOM_ROW_PERIODIC_DUPLICATE /**< Duplicate of a wrapped representative row (see @p ri, @p rj, @p rk). */
258
259/**
260 * @brief Single source of truth for "which staggered momentum rows are unknowns".
261 *
262 * Every consumer of the momentum system must agree on which rows the solver is
263 * responsible for, and every consumer must derive that answer from this function
264 * rather than restating the index arithmetic locally. Three independent
265 * restatements previously disagreed, and the disagreement was silent: the
266 * residual assembly skipped the periodic duplicate column at index 0 while
267 * nothing zeroed it, so `ComputeTotalResidual()`'s BDF term accumulated there
268 * without bound and the reported residual norm stopped describing the state.
269 *
270 * The classification depends only on @p user->info, the configured boundary
271 * types, and the queried index; it reads no field data and performs no
272 * communication, so it is safe to call inside assembly loops.
273 *
274 * Periodicity of an axis is taken from that axis's NEGATIVE face, matching
275 * `ComputeRHS()` and `TransferPeriodicStaggeredFieldByDirection()`. A periodic
276 * axis is expected to carry PERIODIC on both of its faces.
277 *
278 * Callers act on the classification differently, and both actions are correct:
279 * - residual/pseudo-time consumers (`EnforceRHSBoundaryConditions()`) zero
280 * every non-physical row, because the value there is imposed immediately
281 * afterwards by the boundary sweep or the periodic synchronisation;
282 * - the matrix-free Newton path substitutes an explicit equation instead
283 * (`F = X - U_conditioned`, `F = X`, `F = X_dup - X_rep`), because a zeroed
284 * row would leave a zero Jacobian row.
285 *
286 * @param[in] user Block context supplying `info` and `boundary_faces`.
287 * @param[in] i Location index along xi.
288 * @param[in] j Location index along eta.
289 * @param[in] k Location index along zeta.
290 * @param[in] component Staggered component of the row (0 = xi, 1 = eta, 2 = zeta).
291 * @param[out] ri Representative xi index; equals @p i unless the row wraps.
292 * @param[out] rj Representative eta index; equals @p j unless the row wraps.
293 * @param[out] rk Representative zeta index; equals @p k unless the row wraps.
294 * @return The row classification. Only #MOM_ROW_PHYSICAL denotes an unknown.
295 */
296MomentumRowType ClassifyMomentumRow(UserCtx *user, PetscInt i, PetscInt j, PetscInt k,
297 PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk);
298
299/**
300 * @brief Reports whether a momentum row is masked out by the solid-cell field.
301 *
302 * `ComputeRHS()` zeroes the residual at a solid cell and at the staggered rows whose
303 * downstream neighbour is solid, so those rows carry no equation. A solver that only
304 * marches on the residual needs nothing more: a zero residual means no update. A solver
305 * that assembles a matrix and solves `F(X) = 0` does, because such a row has a zero
306 * Jacobian row and a zero column, leaving the unknown undetermined. Those rows must be
307 * constrained like any other row that carries no unknown.
308 *
309 * The condition mirrors the residual's own masking exactly. If one changes, so must the
310 * other, or the assembled operator stops matching the residual it preconditions.
311 *
312 * @param[in] nvert Ghosted solid-cell field, or NULL to apply no masking.
313 * @param[in] i Location index along xi.
314 * @param[in] j Location index along eta.
315 * @param[in] k Location index along zeta.
316 * @param[in] component Staggered component of the row (0 = xi, 1 = eta, 2 = zeta).
317 * @return `PETSC_TRUE` when the row is masked and therefore carries no unknown.
318 */
319PetscBool MomentumRowIsSolidMasked(const PetscReal ***nvert, PetscInt i, PetscInt j,
320 PetscInt k, PetscInt component);
321
322/**
323 * @brief Zeroes every momentum RHS row that does not carry an independent unknown.
324 *
325 * The set of such rows is not restated here: each owned location and component is
326 * asked of ClassifyMomentumRow(), and anything other than #MOM_ROW_PHYSICAL is
327 * zeroed. That covers, without enumerating them,
328 *
329 * - strong Dirichlet rows on non-periodic faces, so the time-stepping scheme
330 * cannot alter the values `ApplyBoundaryConditions()` has just set;
331 * - dummy layers at the far index of every axis, which hold no unknown; and
332 * - periodic duplicate columns, whose value the next
333 * `SynchronizePeriodicStaggeredFields()` copies from the wrapped master.
334 *
335 * The last case is the one that must not be skipped. `ComputeRHS()` leaves the
336 * transverse components of a periodic duplicate column untouched, so a row left
337 * unzeroed here retains its previous contents while `ComputeTotalResidual()`
338 * adds the BDF term on top of them on every call. The residual norm then grows
339 * by |dU|/dt per evaluation regardless of the state, and no pseudo-time
340 * iteration can reduce it.
341 *
342 * Call immediately after the RHS vector is fully assembled (spatial + temporal
343 * terms) and before it is used in a time-stepping update.
344 *
345 * @param user The UserCtx for the specific block being computed.
346 * @return PetscErrorCode 0 on success.
347 */
348PetscErrorCode EnforceRHSBoundaryConditions(UserCtx *user);
349
350/**
351 * @brief Synchronizes periodic endpoint cells for a list of cell-centered fields.
352 *
353 * The fields are first communicated from global to local storage. Each periodic
354 * direction is then transferred in i-j-k order, with an intermediate ghost
355 * refresh after every active direction so periodic edges and corners inherit the
356 * values established by earlier directions. Only global duplicate planes in active
357 * periodic directions are repaired; non-periodic directions are untouched. The
358 * routine is a no-op, including no local refresh, when every direction is
359 * nonperiodic. During active periodic synchronization it internally refreshes the
360 * local vectors, but it is not a general replacement for `UpdateLocalGhosts()`.
361 *
362 * Supported fields are selected by
363 * `FIELD_CAPABILITY_PERIODIC_CELL_SYNC` in the field catalog.
364 *
365 * @param user The main UserCtx struct.
366 * @param num_fields The number of entries in `field_ids`.
367 * @param field_ids The cell-centered fields to synchronize.
368 * @return PetscErrorCode 0 on success.
369 */
370PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[]);
371
372/**
373 * @brief Synchronizes persistent fields belonging to one face family.
374 *
375 * The function performs deterministic I/J/K directional passes with an
376 * intermediate ghost refresh after each active periodic direction. It updates
377 * persistent global seam/dummy values only; face-specific local stencil repair
378 * remains a separate operation.
379 *
380 * @param user The main UserCtx struct.
381 * @param face_direction Face family shared by every field (`'i'`, `'j'`, or `'k'`).
382 * @param[in] num_fields Count of registered face fields.
383 * @param field_ids Registered persistent face-field identities.
384 * @return PetscErrorCode 0 on success.
385 */
386PetscErrorCode SynchronizePeriodicFaceFields(UserCtx *user, char face_direction, PetscInt num_fields, const FieldId field_ids[]);
387
388/**
389 * @brief Synchronizes persistent component-staggered vector fields.
390 *
391 * The function performs deterministic I/J/K endpoint transfers with an
392 * intermediate ghost refresh after every active periodic direction. Currently
393 * `Ucont` is the only registered component-staggered field.
394 *
395 * @param user The main UserCtx struct.
396 * @param num_fields Number of entries in `field_ids`.
397 * @param field_ids Registered component-staggered field identities.
398 * @return PetscErrorCode 0 on success.
399 */
400PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields,
401 const FieldId field_ids[]);
402
403/**
404 * @brief Repairs the outer adjacent periodic ghosts used by QUICK cell stencils.
405 *
406 * The supplied local vectors must already contain a current PETSc periodic
407 * ghost exchange. The vector and scalar fields are repaired two logical cells
408 * across each active periodic seam so QUICK's `i-1/i+2` equivalents are valid.
409 *
410 * @param user Main block context containing periodic boundary metadata.
411 * @param local_vector_field Ghosted three-component cell-centered field.
412 * @param local_scalar_field Ghosted scalar cell-centered field.
413 * @return PetscErrorCode 0 on success.
414 */
415PetscErrorCode PreparePeriodicQuickStencilFields(UserCtx *user, Vec local_vector_field,
416 Vec local_scalar_field);
417
418/**
419 * @brief Synchronizes one local-only component-staggered periodic work field.
420 *
421 * This helper communicates locally computed owned entries, establishes the
422 * normal-component periodic endpoint values, and communicates once more.
423 *
424 * @param user Main block context containing periodic boundary metadata.
425 * @param local_field Ghosted local component-staggered vector.
426 * @return PetscErrorCode 0 on success.
427 */
428PetscErrorCode SynchronizePeriodicLocalStaggeredField(UserCtx *user, Vec local_field);
429
430/**
431 * @brief (Orchestrator) Updates all metric-related fields in the local ghost cell regions for periodic boundaries.
432 *
433 * This function synchronizes cell-centered `Aj` and the persistent I/J/K metric
434 * face families through the canonical MPI-safe synchronizers.
435 *
436 * @param user The main UserCtx struct.
437 * @return PetscErrorCode 0 on success.
438 */
439PetscErrorCode ApplyMetricsPeriodicBCs(UserCtx *user);
440
441/**
442 * @brief Applies periodic boundary conditions by copying data across domain boundaries for all relevant fields.
443 *
444 * This is the canonical periodic orchestrator for geometric consistency. It updates
445 * `Ucat`, `P`, and `Nvert` through the generic cell synchronizer and updates
446 * staggered `Ucont` through the component-staggered synchronizer.
447 *
448 * Future extension rule: add new periodic variables by extending the existing field
449 * string dispatchers and invoking them from this orchestrator.
450 *
451 * @param user The main UserCtx struct.
452 * @return PetscErrorCode 0 on success.
453 */
454PetscErrorCode ApplyPeriodicBCs(UserCtx *user);
455
456/**
457 * @brief Fills the dummy cells on the non-periodic faces of one cell-centred field.
458 *
459 * A cell-centred field stores cell `c` at index `c+1`; index 0 and the last index
460 * along each axis are dummy cells outside the domain. Stencils and node averages that
461 * reach across a boundary read them, so their value is the field's boundary condition:
462 *
463 * | Field | Dummy value | Condition it encodes |
464 * |--------|------------------------------|----------------------|
465 * | `Ucat` | `2 Ubcs - interior` | face average equals the handler's boundary velocity |
466 * | `P` | the adjacent interior cell | zero normal gradient |
467 * | `Psi` | the adjacent interior cell | zero normal gradient (no scalar flux) |
468 *
469 * Any other field is refused: its condition must be chosen for the quantity before its
470 * dummy cells are filled (see @ref p60_stats_boundary_sec for why no default serves
471 * every quantity).
472 *
473 * **Pressure.** Zero gradient is the condition the pressure solve already implies on
474 * every non-periodic face: the Poisson operator drops each boundary face's term, the
475 * dummy rows are identities with a zero right-hand side, and the projection corrects
476 * interior faces only. Nothing in the solve reads these values; filling them makes
477 * `P_nodal` and near-wall pressure gradients (the Cabot wall model) consistent with that
478 * condition, instead of averaging in a dummy value that stays at its initial zero. A
479 * pressure boundary condition (a far field, or a pressure outlet) will set its dummy
480 * value here as well, but that alone changes nothing the solve sees; see
481 * @ref p57_pressure_bc_sec for what has to change with it.
482 *
483 * Periodic faces are skipped: the periodic synchronizers own them. Only the flat part
484 * of each face is written (shrunken loop ranges); edges and corners are filled
485 * afterwards by `UpdateCornerNodes` from these values.
486 *
487 * @param user Block context supplying the layout, face types, and `Ubcs`.
488 * @param field_id Cell-centred field to fill: `FIELD_ID_UCAT`, `FIELD_ID_P`, or `FIELD_ID_PSI`.
489 * @return Zero on success; `PETSC_ERR_ARG_WRONG` for a field that is not cell-centred,
490 * `PETSC_ERR_SUP` for one with no boundary rule.
491 */
492PetscErrorCode UpdateDummyCells(UserCtx *user, FieldId field_id);
493
494/**
495 * @brief Fills the edge and corner dummy cells of one cell-centred field by averaging.
496 *
497 * Call after the face dummy cells are final, both periodic (the periodic
498 * synchronizers) and non-periodic (`UpdateDummyCells`). Each edge dummy cell becomes the
499 * mean of its two face-adjacent dummy cells; the edges along the Z faces are done
500 * first, so the corners the remaining edges pass through are averaged from finished
501 * edges. The rule is the same whatever the adjacent face types are.
502 *
503 * @param user Block context supplying the layout.
504 * @param field_id Cell-centred field whose edges and corners are filled.
505 * @return Zero on success; `PETSC_ERR_ARG_WRONG` for a field that is not cell-centred.
506 */
507PetscErrorCode UpdateCornerNodes(UserCtx *user, FieldId field_id);
508
509/**
510 * @brief Applies wall function modeling to near-wall velocities for all wall-type boundaries.
511 *
512 * This function implements log-law wall functions to model the near-wall velocity profile
513 * without fully resolving the viscous sublayer. It is applicable to ALL wall-type boundaries
514 * regardless of their specific boundary condition (no-slip, moving wall, slip, etc.), as
515 * determined by the mathematical_type being WALL.
516 *
517 * MATHEMATICAL BACKGROUND:
518 * Wall functions bridge the gap between the wall (y=0) and the first computational cell
519 * center by using empirical log-law relationships:
520 * - Viscous sublayer (y+ < 11.81): u+ = y+
521 * - Log-law region (y+ > 11.81): u+ = (1/κ) * ln(E * y+)
522 * where u+ = u/u_τ, y+ = y*u_τ/ν, κ = 0.41 (von Karman constant), E = exp(κB)
523 *
524 * IMPLEMENTATION DETAILS:
525 * Unlike standard boundary conditions that set ghost cell values, wall functions:
526 * 1. Read velocity from the SECOND interior cell (i±2, j±2, k±2)
527 * 2. Compute wall shear stress using log-law
528 * 3. Modify velocity at the FIRST interior cell (i±1, j±1, k±1)
529 * 4. Keep ghost cell boundary values (ubcs, ucont) at zero
530 *
531 * WORKFLOW:
532 * - Called from ApplyBoundaryConditions after standard BC application
533 * - Operates on ucat (Cartesian velocity)
534 * - Updates ustar (friction velocity field) for diagnostics/turbulence models
535 * - Ghost cells remain zero; UpdateDummyCells handles extrapolation afterward
536 *
537 * GEOMETRIC QUANTITIES:
538 * sb = wall-normal distance from wall to first interior cell center
539 * sc = wall-normal distance from wall to second interior cell center
540 * These are computed from cell Jacobians (aj) and face area vectors
541 *
542 * APPLICABILITY:
543 * - Requires simCtx->wallfunction = true
544 * - Only processes faces where mathematical_type == WALL
545 * - Skips solid-embedded cells (nvert >= 0.1)
546 *
547 * @param user The UserCtx containing all simulation state and geometry
548 * @return PetscErrorCode 0 on success
549 *
550 * @note This function modifies interior cell velocities, NOT ghost cells
551 * @note Wall roughness (ks) is currently set to 1e-16 (smooth wall)
552 * @see wall_function_loglaw() in wallfunction.c for the actual log-law implementation
553 * @see noslip() in wallfunction.c for the initial linear interpolation
554 */
555PetscErrorCode ApplyWallFunction(UserCtx *user);
556
557/**
558 * @brief Appends one row of near-wall statistics to `<run.analysis.metrics>/wall_model.csv`.
559 *
560 * Reduces the state @ref ApplyWallFunction accumulated over the wall faces this rank owns
561 * and writes the run-wide row from rank 0. `y+` is the column that matters: it says
562 * whether the first cell sits where the selected law is valid, and no stored field can
563 * answer that after the fact.
564 *
565 * A no-op when no wall model is active. When a wall model is active but no cell was
566 * corrected - wall functions enabled on a case with no WALL face - it warns and writes
567 * nothing rather than emitting a row of zeros.
568 *
569 * Collective on the block's communicator; call it on every rank, once per step, after
570 * @ref ApplyWallFunction.
571 *
572 * @param[in] user Block context whose wall-model pass has already run this step.
573 * @return PetscErrorCode 0 on success.
574 */
575PetscErrorCode LogWallModelDiagnostics(UserCtx *user);
576
577/**
578 * @brief Finalizes cell-centered fields after the projection step.
579 *
580 * This function completes the cell-centered state derived from the final,
581 * divergence-free `Ucont` produced by `Projection`. It fills non-periodic
582 * `Ucat` dummy faces, synchronizes periodic `Ucat` and `P` endpoints, resolves
583 * edges and corners, and refreshes the corresponding local vectors.
584 *
585 * This function is fundamentally different from `ApplyBoundaryConditions`: it
586 * does NOT modify `Ucont`, reapply wall functions, or rerun the full physical
587 * boundary-condition workflow.
588 *
589 * WORKFLOW:
590 * 1. Refreshes local `Ucat` and any flow-dependent `Ubcs` targets.
591 * 2. Fills non-periodic dummy faces and establishes periodic cell endpoints.
592 * 3. Resolves edges/corners, restores exact periodic relationships, and refreshes
593 * local `Ucat` and `P`.
594 *
595 * @param user The main UserCtx struct, containing all simulation state.
596 * @return PetscErrorCode 0 on success.
597 */
598PetscErrorCode FinalizePostProjectionCellFields(UserCtx *user);
599
600/**
601 * @brief Main boundary-condition orchestrator executed during solver timestepping.
602 *
603 * This routine performs the full BC workflow for the current block, including
604 * dynamic boundary refresh, periodic transfer, dummy/corner updates, and optional
605 * wall-function corrections in the same order expected by the runtime solver.
606 * It may iterate boundary updates to enforce coupled boundary dependencies.
607 *
608 * @param user The main UserCtx struct containing field vectors and boundary system state.
609 * @return PetscErrorCode 0 on success.
610 */
611PetscErrorCode ApplyBoundaryConditions(UserCtx *user);
612
613#endif // BOUNDARIES_H
PetscErrorCode ApplyPeriodicBCs(UserCtx *user)
Applies periodic boundary conditions by copying data across domain boundaries for all relevant fields...
PetscErrorCode PreparePeriodicQuickStencilFields(UserCtx *user, Vec local_vector_field, Vec local_scalar_field)
Repairs the outer adjacent periodic ghosts used by QUICK cell stencils.
MomentumRowType
Classification of one staggered momentum row (location + component).
Definition Boundaries.h:252
@ MOM_ROW_FIXED_HOMOGENEOUS
Dummy/tangential row carrying no unknown at all.
Definition Boundaries.h:255
@ MOM_ROW_PHYSICAL
Independent unknown governed by the momentum equation.
Definition Boundaries.h:253
@ MOM_ROW_PERIODIC_DUPLICATE
Duplicate of a wrapped representative row (see ri, rj, rk).
Definition Boundaries.h:256
@ MOM_ROW_FIXED_CONDITIONED
Strong Dirichlet row; the value comes from ApplyBoundaryConditions().
Definition Boundaries.h:254
PetscErrorCode BoundarySystem_Initialize(UserCtx *user, const char *bcs_filename)
Initializes the entire boundary system.
Definition Boundaries.c:876
PetscErrorCode GetRandomCellAndLogicalCoordsOnInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscRandom *rand_logic_i_ptr, PetscRandom *rand_logic_j_ptr, PetscRandom *rand_logic_k_ptr, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out)
Assuming the current rank services the inlet face, this function selects a random cell (owned by this...
Definition Boundaries.c:400
PetscErrorCode ApplyWallFunction(UserCtx *user)
Applies wall function modeling to near-wall velocities for all wall-type boundaries.
MomentumRowType ClassifyMomentumRow(UserCtx *user, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
Single source of truth for "which staggered momentum rows are unknowns".
Definition Boundaries.c:597
PetscErrorCode PropagateBoundaryConfigToCoarserLevels(SimCtx *simCtx)
Propagates boundary condition configuration from finest to all coarser multigrid levels.
Definition Boundaries.c:973
PetscErrorCode ApplyMetricsPeriodicBCs(UserCtx *user)
(Orchestrator) Updates all metric-related fields in the local ghost cell regions for periodic boundar...
PetscErrorCode EnforceRHSBoundaryConditions(UserCtx *user)
Zeroes every momentum RHS row that does not carry an independent unknown.
Definition Boundaries.c:686
PetscErrorCode UpdateDummyCells(UserCtx *user, FieldId field_id)
Fills the dummy cells on the non-periodic faces of one cell-centred field.
PetscErrorCode LogWallModelDiagnostics(UserCtx *user)
Appends one row of near-wall statistics to <run.analysis.metrics>/wall_model.csv.
PetscErrorCode BoundarySystem_RefreshUbcs(UserCtx *user)
(Private) A lightweight execution engine that calls the UpdateUbcs() method on all relevant handlers.
PetscErrorCode SynchronizePeriodicLocalStaggeredField(UserCtx *user, Vec local_field)
Synchronizes one local-only component-staggered periodic work field.
PetscBool MomentumRowIsSolidMasked(const PetscReal ***nvert, PetscInt i, PetscInt j, PetscInt k, PetscInt component)
Reports whether a momentum row is masked out by the solid-cell field.
Definition Boundaries.c:655
PetscErrorCode BoundarySystem_Validate(UserCtx *user)
(Public) Validates the consistency and compatibility of the parsed boundary condition system.
Definition Boundaries.c:815
PetscErrorCode BoundaryCondition_Create(BCHandlerType handler_type, BoundaryCondition **new_bc_ptr)
(Private) Creates and configures a specific BoundaryCondition handler object.
Definition Boundaries.c:729
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode CanRankServiceInletFace(UserCtx *user, const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, PetscBool *can_service_inlet_out)
Determines if the current MPI rank owns any part of the globally defined inlet face,...
Definition Boundaries.c:11
PetscErrorCode ApplyBoundaryConditions(UserCtx *user)
Main boundary-condition orchestrator executed during solver timestepping.
PetscErrorCode FinalizePostProjectionCellFields(UserCtx *user)
Finalizes cell-centered fields after the projection step.
PetscErrorCode UpdateCornerNodes(UserCtx *user, FieldId field_id)
Fills the edge and corner dummy cells of one cell-centred field by averaging.
PetscErrorCode CanRankServiceFace(const DMDALocalInfo *info, PetscInt IM_nodes_global, PetscInt JM_nodes_global, PetscInt KM_nodes_global, BCFace face_id, PetscBool *can_service_out)
Determines if the current MPI rank owns any part of a specified global face.
Definition Boundaries.c:127
PetscErrorCode GetDeterministicFaceGridLocation(UserCtx *user, const DMDALocalInfo *info, PetscInt xs_gnode_rank, PetscInt ys_gnode_rank, PetscInt zs_gnode_rank, PetscInt IM_cells_global, PetscInt JM_cells_global, PetscInt KM_cells_global, PetscInt64 particle_global_id, PetscInt *ci_metric_lnode_out, PetscInt *cj_metric_lnode_out, PetscInt *ck_metric_lnode_out, PetscReal *xi_metric_logic_out, PetscReal *eta_metric_logic_out, PetscReal *zta_metric_logic_out, PetscBool *placement_successful_out)
Places particles in a deterministic grid/raster pattern on a specified domain face.
Definition Boundaries.c:213
PetscErrorCode BoundarySystem_ExecuteStep(UserCtx *user)
Executes one full boundary condition update cycle for a time step.
PetscErrorCode SynchronizePeriodicFaceFields(UserCtx *user, char face_direction, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent fields belonging to one face family.
PetscErrorCode BoundarySystem_Destroy(UserCtx *user)
Cleans up and destroys all boundary system resources.
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
Header file for Particle Motion and migration related functions.
Header file for Particle Swarm management functions.
Authoritative identities and storage metadata for persistent Eulerian fields.
FieldId
Compile-time identity for a catalogued Eulerian field.
Public interface for grid, solver, and metric setup routines.
Public interface for data input/output routines.
Logging utilities and macros for PETSc-based applications.
The "virtual table" struct for a boundary condition handler object.
Definition variables.h:377
Main header file for a complex fluid dynamics solver.
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:329
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:287
The master context for the entire simulation.
Definition variables.h:859
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1074
Header file for particle location functions using the walking search algorithm.