25#include "Acts/Definitions/Units.hpp"
26#include "Acts/Geometry/GeometryContext.hpp"
27#include "Acts/Geometry/TrackingGeometry.hpp"
28#include "Acts/Surfaces/BoundaryTolerance.hpp"
29#include "Acts/Surfaces/Surface.hpp"
30#include "Acts/Surfaces/SurfacePlacementBase.hpp"
31#include "ActsPlugins/Root/TGeoDetectorElement.hpp"
33#include <TGeoManager.h>
34#include <TGeoMatrix.h>
45const std::vector<int> gNoSensors{};
50 const auto geoId =
surface.geometryId();
51 auto [it, inserted] = mBySensor.try_emplace(sensorID, Entry{&
surface, geoId});
53 throw std::runtime_error(
"o2::acts::SurfaceIndexMap: sensor " +
std::to_string(sensorID) +
54 " is already mapped");
56 mByGeoId[geoId].push_back(sensorID);
61 const auto it = mBySensor.find(sensorID);
62 return it == mBySensor.end() ? nullptr : it->second.surface;
67 const auto it = mBySensor.find(sensorID);
68 return it == mBySensor.end() ? Acts::GeometryIdentifier{} : it->second.geoId;
73 const auto it = mByGeoId.find(geoId);
74 return it == mByGeoId.end() ? gNoSensors : it->second;
91 explicit CentreLookup(
double cellSize) : mCellSize(cellSize) {}
96 mCells[cellOf(
position)].push_back(mEntries.size() - 1);
100 const Acts::Surface* findNearest(
const Acts::Vector3&
position,
double tolerance)
const
103 const Acts::Surface*
best =
nullptr;
104 double bestDist2 = tolerance * tolerance;
105 for (std::int64_t dx = -1; dx <= 1; ++dx) {
106 for (std::int64_t dy = -1; dy <= 1; ++dy) {
107 for (std::int64_t dz = -1; dz <= 1; ++dz) {
108 const auto it = mCells.find(Cell{cell.x + dx, cell.y + dy, cell.z + dz});
109 if (it == mCells.end()) {
112 for (
const auto idx : it->second) {
113 const double dist2 = (mEntries[
idx].position -
position).squaredNorm();
114 if (dist2 <= bestDist2) {
125 std::size_t
size()
const {
return mEntries.size(); }
133 std::int64_t
x = 0,
y = 0,
z = 0;
137 std::size_t operator()(
const Cell&
c)
const noexcept
139 std::size_t
h =
static_cast<std::size_t
>(
c.x) * 0x9e3779b97f4a7c15ULL;
140 h ^=
static_cast<std::size_t
>(
c.y) + 0x9e3779b97f4a7c15ULL + (
h << 6) + (
h >> 2);
141 h ^=
static_cast<std::size_t
>(
c.z) + 0x9e3779b97f4a7c15ULL + (
h << 6) + (
h >> 2);
146 Cell cellOf(
const Acts::Vector3& p)
const
148 return Cell{
static_cast<std::int64_t
>(std::floor(p[0] / mCellSize)),
149 static_cast<std::int64_t
>(std::floor(p[1] / mCellSize)),
150 static_cast<std::int64_t
>(std::floor(p[2] / mCellSize))};
153 double mCellSize = 1.;
154 std::vector<Entry> mEntries;
155 std::unordered_map<Cell, std::vector<std::size_t>, CellHash> mCells;
164struct SensitiveSurfaces {
167 std::unordered_map<const TGeoNode*, std::vector<const Acts::Surface*>>
byNode;
170 explicit SensitiveSurfaces(
double cellSize) :
byCentre(cellSize) {}
173SensitiveSurfaces collectSensitive(
const Acts::TrackingGeometry& geometry,
174 const Acts::GeometryContext& gctx,
double cellSize)
176 SensitiveSurfaces out(cellSize);
177 geometry.apply([&](
const Acts::Surface&
surface) {
178 const auto* placement =
surface.surfacePlacement();
179 if (placement ==
nullptr || !placement->isSensitive()) {
182 const auto* tgeoElement =
dynamic_cast<const ActsPlugins::TGeoDetectorElement*
>(placement);
183 if (tgeoElement !=
nullptr) {
184 out.byNode[&tgeoElement->tgeoNode()].push_back(&
surface);
189 if (
type == Acts::Surface::SurfaceType::Cylinder ||
type == Acts::Surface::SurfaceType::Disc) {
190 out.layerSurfaces.push_back(&
surface);
199struct SensorPlacement {
206 double rot[9] = {0.};
207 double tra[3] = {0.};
208 cache.
getMatrixL2G(sensorID).GetComponents(rot[0], rot[1], rot[2], tra[0],
209 rot[3], rot[4], rot[5], tra[1],
210 rot[6], rot[7], rot[8], tra[2]);
212 out.position = Acts::Vector3{tra[0] * Acts::UnitConstants::cm, tra[1] * Acts::UnitConstants::cm,
213 tra[2] * Acts::UnitConstants::cm};
214 out.rotation << rot[0], rot[1], rot[2], rot[3], rot[4], rot[5], rot[6], rot[7], rot[8];
222const Acts::Surface* matchByNode(
const SensitiveSurfaces&
surfaces,
const std::string&
path,
223 const Acts::GeometryContext& gctx,
const SensorPlacement& placement,
224 double tolerance,
bool& ambiguous)
227 if (gGeoManager ==
nullptr) {
228 throw std::runtime_error(
"o2::acts::makeSurfaceIndex: no TGeo geometry loaded");
230 gGeoManager->PushPath();
231 const bool ok = gGeoManager->cd(
path.c_str());
232 const TGeoNode*
node = ok ? gGeoManager->GetCurrentNode() :
nullptr;
233 gGeoManager->PopPath();
234 if (
node ==
nullptr) {
242 if (it->second.size() == 1) {
243 return it->second.front();
245 const Acts::Surface*
best =
nullptr;
246 for (
const auto*
surface : it->second) {
247 if ((
surface->localToGlobalTransform(gctx).translation() - placement.position).norm() <= tolerance) {
248 if (best !=
nullptr) {
260const Acts::Surface* matchByPlacement(
const SensitiveSurfaces&
surfaces,
261 const Acts::GeometryContext& gctx,
262 const SensorPlacement& placement,
double tolerance,
268 constexpr double kRotationTolerance = 1
e-9;
270 if (
const auto*
surface =
surfaces.byCentre.findNearest(placement.position, tolerance);
281 const Acts::Surface*
best =
nullptr;
283 const auto& transform =
surface->localToGlobalTransform(gctx);
284 if ((transform.translation() - placement.position).norm() <= tolerance &&
285 (transform.rotation() - placement.rotation).norm() <= kRotationTolerance) {
286 if (best !=
nullptr) {
299 const Acts::GeometryContext& gctx,
305 throw std::runtime_error(
"o2::acts::makeSurfaceIndex: the detector matrix cache is not built");
308 throw std::runtime_error(
309 "o2::acts::makeSurfaceIndex: the L2G matrix cache is empty. Call fillMatrixCache() with the "
310 "L2G bit set before building the index.");
314 const double tolerance = toleranceCm * Acts::UnitConstants::cm;
316 const auto surfaces = collectSensitive(geometry, gctx, std::max(tolerance, 1
e-6));
317 const int nSensors = cache.
getSize();
320 "Matching {} {} sensors against {} sensitive ACTS surfaces ({} per-sensor, {} whole-layer) "
321 "by {} (tolerance {} cm)",
324 pathProvider ?
"TGeo node" :
"placement", toleranceCm);
325 if (pathProvider &&
surfaces.nWithoutNode != 0) {
326 LOGP(warn,
"{} sensitive surfaces have no TGeo detector element and cannot be matched by node",
331 std::size_t nUnmatched = 0;
332 std::size_t nAmbiguous = 0;
333 std::unordered_map<Acts::GeometryIdentifier, int> claimedBy;
334 std::ostringstream failures;
337 for (
int sensorID = 0; sensorID < nSensors; ++sensorID) {
338 const auto placement = sensorPlacementOf(cache, sensorID);
340 bool ambiguous =
false;
341 const Acts::Surface*
match =
343 ? matchByNode(
surfaces, pathProvider(sensorID), gctx, placement, tolerance, ambiguous)
344 : matchByPlacement(
surfaces, gctx, placement, tolerance, ambiguous);
346 if (
match ==
nullptr) {
347 ambiguous ? ++nAmbiguous : ++nUnmatched;
348 if (nReported < 10) {
349 failures <<
"\n sensor " << sensorID <<
" at ("
350 << placement.position[0] / Acts::UnitConstants::cm <<
", "
351 << placement.position[1] / Acts::UnitConstants::cm <<
", "
352 << placement.position[2] / Acts::UnitConstants::cm <<
") cm "
353 << (ambiguous ?
"matches several sensitive ACTS surfaces" :
"matches no sensitive ACTS surface");
361 const auto geoId =
match->geometryId();
362 const auto [it, inserted] = claimedBy.try_emplace(geoId, sensorID);
364 throw std::runtime_error(
365 "o2::acts::makeSurfaceIndex: sensors " +
std::to_string(it->second) +
" and " +
366 std::to_string(sensorID) +
" both resolve to the ACTS surface with geometry id " +
368 ". They are indistinguishable by the information available, so the index would be wrong.");
373 if (nUnmatched != 0 || nAmbiguous != 0) {
375 if (nAmbiguous != 0 && !pathProvider) {
377 " Pass a SensorPathProvider (e.g. GeometryTGeo::getMatrixPath) so sensors are identified by "
378 "their TGeo node instead of their placement.";
380 throw std::runtime_error(
"o2::acts::makeSurfaceIndex: of " +
std::to_string(nSensors) +
381 " sensors, " +
std::to_string(nUnmatched) +
" matched no surface and " +
382 std::to_string(nAmbiguous) +
" were ambiguous." + hint + failures.str());
385 LOGP(info,
"Sensor index built: {} sensors on {} surfaces",
index.size(),
index.getNSurfaces());
std::unique_ptr< expressions::Node > node
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
std::vector< const Acts::Surface * > layerSurfaces
Acts::RotationMatrix3 rotation
const Acts::Surface * surface
std::unordered_map< const TGeoNode *, std::vector< const Acts::Surface * > > byNode
Lookup between O2 sensor indices and ACTS surfaces.
std::vector< std::shared_ptr< Surface > > surfaces
Class for time synchronization of RawReader instances.
const Acts::Surface * getSurface(int sensorID) const
const std::vector< int > & getSensorIDs(Acts::GeometryIdentifier geoId) const
void add(int sensorID, const Acts::Surface &surface)
Acts::GeometryIdentifier getGeometryId(int sensorID) const
static constexpr const char * getName(ID id)
names of defined detectors
const o2::detectors::DetID & getDetID() const
const Mat3D & getMatrixL2G(int sensID) const
const MatrixCache< Mat3D > & getCacheL2G() const
bool match(const std::vector< std::string > &queries, const char *pattern)
GLint GLint GLsizei GLint GLenum GLenum type
GLsizei const GLchar *const * path
GLdouble GLdouble GLdouble z
SurfaceIndexMap makeSurfaceIndex(const Acts::TrackingGeometry &geometry, const Acts::GeometryContext &gctx, const o2::detectors::DetMatrixCache &cache, double toleranceCm=1e-3, SensorPathProvider pathProvider={})
std::function< std::string(int sensorID)> SensorPathProvider
Full TGeo node path of one sensor, e.g. o2::trk::GeometryTGeo::getMatrixPath().
const bool const bool const int FollowDirection BestTrial TrackITSInternal< NLayers > & best
bool operator==(const observer_ptr< W1 > &p1, const observer_ptr< W2 > &p2)
std::string to_string(gsl::span< T, Size > span)