|
chombo-discharge
|
Arena-backed Struct-of-Arrays particle container for a single grid patch. More...
#include <CD_ParticleSoA.H>

Public Member Functions | |
Construction and lifetime | |
| ParticleSoA ()=default | |
| Construct an empty container. | |
| ~ParticleSoA () | |
| Destructor (frees the arena). | |
| ParticleSoA (const ParticleSoA &)=delete | |
| Copy construction is deleted (move-only). | |
| ParticleSoA & | operator= (const ParticleSoA &)=delete |
| Copy assignment is deleted (move-only). | |
| ParticleSoA (ParticleSoA &&a_other) noexcept | |
| Move constructor (steals the arena). | |
| ParticleSoA & | operator= (ParticleSoA &&a_other) noexcept |
| Move assignment (steals the arena). | |
| ParticleSoA | deepCopy () const |
| Explicit deep copy: a new container with a private arena duplicating every particle. | |
| void | deepCopyTo (ParticleSoA &a_dst) const |
| Deep copy into an existing destination, reusing its arena when possible. | |
| void | swap (ParticleSoA &a_other) noexcept |
| Swap the entire state (arena, size, capacity, sort) with another container in O(1). | |
Size and capacity | |
| std::size_t | size () const noexcept |
| Number of particles currently stored. | |
| std::size_t | capacity () const noexcept |
| Allocated capacity in particles. | |
| bool | empty () const noexcept |
| Whether the container holds no particles. | |
| void | clear () noexcept |
| Drop all particles (keeps the arena; invalidates the cell sort). | |
| void | reserve (const std::size_t a_capacity) |
| Ensure capacity for at least a_capacity particles (reallocates + moves on growth). | |
| void | resize (const std::size_t a_count) |
| Set the particle count (grows capacity if needed; new slots are uninitialized). | |
| void | shrinkToFit () |
| Reclaim unused capacity by reallocating the arena down to the current size. | |
Population | |
| void | append (const RealVect &a_position, const double a_weight) |
| Append one particle with a default-constructed payload. | |
| void | append (const RealVect &a_position, const double a_weight, const P &a_payload) |
| Append one particle with the given payload. | |
| void | append (const ParticleSoA &a_other) |
| Append every particle of another container (bulk catenate; all columns, incl. id/rank). | |
| void | appendParticle (const ParticleSoA &a_src, const std::size_t a_index) |
| Append a single particle (all columns, incl. id/rank) copied from another container. | |
| void | catenate (ParticleSoA &a_other) |
| Move every particle of another container into this one, leaving a_other empty (catenate). | |
| P | gather (const std::size_t a_index) const |
| Gather particle i's payload back into the AoS payload view. | |
| void | remove (const std::size_t a_index) noexcept |
| Remove particle i using swap-and-pop (O(1), does NOT preserve order). | |
Column and field access | |
| template<std::size_t K> | |
| ColumnType< K > * | columnByIndex () noexcept |
| Typed base pointer of column K (low-level). | |
| template<std::size_t K> | |
| const ColumnType< K > * | columnByIndex () const noexcept |
| Const typed base pointer of column K (low-level). | |
| template<auto Member> | |
| auto * | column () noexcept |
| Whole payload column selected by member pointer (raw pointer, vectorizable). | |
| template<auto Member> | |
| const auto * | column () const noexcept |
| Const whole payload column selected by member pointer. | |
| template<auto Member> | |
| auto & | get (const std::size_t a_index) noexcept |
| One particle's payload field selected by member pointer. | |
| template<auto Member> | |
| const auto & | get (const std::size_t a_index) const noexcept |
| Const overload of get<&P::field>(i). | |
| double * | positionColumn (const int a_dir) noexcept |
| Raw position component column dir (double*, for SIMD kernels). | |
| const double * | positionColumn (const int a_dir) const noexcept |
| Const raw position component column dir. | |
| double * | weightColumn () noexcept |
| Raw weight column (double*). | |
| const double * | weightColumn () const noexcept |
| Const raw weight column. | |
Raw arena and bulk transfer | |
| const void * | data () const noexcept |
| Raw arena pointer (column-major); a compact container's whole data span. | |
| void * | data () noexcept |
| Mutable raw arena pointer (e.g. zero-copy MPI receive into the arena). | |
| std::size_t | byteSpan () const noexcept |
| Byte span of the live data (for a compact container, one contiguous memcpy/MPI_Send). | |
Cell sorting (CSR) | |
| void | sortByCell (const Box &a_box, const RealVect &a_dx, const RealVect &a_probLo) |
| Counting-sort the columns into Fortran cell order and build CSR cell offsets. | |
| bool | isSorted () const noexcept |
| Whether the container is currently cell-sorted (false after append/remove). | |
| bool | isSortedAgainst (const Box &a_box, const RealVect &a_dx, const RealVect &a_probLo) const noexcept |
| Whether the container is cell-sorted against exactly this cell domain. | |
| std::size_t | numCells () const noexcept |
| Number of cells in the CSR sort (0 if not sorted). | |
| std::size_t | cellStart (const std::size_t a_cell) const noexcept |
| CSR start offset of cell c (valid after sortByCell; requires c <= numCells()). | |
| std::size_t | particlesInCell (const std::size_t a_cell) const noexcept |
| Number of particles in cell c (valid after sortByCell). | |
| std::pair< std::size_t, std::size_t > | cellRange (const std::size_t a_cell) const noexcept |
| Half-open particle index range [begin, end) owned by cell c (valid after sortByCell). | |
| void | extractCell (const std::size_t a_cell, ParticleSoA &a_out) const |
| Extract cell c's particles (the CSR range [cellStart(c), cellStart(c+1))) into a_out. | |
Protected Member Functions | |
| std::size_t | cellKey (const std::size_t a_index, const Box &a_box, const RealVect &a_dx, const RealVect &a_probLo) const noexcept |
| Compute the Fortran (x-fastest) cell index of particle i within the sort domain. | |
| bool | checkCellSort (const Box &a_box, const RealVect &a_dx, const RealVect &a_probLo) const noexcept |
| Verify that the CSR mapping really does describe the current particle positions. | |
| void | steal (ParticleSoA &a_o) noexcept |
| Steal another container's arena (move helper). | |
| void | growTo (const std::size_t a_needed) |
| Grow the arena to hold at least a_needed particles, geometrically. | |
| void | growIfFull () |
| Grow geometrically if the container is full (called before writing slot m_size). | |
| template<std::size_t... I> | |
| std::size_t | computeOffsets (const std::size_t a_capacity, std::array< std::size_t, s_numColumns > &a_off, std::index_sequence< I... >) const noexcept |
| Compute per-column byte offsets for a given capacity; returns the total bytes. | |
| template<std::size_t... I> | |
| void | setColPtrs (const std::array< std::size_t, s_numColumns > &a_off, std::index_sequence< I... >) noexcept |
| Cache the column base pointers from a fresh buffer + offsets. | |
| template<std::size_t... I> | |
| void | moveColumns (void *a_newBuf, const std::array< std::size_t, s_numColumns > &a_off, std::index_sequence< I... >) noexcept |
| Contiguously memcpy every column's live region into a freshly-allocated buffer. | |
| template<std::size_t... I> | |
| void | copyLiveColumnsTo (ParticleSoA &a_dst, std::index_sequence< I... >) const noexcept |
| Copy this container's m_size live elements of every column into another container. | |
| template<std::size_t... I> | |
| void | appendColumnsFrom (const ParticleSoA &a_other, const std::size_t a_at, std::index_sequence< I... >) noexcept |
| Bulk-append another container's live columns at slot a_at of this container's columns. | |
| template<std::size_t... I> | |
| void | copyParticleColumns (const ParticleSoA &a_src, const std::size_t a_srcIdx, const std::size_t a_dstIdx, std::index_sequence< I... >) noexcept |
| Copy one particle's every column from a_src[a_srcIdx] into this[a_dstIdx]. | |
| void | reallocate (const std::size_t a_capacity) |
| Allocate a new arena and reallocate/move the columns into it (growth path). | |
| void | permute (const std::vector< std::size_t > &a_dest) |
| Reorder every column in place by a_dest (a_dest[i] = new slot of old particle i). | |
| template<std::size_t K> | |
| void | scatterColumn (void *a_newBuf, const std::size_t a_off, const std::vector< std::size_t > &a_dest) noexcept |
| Per-column scatter for permute(): newcol[dest[i]] = oldcol[i]. | |
| template<std::size_t... I> | |
| void | scatterColumns (void *a_newBuf, const std::array< std::size_t, s_numColumns > &a_off, const std::vector< std::size_t > &a_dest, std::index_sequence< I... >) noexcept |
| Scatter every column for permute() into a freshly-allocated buffer. | |
| template<std::size_t... J> | |
| void | writePayload (const P &a_p, std::index_sequence< J... >) noexcept |
| Write the payload columns of slot m_size from a payload struct. | |
| template<std::size_t... J> | |
| P | gatherPayload (const std::size_t a_index, std::index_sequence< J... >) const |
| Read the payload columns of slot a_index into a payload struct. | |
| template<std::size_t... I> | |
| void | removeImpl (const std::size_t a_index, std::index_sequence< I... >) noexcept |
| Swap-and-pop slot a_index in every column. | |
| template<std::size_t... I> | |
| void | linearizeImpl (unsigned char *a_buf, const std::size_t a_index, std::index_sequence< I... >) const noexcept |
| Push every column of particle a_index onto a byte buffer (MPI). | |
| template<std::size_t... I> | |
| void | delinearizeImpl (const unsigned char *a_buf, std::index_sequence< I... >) noexcept |
| Pull every column of one particle off a byte buffer into slot m_size (MPI). | |
| template<std::size_t K> | |
| void | pullColumn (const unsigned char *&a_buf) noexcept |
| Pull one column's value off a byte buffer into slot m_size and advance the pointer. | |
| template<std::size_t... J> | |
| void | h5LinearizePayload (unsigned char *&a_buf, const std::size_t a_index, std::index_sequence< J... >) const noexcept |
| Push the HDF5 payload subset of particle a_index onto a byte buffer. | |
| template<std::size_t... J> | |
| void | h5DelinearizePayload (const unsigned char *&a_buf, std::index_sequence< J... >) noexcept |
| Pull the HDF5 payload subset off a byte buffer into slot m_size. | |
| template<std::size_t... I> | |
| std::size_t | byteSpanImpl (std::index_sequence< I... >) const noexcept |
| Byte span of the live data: max over columns of (offset + used bytes). | |
Static Protected Member Functions | |
| static std::size_t | alignUp (const std::size_t a_x) noexcept |
| Round a_x up to the next multiple of s_align. | |
| template<std::size_t... J> | |
| static constexpr std::size_t | h5PayloadSize (std::index_sequence< J... >) noexcept |
| Compile-time byte size of the HDF5 payload subset. | |
Protected Attributes | |
| void * | m_buffer = nullptr |
| The single arena allocation. | |
| std::size_t | m_capacity = 0 |
| Capacity in particles. | |
| std::size_t | m_bytes = 0 |
| Byte size of the arena at m_buffer (zero when m_buffer is null). | |
| std::size_t | m_size = 0 |
| Live particle count. | |
| bool | m_sorted = false |
| Whether m_cellStart is valid. | |
| std::array< void *, s_numColumns > | m_colPtrs {} |
| Cached column base pointers into m_buffer. | |
| std::vector< std::size_t > | m_cellStart |
| CSR cell offsets (size numCells+1 when sorted). | |
| Box | m_sortBox |
| Patch box the CSR mapping in m_cellStart was built against (meaningful only when m_sorted). | |
| RealVect | m_sortDx = RealVect::Zero |
| Grid spacing the CSR mapping was built against (meaningful only when m_sorted). | |
| RealVect | m_sortProbLo = RealVect::Zero |
| Lower domain corner the CSR mapping was built against (meaningful only when m_sorted). | |
Compile-time layout (indices and sizes) | |
| using | PayloadColumns = std::remove_cv_t< std::remove_reference_t< decltype(Traits::columns)> > |
| The payload columns descriptor tuple type (tuple of pointer-to-member). | |
| static constexpr std::size_t | s_numPayloadColumns = std::tuple_size<PayloadColumns>::value |
| Number of user-declared payload columns. | |
| static constexpr std::size_t | s_weightCol = SpaceDim |
| Column index of the weight (immediately after the SpaceDim position columns). | |
| static constexpr std::size_t | s_idCol = SpaceDim + 1 |
| Column index of the container-owned particleID. | |
| static constexpr std::size_t | s_rankCol = SpaceDim + 2 |
| Column index of the container-owned rankID. | |
| static constexpr std::size_t | s_ghostCol = SpaceDim + 3 |
| Column index of the container-owned ghost designation. | |
| static constexpr std::size_t | s_payloadBegin = SpaceDim + 4 |
| Index of the first payload column. | |
| static constexpr std::size_t | s_numColumns = s_payloadBegin + s_numPayloadColumns |
| Total number of columns (SpaceDim position + weight + id + rank + ghost + payload). | |
| static constexpr std::size_t | s_align = 64 |
| Cache-line alignment for each column (also enables aligned SIMD). | |
Compile-time layout (value types) | |
| using | ColumnValueTuple = decltype(std::tuple_cat(std::declval< MandatoryValues >(), std::declval< PayloadValues >())) |
| The value types of every column, in storage order. | |
| template<std::size_t K> | |
| using | ColumnType = std::tuple_element_t< K, ColumnValueTuple > |
| Value type of column K. | |
| using | H5PayloadColumns = typename detail::H5ColumnSubset< Traits, std::make_index_sequence< s_numPayloadColumns > >::Type |
| The HDF5 payload column subset (indices into the payload columns). | |
| template<typename M > | |
| static constexpr std::size_t | columnIndex (const M a_member) noexcept |
| Derive the column index of a PAYLOAD member pointer (reorder-safe selector). | |
Mandatory-field accessors | |
| static constexpr ParticleID | s_invalidID = -1 |
| Sentinel for an unassigned/invalid global particle id. | |
| RealVect | position (const std::size_t a_index) const noexcept |
| Position of particle i as a RealVect (by value, assembled from the scalar columns). | |
| void | setPosition (const std::size_t a_index, const RealVect &a_position) noexcept |
| Set the position of particle i. | |
| double & | weight (const std::size_t a_index) noexcept |
| Weight of particle i. | |
| const double & | weight (const std::size_t a_index) const noexcept |
| Const weight of particle i. | |
| ParticleID & | particleID (const std::size_t a_index) noexcept |
| Global id of particle i (container-owned metadata). | |
| const ParticleID & | particleID (const std::size_t a_index) const noexcept |
| Const global id of particle i. | |
| RankID & | rankID (const std::size_t a_index) noexcept |
| Owning rank of particle i (container-owned metadata). | |
| const RankID & | rankID (const std::size_t a_index) const noexcept |
| Const owning rank of particle i. | |
| GhostType & | ghost (const std::size_t a_index) noexcept |
| Ghost designation of particle i (container-owned metadata). | |
| const GhostType & | ghost (const std::size_t a_index) const noexcept |
| Const ghost designation of particle i. | |
| bool | isGhost (const std::size_t a_index) const noexcept |
| Whether particle i is a ghost particle (any non-Valid designation). | |
MPI linearization | |
| static constexpr std::size_t | bytesPerParticle () noexcept |
| Byte count of one fully-linearized particle (all columns, for MPI). | |
| void | linearizeParticle (void *a_buffer, const std::size_t a_index) const noexcept |
| Linearize particle i into a byte buffer (all columns, for MPI send). | |
| void | delinearizeAndAppend (const void *a_buffer) |
| Append a particle delinearized from a byte buffer (all columns, for MPI receive). | |
HDF5 linearization | |
| static constexpr std::size_t | h5BytesPerParticle () noexcept |
| Bytes for one HDF5-linearized particle (position + weight + h5 payload subset). | |
| void | h5LinearizeParticle (void *a_buffer, const std::size_t a_index) const noexcept |
| Linearize the HDF5-checkpointed columns of particle i (no id/rank). | |
| void | h5DelinearizeAndAppend (const void *a_buffer) |
| Append a particle whose HDF5-checkpointed columns come from a buffer. | |
Arena-backed Struct-of-Arrays particle container for a single grid patch.
See the file-level documentation for the data model, the container-owned mandatory columns, and the recipe for defining a payload type.
append(pos, weight, payload) adds a particle (grows geometrically); remove(i) deletes particle i by swap-and-pop (O(1), does NOT preserve order). The canonical remove loop does not advance i on a removal:
append/remove/reserve invalidate raw pointers from column()/positionColumn(). Capacity never shrinks (clear() keeps it); the container is meant to be reused across steps.
sortByCell(box,dx,probLo) counting-sorts the columns into Fortran cell order and builds a CSR offsets array, so cell c owns the contiguous range [cellStart(c), cellStart(c+1)). Append/remove invalidate the sort (isSorted()).
linearizeParticle()/delinearizeAndAppend() pack/unpack ALL columns (incl. id/rank) for MPI. h5LinearizeParticle()/h5DelinearizeAndAppend() handle the HDF5 subset (position + weight + the payload h5Columns; never id/rank). data()/byteSpan() expose the raw arena for a one-memcpy / zero-copy whole-container transfer.
| P | User payload struct (extra columns only); defaults to NoPayload. |
| Traits | Column descriptor for the payload; defaults to ParticleTraits |
.
|
inlinenoexcept |
Move constructor (steals the arena).
| [in,out] | a_other | Source container, left empty after the move. |
|
inlinestaticprotectednoexcept |
Round a_x up to the next multiple of s_align.
| [in] | a_x | Value to round up. |
|
inline |
Append every particle of another container (bulk catenate; all columns, incl. id/rank).
Copies a_other's live particles onto the end of this container with a per-column memcpy (one reservation, then column-wise bulk copies). Unlike the single-particle append(), this PRESERVES the particleID/rankID metadata as well as position/weight/payload. Invalidates the cell sort. Appending a container to itself is supported.
| [in] | a_other | Source container whose particles are appended. |
|
inline |
Append one particle with a default-constructed payload.
The metadata columns (id/rank) are set to s_invalidID/-1; assign them via particleID(i)/rankID(i) afterwards, or let the AMR layer / delinearize set them.
| [in] | a_position | Particle position. |
| [in] | a_weight | Particle weight. |
|
inline |
Append one particle with the given payload.
The metadata columns (id/rank) are set to s_invalidID/-1; assign them via particleID(i)/rankID(i) afterwards, or let the AMR layer / delinearize set them.
| [in] | a_position | Particle position. |
| [in] | a_weight | Particle weight. |
| [in] | a_payload | Payload columns for this particle. |
|
inlineprotectednoexcept |
Bulk-append another container's live columns at slot a_at of this container's columns.
Per-column memcpy of a_other's m_size live elements into this container starting at element index a_at. This container must already have capacity >= a_at + a_other.size(). Disjoint source/destination (even when a_other == this, since the new slots lie past the existing ones).
| I | Column indices [0, s_numColumns). |
| [in] | a_other | Source container. |
| [in] | a_at | First destination element index (the size before appending). |
|
inline |
Append a single particle (all columns, incl. id/rank) copied from another container.
The single-particle analogue of append(const ParticleSoA&). Pair it with remove() on the source to move one particle between containers. Invalidates the cell sort. Appending from self is supported.
| [in] | a_src | Source container to copy from. |
| [in] | a_index | Index of the particle in a_src to copy. |
|
inlinenoexcept |
Byte span of the live data (for a compact container, one contiguous memcpy/MPI_Send).
|
inlineprotectednoexcept |
Byte span of the live data: max over columns of (offset + used bytes).
| I | Column indices [0, s_numColumns). |
|
inlinestaticconstexprnoexcept |
Byte count of one fully-linearized particle (all columns, for MPI).
|
inlinenoexcept |
Allocated capacity in particles.
|
inline |
Move every particle of another container into this one, leaving a_other empty (catenate).
The move counterpart of append(const ParticleSoA&): appends all of a_other's particles (all columns, incl. id/rank) and then clears a_other. When this container is empty the two arenas are swapped instead, so the common "drain into an empty destination" case is O(1) with zero copy. Invalidates the cell sort. Catenating a container into itself is a no-op.
| [in,out] | a_other | Source container, left empty afterwards. |
|
inlineprotectednoexcept |
Compute the Fortran (x-fastest) cell index of particle i within the sort domain.
Shared by sortByCell() and its debug-mode verifier so the two can never disagree about the mapping. Positions outside the box are clamped to the boundary cells.
| [in] | a_index | Particle index. |
| [in] | a_box | Patch box defining the cells. |
| [in] | a_dx | Grid spacing per direction. |
| [in] | a_probLo | Physical coordinate of the lower domain corner. |
|
inlinenoexcept |
Half-open particle index range [begin, end) owned by cell c (valid after sortByCell).
Convenience over cellStart(c)/cellStart(c+1); the cell's particles are the contiguous indices [first, second).
| [in] | a_cell | Cell index. |
|
inlinenoexcept |
CSR start offset of cell c (valid after sortByCell; requires c <= numCells()).
| [in] | a_cell | Cell index. |
|
inlineprotectednoexcept |
Verify that the CSR mapping really does describe the current particle positions.
The sort flag is only as good as the invalidation of every mutating path, so sortByCell() asserts on this whenever it takes its early-out: it recomputes each particle's cell key and checks that the particle sits in that cell's CSR range. O(N), and compiled out with the assertion in optimized builds. A failure here means some path moved particles without clearing m_sorted.
| [in] | a_box | Patch box defining the cells. |
| [in] | a_dx | Grid spacing per direction. |
| [in] | a_probLo | Physical coordinate of the lower domain corner. |
|
inlinenoexcept |
Const whole payload column selected by member pointer.
| Member | Member pointer selecting the payload column. |
|
inlinenoexcept |
Whole payload column selected by member pointer (raw pointer, vectorizable).
| Member | Member pointer selecting the payload column. |
|
inlinenoexcept |
Const typed base pointer of column K (low-level).
| K | Column index. |
|
inlinenoexcept |
Typed base pointer of column K (low-level).
| K | Column index. |
|
inlinestaticconstexprnoexcept |
Derive the column index of a PAYLOAD member pointer (reorder-safe selector).
| M | Pointer-to-member type of the payload field. |
| [in] | a_member | Member pointer selecting the payload column. |
|
inlineprotectednoexcept |
Compute per-column byte offsets for a given capacity; returns the total bytes.
| I | Column indices [0, s_numColumns). |
| [in] | a_capacity | Capacity (in particles) the columns are sized for. |
| [out] | a_off | Filled with the byte offset of each column. |
|
inlineprotectednoexcept |
Copy this container's m_size live elements of every column into another container.
Per-column copy (the two arenas may have different capacities, hence different layouts, so a single whole-arena memcpy is not valid). a_dst must already have capacity >= m_size.
| I | Column indices [0, s_numColumns). |
| [in,out] | a_dst | Destination container (its column pointers are written). |
|
inlineprotectednoexcept |
Copy one particle's every column from a_src[a_srcIdx] into this[a_dstIdx].
Per-column single-element copy. Both indices must be in range and this must have capacity for a_dstIdx.
| I | Column indices [0, s_numColumns). |
| [in] | a_src | Source container. |
| [in] | a_srcIdx | Source particle index. |
| [in] | a_dstIdx | Destination particle index in this container. |
|
inlinenoexcept |
Raw arena pointer (column-major); a compact container's whole data span.
|
inlinenoexcept |
Mutable raw arena pointer (e.g. zero-copy MPI receive into the arena).
|
inline |
Explicit deep copy: a new container with a private arena duplicating every particle.
Copy construction and copy assignment are deleted (they would alias the single arena); call this when an independent copy of all the particles is genuinely wanted (rather than moving them). The cell-sort state (isSorted() + the CSR cell offsets) is preserved, so a cell-sorted container copies as cell-sorted.
|
inline |
Deep copy into an existing destination, reusing its arena when possible.
Like deepCopy() but writes into a_dst instead of returning a new container. a_dst's existing allocation is reused when it is already large enough (grown only if it is too small), which avoids a malloc when copying repeatedly into the same destination. a_dst is overwritten with an independent copy of every particle, and its cell-sort state is set to match this container. Copying onto self is a no-op.
| [in,out] | a_dst | Destination container, overwritten with a copy of every particle. |
|
inline |
Append a particle delinearized from a byte buffer (all columns, for MPI receive).
| [in] | a_buffer | Buffer with at least bytesPerParticle() bytes. |
|
inlineprotectednoexcept |
Pull every column of one particle off a byte buffer into slot m_size (MPI).
| I | Column indices [0, s_numColumns). |
| [in] | a_buf | Buffer holding one linearized particle. |
|
inlinenoexcept |
Whether the container holds no particles.
|
inline |
Extract cell c's particles (the CSR range [cellStart(c), cellStart(c+1))) into a_out.
a_out is cleared first, then this cell's particles are appended (all columns, including id/rank). Requires the container to be cell-sorted. This is the building block of the per-cell extract->process->rebuild idiom that replaces the AoS BinFab<List<P>> per-cell pattern: extract a cell into a reusable scratch container, mutate it (append/remove), accumulate it into an output container via append(const ParticleSoA&), and finally swap() the output into the leaf. See ItoSolver::makeSuperparticles for the canonical use.
| [in] | a_cell | Cell index. |
| [out] | a_out | Destination scratch container (cleared on entry; reuse it across cells). |
|
inline |
Gather particle i's payload back into the AoS payload view.
| [in] | a_index | Particle index. |
|
inlineprotected |
Read the payload columns of slot a_index into a payload struct.
| J | Payload-column indices [0, s_numPayloadColumns). |
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Const overload of get<&P::field>(i).
| Member | Member pointer selecting the payload column. |
| [in] | a_index | Particle index. |
|
inlinenoexcept |
One particle's payload field selected by member pointer.
| Member | Member pointer selecting the payload column. |
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Const ghost designation of particle i.
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Ghost designation of particle i (container-owned metadata).
| [in] | a_index | Particle index. |
|
inlineprotected |
Grow the arena to hold at least a_needed particles, geometrically.
The growth policy for every append path, and deliberately NOT folded into reserve(): reserve() sets the capacity EXACTLY, and exactly one caller needs that for correctness. deepCopy() sizes the destination to the SOURCE's capacity and then flat-memcpy()s byteSpan() across in one go, which is only valid while both arenas compute the same per-column offsets – and those offsets are derived from the capacity. Rounding the capacity up there would silently copy the columns to the wrong places. The remaining exact-sizing callers do not depend on the layout: resize() and deepCopyTo() simply want the capacity they asked for rather than a doubled one, deepCopyTo() copying column by column and so needing only capacity >= m_size.
An append that called reserve(m_size + n) directly would leave capacity == size on return, so the very next append would reallocate and recopy the whole arena – turning the extract->mutate->accumulate idiom extractCell() documents as canonical into O(N^2) copying, since the accumulating container is grown one cell at a time.
| [in] | a_needed | Number of particles the arena must be able to hold. |
|
inlinestaticconstexprnoexcept |
Bytes for one HDF5-linearized particle (position + weight + h5 payload subset).
|
inline |
Append a particle whose HDF5-checkpointed columns come from a buffer.
id/rank are set invalid and non-checkpointed payload columns default-constructed.
| [in] | a_buffer | Buffer with at least h5BytesPerParticle() bytes. |
|
inlineprotectednoexcept |
Pull the HDF5 payload subset off a byte buffer into slot m_size.
| J | Payload-column indices in the HDF5 subset. |
| [in,out] | a_buf | Buffer pointer, advanced as columns are read. |
|
inlinenoexcept |
Linearize the HDF5-checkpointed columns of particle i (no id/rank).
| [in,out] | a_buffer | Buffer with at least h5BytesPerParticle() bytes. |
| [in] | a_index | Particle index. |
|
inlineprotectednoexcept |
Push the HDF5 payload subset of particle a_index onto a byte buffer.
| J | Payload-column indices in the HDF5 subset. |
| [in,out] | a_buf | Buffer pointer, advanced as columns are written. |
| [in] | a_index | Particle index. |
|
inlinestaticconstexprprotectednoexcept |
Compile-time byte size of the HDF5 payload subset.
| J | Payload-column indices in the HDF5 subset. |
|
inlinenoexcept |
Whether particle i is a ghost particle (any non-Valid designation).
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Whether the container is currently cell-sorted (false after append/remove).
|
inlinenoexcept |
Whether the container is cell-sorted against exactly this cell domain.
isSorted() only says that some CSR mapping is valid; this says it is the mapping the caller is about to index with. sortByCell() early-outs on precisely this condition.
| [in] | a_box | Patch box defining the cells. |
| [in] | a_dx | Grid spacing per direction. |
| [in] | a_probLo | Physical coordinate of the lower domain corner. |
|
inlineprotectednoexcept |
Push every column of particle a_index onto a byte buffer (MPI).
| I | Column indices [0, s_numColumns). |
| [in,out] | a_buf | Buffer pointer, advanced as columns are written. |
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Linearize particle i into a byte buffer (all columns, for MPI send).
| [in,out] | a_buffer | Buffer with at least bytesPerParticle() bytes. |
| [in] | a_index | Particle index. |
|
inlineprotectednoexcept |
Contiguously memcpy every column's live region into a freshly-allocated buffer.
| I | Column indices [0, s_numColumns). |
| [out] | a_newBuf | Destination arena buffer. |
| [in] | a_off | Per-column byte offsets into a_newBuf. |
|
inlinenoexcept |
Number of cells in the CSR sort (0 if not sorted).
|
delete |
Copy assignment is deleted (move-only).
|
inlinenoexcept |
Move assignment (steals the arena).
| [in,out] | a_other | Source container, left empty after the move. |
|
inlinenoexcept |
Const global id of particle i.
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Global id of particle i (container-owned metadata).
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Number of particles in cell c (valid after sortByCell).
| [in] | a_cell | Cell index. |
|
inlineprotected |
Reorder every column in place by a_dest (a_dest[i] = new slot of old particle i).
| [in] | a_dest | Destination slot for each current particle. |
|
inlinenoexcept |
Position of particle i as a RealVect (by value, assembled from the scalar columns).
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Const raw position component column dir.
| [in] | a_dir | Spatial direction in [0, SpaceDim). |
|
inlinenoexcept |
Raw position component column dir (double*, for SIMD kernels).
Handing out a writable position column invalidates the cell sort: the caller may move particles across cell boundaries, and the container cannot observe that. The sort flag is therefore cleared here rather than on the (unobservable) write, which is what lets sortByCell() trust the flag and skip a re-sort. Use the const overload for read-only kernels to keep the sort.
| [in] | a_dir | Spatial direction in [0, SpaceDim). |
|
inlineprotectednoexcept |
Pull one column's value off a byte buffer into slot m_size and advance the pointer.
| K | Column index. |
| [in,out] | a_buf | Buffer pointer, advanced by the column's byte size. |
|
inlinenoexcept |
Const owning rank of particle i.
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Owning rank of particle i (container-owned metadata).
| [in] | a_index | Particle index. |
|
inlineprotected |
Allocate a new arena and reallocate/move the columns into it (growth path).
| [in] | a_capacity | New capacity in particles. |
|
inlinenoexcept |
Remove particle i using swap-and-pop (O(1), does NOT preserve order).
| [in] | a_index | Particle index. |
|
inlineprotectednoexcept |
Swap-and-pop slot a_index in every column.
| I | Column indices [0, s_numColumns). |
| [in] | a_index | Particle index to remove. |
|
inline |
Ensure capacity for at least a_capacity particles (reallocates + moves on growth).
| [in] | a_capacity | Requested capacity. |
|
inline |
Set the particle count (grows capacity if needed; new slots are uninitialized).
| [in] | a_count | New particle count. |
|
inlineprotectednoexcept |
Per-column scatter for permute(): newcol[dest[i]] = oldcol[i].
| K | Column index to scatter. |
| [out] | a_newBuf | Destination arena buffer. |
| [in] | a_off | Byte offset of column K in a_newBuf. |
| [in] | a_dest | Destination slot for each current particle. |
|
inlineprotectednoexcept |
Scatter every column for permute() into a freshly-allocated buffer.
| I | Column indices [0, s_numColumns). |
| [out] | a_newBuf | Destination arena buffer. |
| [in] | a_off | Per-column byte offsets into a_newBuf. |
| [in] | a_dest | Destination slot for each current particle. |
|
inlineprotectednoexcept |
Cache the column base pointers from a fresh buffer + offsets.
| I | Column indices [0, s_numColumns). |
| [in] | a_off | Per-column byte offsets into m_buffer. |
|
inlinenoexcept |
Set the position of particle i.
Invalidates the cell sort – the new position may lie in a different cell.
| [in] | a_index | Particle index. |
| [in] | a_position | New position. |
|
inline |
Reclaim unused capacity by reallocating the arena down to the current size.
A no-op when already compact (capacity == size). The arena does not shrink on its own (clear()/remove() keep the capacity for reuse); call this to return memory after a transient spike. Invalidates raw column pointers. The particle order and cell-sort state are preserved.
|
inlinenoexcept |
Number of particles currently stored.
|
inline |
Counting-sort the columns into Fortran cell order and build CSR cell offsets.
After this, cell c owns the contiguous particle range [cellStart(c), cellStart(c+1)). Particles must lie within a_box; out-of-range positions are clamped to the boundary cells.
This is idempotent: a container already sorted against the same (box, dx, probLo) returns immediately, because the sort it would produce is the one it already has. Callers that establish the sort defensively therefore cost nothing when an earlier caller already did it, which is the common case – the ItoKMC reaction path sorts the same leaves at three separate call sites. Any operation that can move a particle between cells (append, remove, resize, setPosition, or handing out a writable positionColumn()) clears the flag, so the early-out only fires when the CSR mapping is still the one this container computed. In debug builds the mapping is re-verified on every early-out; see checkCellSort().
| [in] | a_box | Patch box defining the cells. |
| [in] | a_dx | Grid spacing per direction. |
| [in] | a_probLo | Physical coordinate of the lower domain corner. |
|
inlineprotectednoexcept |
Steal another container's arena (move helper).
| [in,out] | a_o | Source container, left empty afterwards. |
|
inlinenoexcept |
Swap the entire state (arena, size, capacity, sort) with another container in O(1).
Exchanges the cached column pointers and metadata only – no particle data is moved. Useful for the build-then-swap idiom and for std::swap.
| [in,out] | a_other | Container to swap with. |
|
inlinenoexcept |
Const weight of particle i.
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Weight of particle i.
| [in] | a_index | Particle index. |
|
inlinenoexcept |
Const raw weight column.
|
inlinenoexcept |
Raw weight column (double*).
|
inlineprotectednoexcept |
Write the payload columns of slot m_size from a payload struct.
| J | Payload-column indices [0, s_numPayloadColumns). |
| [in] | a_p | Payload struct to read from. |
|
protected |
Byte size of the arena at m_buffer (zero when m_buffer is null).
Kept so a release can decrement ParticleMemory by exactly what the matching allocation added, without recomputing the column offsets. It therefore describes the arena rather than the container, and must travel with m_buffer through every ownership transfer – swap() and steal() both move it. A transfer that moves the arena but leaves this behind attributes the arena to a container that no longer holds it, and the accounting drifts from the first such transfer on.