Interfaces

These classes manage access to geometric information throughout the codebase. They work in tandem with celeritas::GeantGeoParams to associate Celeritas identifiers with Geant4 runtime data structures.

Volume hierarchy

class VolumeParams : public celeritas::ParamsDataInterface<VolumeParamsData>

Define and manage a hierarchy of volumes and instances thereof.

See the introduction to the Geometry API section for a detailed description of volumes in the detector geometry description. This class abstracts the graph of user-defined volumes, relating nodes (VolumeId, aka logical volume) to edges (VolumeInstanceId, aka physical volume) and providing the means to determine the path (isomorphic to a VolumeUniqueInstanceId, aka touchable history) of a track state. The root of the graph is the world volume, and the level of a volume in the path is the distance to the root: zero for the root volume, one for its direct child, etc. The maximum value of the level in any path is one less than num_volume_levels : an array of VolumeInstanceId with that size can represent any path. (When explicitly constructing this array, we omit the world volume since it is implicit.) The total number of paths to any node in the geometry is num_unique_instances .

In conjunction with GeantGeoParams, this class allows conversion between the Celeritas geometry implementation and the Geant4 geometry navigation.

Label-based lookup (volume and volume instance names) is provided through the volume_labels and volume_instance_labels accessors. Graph properties (material, connectivity, world) are stored in the underlying VolumeParamsData and accessed efficiently via VolumeView.

class VolumeView

Access material and connectivity for a single logical volume.

This GPU-compatible view provides per-volume access to the geometry material ID and parent/child edges in the volume instance graph.

Example:
VolumeView view{params.host_ref(), vol_id};
GeoMatId mat = view.material();
for (VolumeInstanceId vi : view.children()) { ... }

Conversion between a “navigation path”/”touchable history” and celeritas::VolumeUniqueInstanceId can be done on host or device.

constexpr VolumeUniqueInstanceId celeritas::world_unique_instance = {0}

Unique instance ID of the “world” volume (root of the volume graph)

class VolumePathAccumulator

Incrementally compute the unique ID of a path in the volume hierarchy.

Each VolumeUniqueInstanceId uniquely identifies a root-to-node path (i.e., a Geant4 “touchable”) in the volume DAG. This class computes the ID on the fly without allocating a path buffer: call operator() once for each VolumeInstanceId encountered while descending from the world volume, passing the current accumulated ID and receiving the updated one.

For a volume instance vi at position k in its parent volume’s children list, the offset is the sum of num_desc(volume(vj)) for all preceding siblings vj (positions 0..k-1), where num_desc(V) counts the total number of unique paths ending at any node in V’s subtree (including V itself). For a path \([vi_0, vi_1, \ldots, vi_k]\) the unique instance ID is

\[ \text{uid} = \sum_{i=0}^{k} \bigl(\text{offset}[vi_i] + 1\bigr). \]
The empty path (the world volume itself, with no enclosing instance) maps to ID 0 (see world_unique_instance ).

Example:
VolumePathAccumulator accum{params.host_ref()};
VolumeUniqueInstanceId uid = world_unique_instance;
for (VolumeInstanceId vi : path_below_world)
{
    uid = accum(uid, vi);  // unique ID for the node reached via this step
}

class VolumePathFinder

Reconstruct the volume-instance path for a VolumeUniqueInstanceId.

Each VolumeUniqueInstanceId uniquely identifies a root-to-node path (i.e., a Geant4 “touchable”) in the volume DAG. This class performs the inverse of VolumePathAccumulator: given an ID it fills a caller-supplied scratch buffer with the VolumeInstanceId sequence and returns a (possibly shorter) span of the result.

VolumeUniqueInstanceId{0} (or world_unique_instance ) always denotes the world volume itself (empty path), and VolumeUniqueInstanceId{} (null/invalid) is rejected with a precondition failure. The valid range is \([0,\, N_\text{unique})\).

The algorithm descends from the world volume level by level, always seeding from the world’s direct children. At each level it scans the current volume’s children to find the unique child whose subtree contains the remaining UID, exploiting the fact that sibling offsets are strictly increasing. The cost is \(O(D \log C)\) where \(D\) is the path depth and \(C\) is the maximum number of children of any volume.

The scratch buffer must be at least num_volume_levels - 1 long (the maximum possible path depth). Successive calls reuse the same buffer, so callers must consume the returned span before the next call.

Example:
std::vector<VolumeInstanceId> buf(params.num_volume_levels());
VolumePathFinder find_path{params.host_ref(), make_span(buf)};

VolumeUniqueInstanceId uid = ...;
auto path = find_path(uid);   // [vi_0, vi_1, ..., vi_k]

Surfaces and detectors

class SurfaceParams : public celeritas::ParamsDataInterface<SurfaceParamsData>

Map volumetric geometry information to surface IDs.

See the introduction to the Geometry API section for a detailed description of surfaces in the detector geometry description.

The specification of surfaces using volume relationships is required by volume-based geometries such as Geant4 and VecGeom 1, so it is not currently possible to define different properties for the different faces of a volume unless those faces are surrounded by distinct geometric volumes. Since ORANGE and VecGeom 2 support true surface definitions, a future extension will allow the user to attach surface properties to, for example, different sides of a cube.

class DetectorParams : public celeritas::ParamsDataInterface<DetectorParamsData>

Map Geant4 sensitive detectors to distinct detector IDs.

Implementation volumes

class GeoParamsInterface

Interface class for accessing host geometry metadata.

This class is implemented by OrangeParams to allow navigation with the ORANGE geometry implementation, VecgeomParams for using VecGeom, and GeantGeoParams for testing with the Geant4-provided navigator.

Subclassed by celeritas::GeantGeoParams, celeritas::OrangeParams, celeritas::VecgeomParams

A few helper functions can be used to build collections (see Data model) of ImplVolumeId for runtime tracking (used internally by fields, physics, etc.).

template<class T, class G, class F>
inline Collection<T, Ownership::value, MemSpace::host, ImplVolumeId> celeritas::build_volume_collection(G const &geo, F &&fill_value)

Create a “collection” that maps from ImplVolumeId to a value.

This builds collections for runtime execution using a GeoTrackView’s impl_volume_id() call, which requires less indirection than volume_id() .

Given a geometry (which is allowed to be GeoParamsInterface ), a function

T(*)(VolumeId) 
will be called for every ImplVolumeId in the geometry that corresponds to a canonical volume. The resulting value will be assigned to the collection.

template<class T>
class VolumeMapFiller

Helper class to fill a volume collection from a map.

Example:

host_data.detector
    = build_volume_collection<DetectorId>(geo, VolumeMapFiller{det_ids});