Celeritas  0.5.0-86+4a8eea4
Collection: a data portability class

The Collection manages data allocation and transfer between CPU and GPU.

Its primary design goal is facilitating construction of deeply hierarchical data on host at setup time and seamlessly copying to device. The templated T must be trivially copyable—either a fundamental data type or a struct of such types.

An individual item in a Collection<T> can be accessed with ItemId<T>, a contiguous subset of items are accessed with ItemRange<T>, and the entirety of the data are accessed with AllItems<T>. All three of these classes are trivially copyable, so they can be embedded in structs that can be managed by a Collection. A group of Collections, one for each data type, can therefore be trivially copied to the GPU to enable arbitrarily deep and complex data hierarchies.

By convention, groups of Collections comprising the data for a single class or subsystem (such as RayleighInteractor or Physics) are stored in a helper struct suffixed with Data . For cases where there is both persistent data (problem-specific parameters) and transient data (track-specific states), the collections must be grouped into two separate classes. StateData are meant to be mutable and never directly copied between host and device; its data collections are typically accessed by thread ID. ParamsData are immutable and always "mirrored" on both host and device. Sometimes it's sensible to partition ParamsData into discrete helper structs (stored by value), each with a group of collections, and perhaps another struct that has non-templated scalars (since the default assignment operator is less work than manually copying scalars in a templated assignment operator.

A collection group has the following requirements to be compatible with the CollectionMirror, CollectionStateStore, and other such helper classes:

  • Be a struct templated with template<Ownership W, MemSpace M>
  • Contain only Collection objects and trivially copyable structs
  • Define an operator bool that is true if and only if the class data is assigned and consistent
  • Define a templated assignment operator on "other" Ownership and MemSpace which assigns every member to the right-hand-side's member

Additionally, a StateData collection group must define

  • A member function size() returning the number of entries (i.e. number of threads)
  • A free function resize with one of two signatures:
    void resize(
    StateData<Ownership::value, M>* data,
    HostCRef<ParamsData> const& params,
    StreamId stream,
    size_type size);
    // or...
    void resize(
    StateData<Ownership::value, M>* data,
    const HostCRef<ParamsData>& params,
    size_type size);
    // or...
    void resize(
    StateData<Ownership::value, M>* data,
    size_type size);
    void resize(AtomicRelaxStateData< Ownership::value, M > *state, HostCRef< AtomicRelaxParamsData > const &params, size_type size)
    Resize state data in host code.
    Definition: AtomicRelaxationData.hh:151

By convention, related groups of collections are stored in a header file named Data.hh .

See ParticleParamsData and ParticleStateData for minimal examples of using collections. The MaterialParamsData demonstrates additional complexity by having a multi-level data hierarchy, and MaterialStateData has a resize function that uses params data. PhysicsParamsData is a very complex example, and GeoParamsData demonstates how to use template specialization to adapt Collections to another codebase with a different convention for host-device portability.