classDiagram
class Index {
+first()
+last()
+stride()
}
class NDIndex {
+dimension
+operator[]
}
class UniformCartesian {
+spacing
}
class Mesh {
+gridsize
+origin
}
class FieldLayout {
+localNDIndex()
+globalNDIndex()
}
class Field {
+mesh
+layout
+view
}
class ParticleBase {
+create()
+destroy()
+update()
}
NDIndex --> Index
FieldLayout --> NDIndex
Field --> FieldLayout
Field --> UniformCartesian
UniformCartesian --> Mesh
ParticleBase --> FieldLayout
6 Core Concepts
IPPL code is parameterized by dimension, value type, memory space, and execution space. This gives user code a compact notation while allowing the library to instantiate high-performance implementations for CPUs and GPUs.
6.1 Concept map
6.2 Design rules
- Use IPPL index and region types to describe domains instead of hand-written loops over global coordinates.
- Treat
FieldLayoutand particle layout objects as ownership and communication contracts. - Prefer field expressions and reductions over manual host-side copies.
- Make execution-space behavior explicit when adding new APIs.
- Keep Doxygen comments close to the public interface; the manual should explain usage and design intent.
6.3 Domain construction pattern
Most examples follow the same domain construction pattern:
constexpr unsigned Dim = 3;
ippl::Vector<int, Dim> nr = {64, 64, 64};
ippl::NDIndex<Dim> domain;
for (unsigned d = 0; d < Dim; ++d) {
domain[d] = ippl::Index(nr[d]);
}
std::array<bool, Dim> isParallel;
isParallel.fill(true);
ippl::Vector<double, Dim> hr = {1.0 / nr[0], 1.0 / nr[1], 1.0 / nr[2]};
ippl::Vector<double, Dim> origin = {0.0, 0.0, 0.0};
using Mesh_t = ippl::UniformCartesian<double, Dim>;
Mesh_t mesh(domain, hr, origin);
ippl::FieldLayout<Dim> layout(MPI_COMM_WORLD, domain, isParallel);The same domain, mesh, and layout then become the shared coordinate system for fields, particle layouts, and solvers.
6.4 Index
ippl::Index represents a one-dimensional strided integer range. It is used both to build global domains and to express subranges. Current constructors are:
| Constructor | Meaning |
|---|---|
Index() |
Empty range. |
Index(n) |
Range [0, n - 1]. The argument is a length, not an upper bound. |
Index(first, last) |
Inclusive range [first, last] with stride 1. |
Index(first, last, stride) |
Inclusive strided range. |
Examples:
ippl::Index all(10); // 0, 1, ..., 9
ippl::Index high(5, 9); // 5, 6, ..., 9
ippl::Index odd(1, 9, 2); // 1, 3, 5, 7, 9Useful accessors are first(), last(), min(), max(), length(), stride(), and empty(). Index also supports range arithmetic such as I + 1, I - 1, 2 * I, and I / 2, plus geometric operations such as intersect, grow, touches, contains, and split.
6.5 NDIndex
ippl::NDIndex<Dim> is a fixed-size container of Dim Index objects. It describes a rectangular domain in index space.
ippl::NDIndex<3> domain;
domain[0] = ippl::Index(64);
domain[1] = ippl::Index(64);
domain[2] = ippl::Index(128);Like Index, it supports intersect, grow, touches, contains, split, length, first, and last. Layout, mesh, field, particle, and solver code all use this object as the shared description of the discrete domain.
6.6 Mesh and layout
UniformCartesian<T, Dim> adds geometry to an NDIndex: mesh spacing, origin, cell volume, and mesh volume.
ippl::Vector<double, Dim> hx = {dx, dy, dz};
ippl::Vector<double, Dim> origin = {0.0, 0.0, 0.0};
ippl::UniformCartesian<double, Dim> mesh(domain, hx, origin);FieldLayout<Dim> adds ownership and communication information to the same domain:
std::array<bool, Dim> isParallel;
isParallel.fill(true);
ippl::FieldLayout<Dim> layout(MPI_COMM_WORLD, domain, isParallel);Each boolean in isParallel tells the partitioner whether that axis may be decomposed. At least one axis must be parallel in distributed runs. Pass true as the final constructor argument when all field boundaries are periodic:
ippl::FieldLayout<Dim> periodicLayout(MPI_COMM_WORLD, domain, isParallel, true);flowchart LR Index0["Index x"] Index1["Index y"] Index2["Index z"] Domain["NDIndex<Dim>"] Mesh["UniformCartesian<T, Dim> (Mesh)"] Layout["FieldLayout<Dim>"] Field["Field<T, Dim, Mesh, Centering>"] Index0 --> Domain Index1 --> Domain Index2 --> Domain Domain --> Mesh Domain --> Layout Mesh --> Field Layout --> Field
6.7 ParameterList
Solvers take many options, such as type of algorithm used, etc. These also include options for the FFT provided by heffte. These are commonly passed through ippl::ParameterList.
The ParameterList is a collection of options, identified with a key (std::string) and given a value. The allowed value types in the ParameterList are double, float, bool, std::string, unsigned int, int. The following is an example of a ParameterList with some heffte options:
ippl::ParameterList params;
params.add("use_pencils", true);
params.add("use_reorder", false);
params.add("use_gpu_aware", true);
bool gpuAware = params.get<bool>("use_gpu_aware");To add options to the ParameterList, we use add(key, value). add rejects duplicate keys. The value of a key can be updated using update(key, value). To get the value of an option in the ParameterList, we can use the get<T>(key) function. get(key) without a default throws if the key is missing, while get(key, defaultValue) returns the default for absent keys.