The Grid
template class provides a generic binned Grid
implementation in Grid
accepts a variadic list of Axis
types, where the number of axes equals the number of desired dimensions of the Grid
.
Axis
accepts two template parameters:
template <AxisType type,
AxisBoundaryType bdt = AxisBoundaryType::Open>
class Axis;
where
enum class AxisBoundaryType { Open, Bound, Closed };
enum class AxisType { Equidistant, Variable };
AxisType
defines whether an axis is fully determined by
If at all possible, Equidistant
is preferrable, since bin
where Variable
, a search for the correct bin is performed over the bin boundaries.
AxisBoundaryType
steers how out-of-bounds lookups are handled.
There are three options:
- Bound: out-of-bounds lookups resolve to the closest valid bin.
- Open: out-of-bounds lookups resolve to dedicated underflow and overflow bins.
- Closed: out-of-bounds lookups wrap-around to the other side of the axis.
The types of the axes have to be known at compile-time, since they are provided to the Grid
as template parameters. Thus the number of dimensions Grid
is also fixed at compile-time.
The axes can be any combination of the aforementioned variations.
template <typename T, class... Axes> class Grid;
where T
is the value type that is stored in each bin. Instances of each axis are then given to the Grid
constructor as a tuple. This Axis instances hold the number of bins and the boundary values, which are runtime values.
The Grid
performs a lookup by recursively visiting each axis and having it perform a lookup in the corresponding component of the input vector. The lookup methods are templated on the input vector type, which only has to support component access. Transforming in and out of the local Grid
reference frame is not handled by the Grid
.
The underlying data structure of the Grid
is a one-dimensional std::vector<T>
, where T
is the template parameter determining the stored value type. The index of this vector is referred to as the global bin index.
The logical index structure, where each global bin is addressed by an
using index_t = std::array<size_t, N>;
index_t getLocalBinIndices(size_t bin) const;
size_t getGlobalBinIndex(const index_t& localBins) const;
The local bin indices are always defined from 1 to AxisBoundaryType != Open
.
The Grid
can determine the number of neighbors around a given bin. This done by first converting the global bin index to local bin indices, and then varying the local bin indices in each dimension. At this stage, each Axis gets to decide, which indices are considered neighbors, which differs depending on AxisBinningType
. Open
considers the underflow and overflow bins, while Bound
does not. Closed
considers bins on the other side of the axis.
The resulting neighbor combination around bin B might look like
b x b | 1 | 2 | 3 |
---|---|---|---|
1 | x | 0,+1 | x |
2 | -1,0 | B | +1,0 |
3 | x | 0,-1 | x |
Here, the corner combinations are still missing (also true for
b x b | 1 | 2 | 3 |
---|---|---|---|
1 | -1,+1 | 0,+1 | +1,+1 |
2 | -1,0 | B | +1,0 |
3 | -1,-1 | 0,-1 | +1,-1 |
These local bin indices are then converted into global bin indices before being returned.