flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
block_container.hpp File Reference

flow — VoF Part III rung W0: the per-bubble VoF BLOCK, a third container over the same L1 kernels (suite/docs/VOF_PLAN.md §10, the TBFsolver vofBlock pattern). More...

#include <algorithm>
#include <array>
#include <cmath>
#include <cstdio>
#include <Kokkos_Core.hpp>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
#include "mac_stencils.hpp"
#include "peclet/core/decomp/block_decomposer.hpp"
#include "vof/advect_wy.hpp"
#include "vof/block_batch.hpp"
#include "vof/colour_field.hpp"
#include "vof/curvature_field.hpp"
#include "vof/surface_tension.hpp"
#include "policy.hpp"

Go to the source code of this file.

Classes

struct  peclet::flow::vof::VofBox
 Half-open global cell box [lo, hi). More...
 
struct  peclet::flow::vof::VofRun
 One contiguous run of GLOBAL indices covered by a block's index range on one axis, with the block-local index the run starts at. More...
 
struct  peclet::flow::vof::VofBlockStats
 Per-block Lagrangian census, computed on the master (VOF_PLAN §10 W1 outputs, available at W0). More...
 
class  peclet::flow::vof::VofBlock
 One bubble's block. More...
 
struct  peclet::flow::vof::VofBlockExchangeBase
 Gather / scatter / table replication. More...
 
class  peclet::flow::vof::VofBlockSet
 The container: a replicated table of blocks, the per-step orchestration (gather → advect → re-centre → scatter/union) and the per-bubble statistics. More...
 
struct  peclet::flow::vof::VofBlockSet::DebrisJob
 One block's share of the batched sums (raw pointers: the table rides in the functor). More...
 
struct  peclet::flow::vof::VofBlockSet::DebrisTable
 

Namespaces

namespace  peclet
 
namespace  peclet::flow
 
namespace  peclet::flow::vof
 

Enumerations

enum class  peclet::flow::vof::VofMasterAssign { peclet::flow::vof::RoundRobin = 0 , peclet::flow::vof::Lpt = 1 , peclet::flow::vof::WeightedOrb = 2 }
 How a block's MASTER rank is chosen. More...
 

Functions

int peclet::flow::vof::vofAxisRuns (int a, int b, int gs, bool periodic, VofRun out[5], int outside=0)
 Decompose [a, b) on one axis into global runs.
 
VofBox peclet::flow::vof::vofClampBox (VofBox b, I3 gs, const std::array< bool, 3 > &per)
 Clamp a block box so it is representable: at most the whole axis on a periodic axis, inside the domain on a non-periodic one.
 
void peclet::flow::vof::vofAssignLpt (const std::vector< long > &w, int size, std::vector< int > &master)
 Longest-processing-time greedy (Graham 1969): heaviest block first onto the currently least-loaded rank, ties to the LOWEST rank id.
 
void peclet::flow::vof::vofAssignOrb (const std::vector< long > &w, int size, std::vector< int > &master)
 Weighted ORB over a 1-D block space: the blocks are laid out as a 1-D "grid" of N cells in block-id order carrying their weights, and core::decomp::BlockDecomposer<1> recursively bisects it into size CONTIGUOUS runs of balanced weight.
 

Detailed Description

flow — VoF Part III rung W0: the per-bubble VoF BLOCK, a third container over the same L1 kernels (suite/docs/VOF_PLAN.md §10, the TBFsolver vofBlock pattern).

What a block is, and why

One bubble = one WyAdvector on a small dense global index box, plus a master rank that owns it. The global colour the closures see is the union C = max_blocks C_block, never the source. Because each marker is transported on its own field, two bubbles that touch cannot coalesce numerically — coalescence becomes an explicit model decision (rung W4) instead of a numerical accident of a single global colour field. That is the whole point of the container; everything else here is bookkeeping.

Lineage: Cifani et al., Computers & Fluids 2018 (TBFsolver, src/VOF/vofBlocks.f90) — moving bounding box = bubble extent + a 3-cell offset, a master rank assigned independently of the flow decomposition, gather u to the master, run the whole VoF pipeline on the dense block, scatter back with UNPACK_MAX. Also Coyajee & Boersma JCP 2009 and Balcázar et al. IJHFF 2015 (multiple-marker VoF/CLSVOF). Nothing is transcribed from TBFsolver; the kernels are the suite's own L1 set (peclet::core::vof) and the advection is Weymouth–Yue, not TBFsolver's implicit-in-sweep scheme.

The three index boxes (get these right and the rest follows)

bubble box tight bounding box of the cells this block's colour is > 0 INNER box bubble box grown by margin (= 3) on every side — the advector's inner region EXTENDED box inner box grown by ghost (= 3) — the advector's extended block

so the extended block reaches 6 cells beyond the bubble, exactly TBFsolver's offset. All three are in GLOBAL cell indices and may hang outside [0, gs) on a periodic axis (the gather wraps).

Why margin 3 is what makes the block conservative. One advect() runs one sweep per axis, so colour moves at most ONE cell along any axis per step. With the nonzero colour ≥ 3 cells from the inner-box boundary at the start of a step, nothing can reach the boundary and be fluxed across it, so no liquid ever leaves the block and Σ C over the inner box is conserved by the same telescoping argument the global field enjoys. Re-centring (below) restores the margin every time it is spent.

Ghost policy of a block (the reason G1 can be BITWISE)

A block's extended-box cells that lie inside the domain but outside its inner box carry no colour of this marker (C = 0, the continuous phase) — that is what the margin guarantees — so the ghost fill writes 0 there, which is exactly the value the global-field advector holds at the same global cells. Cells outside the domain on a non-periodic axis take the globally-clamped (zero-gradient) value, the same rule colour_field.hpp::clampFill applies to the structured field. A block whose box spans a whole periodic axis gets the periodic wrap on that axis instead. The face velocities are gathered from the owners of the same global cells — outside a non-periodic domain too, from the ghost layers of the boundary rank, because the low domain face lives there (gate W) — so every double the block's WY update consumes is bit-for-bit the double the global-field update consumes — hence gate G1 is a bitwise gate and not a tolerance.

What lives where

This header is MPI-free and container-agnostic index math + orchestration. The gather/scatter (which needs the flow decomposition and MPI) is vof/block_exchange.hpp; it is injected through VofBlockExchangeBase so this file compiles in the single-rank module unchanged.

Definition in file block_container.hpp.