|
| 1 | +# ACTS tracking geometry in O2 |
| 2 | + |
| 3 | +Provides the shared, immutable `Acts::TrackingGeometry` that ACTS-based |
| 4 | +reconstruction needs, built from the TGeo geometry O2 already has live in memory. |
| 5 | + |
| 6 | +ACTS is an **optional** O2 dependency (`dependencies/O2Dependencies.cmake`). Without |
| 7 | +it this package produces no targets and `O2_WITH_ACTS` is not defined, so anything |
| 8 | +using it must be guarded. |
| 9 | + |
| 10 | +## Libraries |
| 11 | + |
| 12 | +| Target | Contents | |
| 13 | +| --- | --- | |
| 14 | +| `O2::ACTSInterface` | `TrackingGeometryManager` (the provider), `ITrackingGeometryBuilder` (the detector-specific seam), `SurfaceIndexMap` (sensor ↔ surface lookup), `MagneticFieldAdapter` (`Acts::MagneticFieldProvider` over the O2 field). No DPL dependency. | |
| 15 | +| `O2::ACTSWorkflow` | `ActsGeometryService`, the same provider reachable through the DPL `ServiceRegistry`. | |
| 16 | +| `O2::ALICE3ACTS` | `Gen3BlueprintBuilder`, the ALICE 3 builder (under `Detectors/Upgrades/ALICE3/ACTS`). | |
| 17 | + |
| 18 | +## Using it from a DPL task |
| 19 | + |
| 20 | +The manager fetches nothing itself: it needs `gGeoManager` to be live, which is what |
| 21 | +`GRPGeomRequest::Aligned` arranges. Note that a task that only used the material LUT |
| 22 | +before will have been passing `GRPGeomRequest::None` and has to be switched. |
| 23 | + |
| 24 | +```cpp |
| 25 | +// spec factory |
| 26 | +auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>( |
| 27 | + false, false, false, true /*GRPMagField*/, false, |
| 28 | + o2::base::GRPGeomRequest::Aligned, inputs, true); |
| 29 | + |
| 30 | +void init(InitContext& ic) |
| 31 | +{ |
| 32 | + o2::base::GRPGeomHelper::instance().setRequest(mCCDBReq); |
| 33 | + |
| 34 | + o2::alice3::Gen3BlueprintBuilder::Config cfg; |
| 35 | + cfg.geometryConfigFile = ic.options().get<std::string>("acts-geometry-config"); |
| 36 | + o2::acts::TrackingGeometryManager::instance().setBuilder( |
| 37 | + std::make_unique<o2::alice3::Gen3BlueprintBuilder>(cfg)); |
| 38 | +} |
| 39 | + |
| 40 | +void run(ProcessingContext& pc) |
| 41 | +{ |
| 42 | + o2::base::GRPGeomHelper::instance().checkUpdates(pc); // gGeoManager now live |
| 43 | + const auto& tg = o2::acts::TrackingGeometryManager::instance().get(); // built once |
| 44 | +} |
| 45 | +``` |
| 46 | +
|
| 47 | +To reach it through the registry instead, put `o2::acts::defaultServicesWithActsGeometry()` |
| 48 | +into the `DataProcessorSpec`'s `requiredServices` and use |
| 49 | +`pc.services().get<o2::acts::ActsGeometryService>()`. Both paths hand out the same object. |
| 50 | +
|
| 51 | +## Mapping O2 clusters onto ACTS surfaces |
| 52 | +
|
| 53 | +`makeSurfaceIndex()` (or `TrackingGeometryManager::getIndex(cache, tol, pathProvider)`, |
| 54 | +which caches per detector) maps every sensor of a `DetMatrixCache`-derived geometry helper |
| 55 | +onto a sensitive ACTS surface. |
| 56 | +
|
| 57 | +**Pass a `SensorPathProvider` whenever the detector has one.** With it, sensors are |
| 58 | +identified by the TGeo node the surface was built from — an identity, so it cannot |
| 59 | +mis-assign: |
| 60 | +
|
| 61 | +```cpp |
| 62 | +auto* trkGeo = o2::trk::GeometryTGeo::Instance(); |
| 63 | +trkGeo->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); |
| 64 | +const auto& index = mgr.getIndex(*trkGeo, 1e-3, |
| 65 | + [trkGeo](int chipID) { return std::string(trkGeo->getMatrixPath(chipID).Data()); }); |
| 66 | +``` |
| 67 | + |
| 68 | +Without it the fallback matches on the sensor's local-to-global transform, which is exact |
| 69 | +where a transform identifies a sensor but not always: the ALICE 3 vertex-detector petals |
| 70 | +are tube segments, so the three layers of a petal share both origin and rotation and |
| 71 | +differ only in radius, which the matrix cache does not carry. Those are reported as |
| 72 | +ambiguous rather than assigned arbitrarily, and `makeSurfaceIndex()` throws. One surface |
| 73 | +per sensor is enforced in both modes. |
| 74 | + |
| 75 | +## The Gen3 geometry description |
| 76 | + |
| 77 | +`Detectors/Upgrades/ALICE3/ACTS/config/gen3_geometry_config.json` carries everything |
| 78 | +geometry-specific: sensor name globs, region boundaries, per-subsystem clustering |
| 79 | +tolerances, passive material structures and the pinned volume IDs. All lengths in mm. |
| 80 | + |
| 81 | +It is tuned for the layout `run_test.sh` generates — verified against an o2-sim geometry of |
| 82 | +that layout: the sensor globs cover every sensitive volume family (and correctly exclude |
| 83 | +`FT3Sensor_Inactive_*`), `*EOSCard*` matches the 504 end-of-stave volumes, the passive |
| 84 | +cylinder radii and half-lengths match the real support volumes, and the resulting |
| 85 | +volume/layer/surface table is identical to the one actsO2's reference geometry produces. |
| 86 | + |
| 87 | +One known imprecision, inherited and present for both geometries: `TRK_MID_CarbonSupport` |
| 88 | +is declared with `halfZ = 1420` while the real `TRK_MID_CARBONSUPPORT` volume has |
| 89 | +`dz = 1410 mm`. It only affects the z-extent of that passive layer's material receiver. |
| 90 | + |
| 91 | +## Material |
| 92 | + |
| 93 | +Gen3 construction takes no `IMaterialDecorator`, so an ACTS JSON material map is applied |
| 94 | +afterwards via `setMaterialMapFile()`. Material maps are keyed on |
| 95 | +`Acts::GeometryIdentifier`, so a structural change to a builder invalidates existing |
| 96 | +maps; the manager raises rather than silently producing a material-free geometry. |
| 97 | + |
| 98 | +## Checking a geometry |
| 99 | + |
| 100 | +`Detectors/Upgrades/ALICE3/ACTS/macros/run_test.sh` does the whole thing: it runs |
| 101 | +`o2-sim-serial-run5` with the ALICE 3 layout the ACTS chain is developed against, then |
| 102 | +builds the tracking geometry from the result and checks every TRK chip against its ACTS |
| 103 | +surface. Run it from a scratch directory — `o2-sim` writes into `$PWD`: |
| 104 | + |
| 105 | +```bash |
| 106 | +mkdir -p /tmp/acts && cd /tmp/acts |
| 107 | +bash <O2-source>/Detectors/Upgrades/ALICE3/ACTS/macros/run_test.sh |
| 108 | +``` |
| 109 | + |
| 110 | +The geometry description it needs is shipped in this package |
| 111 | +(`Detectors/Upgrades/ALICE3/ACTS/config/gen3_geometry_config.json`, installed to |
| 112 | +`$O2_ROOT/share/Detectors/Upgrades/ALICE3/ACTS/config/`) and matches the layout the script |
| 113 | +generates. Set `GEN3_CONFIG` to point at a different geometry's config. |
| 114 | + |
| 115 | +Knobs: `nEvents`, `generator`, `modules`, `GEN3_CONFIG`, `SKIP_ALIGNMENT`. The last one |
| 116 | +defaults to 1 because `o2-sim` finishes by fetching alignment from CCDB, which needs a |
| 117 | +valid alien token and aborts without one — after the geometry file has already been |
| 118 | +written. The ACTS geometry is built from the ideal geometry, so skipping it costs nothing. |
| 119 | + |
| 120 | +The macro `CheckActsTrackingGeometry.C` can also be run on its own against an existing |
| 121 | +`o2sim_geometry.root`; it prints the volume/layer/surface table, which is the authority for |
| 122 | +the `(volume, layer)` keys that digitisation and seeding configurations use. It needs ACTS, |
| 123 | +Eigen and `$O2_ROOT/include` on `ROOT_INCLUDE_PATH` — `run_test.sh` sets that up. |
0 commit comments