ATLAS Offline Software
GeoIDSvc.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // class header include
6 #include "GeoIDSvc.h"
7 
8 // framework includes
9 #include "GaudiKernel/Bootstrap.h"
10 #include "GaudiKernel/ISvcLocator.h"
11 
12 // DetectorDescription
14 
15 // STL includes
16 #include <algorithm>
17 
19 ISF::GeoIDSvc::GeoIDSvc(const std::string& name,ISvcLocator* svc) :
20  base_class(name,svc)
21 {
22 }
23 
24 // Athena algtool's Hooks
26 {
27  ATH_MSG_DEBUG("initialize() ...");
28 
29  // retrieve envelope definition service
30  ATH_CHECK(m_envDefSvc.retrieve());
31 
32  // create internal volume representations for the given dimensions
33  std::vector<double> tmpZBins[AtlasDetDescr::fNumAtlasRegions];
34  std::map< size_t, double > tmpRBins[AtlasDetDescr::fNumAtlasRegions];
35  //std::map< size_t, std::array<RadiusGeoIDPair,2> > tmpRBins[AtlasDetDescr::fNumAtlasRegions];
36 
38 
39  // retrieve a list of (r,z) pairs for the z>0
40  // side of the envelope
41  std::unique_ptr<RZPairList> curRZ = prepareRZPairs( AtlasDetDescr::AtlasRegion(geoID) );
42  if (curRZ->size()==0) {
43  ATH_MSG_ERROR("Unable to create volume representation for geoID="<<geoID);
44  return StatusCode::FAILURE;
45  }
46  ATH_MSG_VERBOSE("Found " << curRZ->size() << " (r,z) pairs with positive z for geoID=" << geoID);
47 
48  // TODO:
49  // make sure the list of (r,z) pairs is supported by this GeoIDSvc implementation
50  // -> only cylindrical boundaries, no conical boundaries
51  // -> no undercuts
52  //if ( checkRZPairs(curRZ).isFailure()) {
53  // ATH_MSG_ERROR("Unable to create volume representation for geoID="<<geoID);
54  // return StatusCode::FAILURE;
55  //}
56 
57  ATH_MSG_DEBUG("Preparing " << curRZ->size() << " (r,z) pairs with positive z for geoID=" << geoID);
58  while ( curRZ->size()) {
59  //double minR = std::min( curRZ.front().first , curRZ.back().first );
60  double maxR = std::max( curRZ->front().first , curRZ->back().first );
61  double zFront = curRZ->front().second;
62  double zBack = curRZ->back().second;
63  double minZ = std::min( zFront, zBack);
64 
65  ATH_MSG_VERBOSE(" minz=" << minZ << " zBack="<<zBack<<" zFront="<<zFront<<" maxR="<<maxR<<" curRZ->size()="<<curRZ->size());
66 
67  // remove items only on the one side of the list that
68  // has the smaller z
69  if (zFront<zBack) curRZ->pop_front();
70  else if (zBack<zFront) curRZ->pop_back();
71  else {
72  // both are equal in z
73  curRZ->pop_front();
74  if (curRZ->size()>0) curRZ->pop_back();
75  }
76 
77  // register the boundary value of new bin in z
78  size_t curZBin = tmpZBins[geoID].size();
79  // skip this entry if minZ did not change
80  if ( (curZBin>0) && ( fabs(tmpZBins[geoID][curZBin-1]-minZ) <m_tolerance) ) continue;
81 
82  tmpZBins[geoID].push_back(minZ);
83 
84  // construct the (radius^2,geoID) pairs
85  //std::array<RadiusGeoIDPair, 2> radiusGeoIDs;
86  // radiusGeoIDs[0] = RadiusGeoIDPair(minR*minR, AtlasDetDescr::fUndefinedAtlasRegion);
87  //if (curZBin==0) radiusGeoIDs[1] = RadiusGeoIDPair(maxR*maxR, AtlasDetDescr::fUndefinedAtlasRegion);
88  //else radiusGeoIDs[1] = RadiusGeoIDPair(maxR*maxR, AtlasDetDescr::AtlasRegion(geoID));
91  //tmpRBins[geoID][curZBin] = radiusGeoIDs;
92  tmpRBins[geoID][curZBin] = maxR*maxR;
93  }
94  } // loop over geoIDs
95 
96  ATH_MSG_DEBUG("Combining individual volumen boundaries in one common representation");
97  // convert and combine the gathered tmpRBins, tmpZBins into
98  // tmpZBinsGlobal, tmpRBinsGlobal which will have the same
99  // format as the member variables m_zBins and m_radiusBins
100  size_t tmpZBinIndex[AtlasDetDescr::fNumAtlasRegions];
102  tmpZBinIndex[geoID] = 0;
103  std::vector<double> tmpZBinsGlobal;
104  std::map< size_t, RadiusGeoIDPairSet > tmpRBinsGlobal;
105  RadiusGeoIDPairSet curRadiusGeoIDs;
106  double minZ = 1e99;
107  double prevMinZ;
108  while (true) {
110 
111  // loop until a bin with minimum z value is found that
112  // differs at least m_tolerance from previous minZ
113  do {
114  ATH_MSG_VERBOSE(" (re)starting search for minZ");
115  prevMinZ = minZ;
116  minZ = 1e99;
117  curRadiusGeoIDs.clear();
118 
119  // loop over all geoIDs to find the bin with minimum z
120  for (int geoID=AtlasDetDescr::fFirstAtlasRegion; geoID<AtlasDetDescr::fNumAtlasRegions; ++geoID) {
121  size_t curTmpZBinIndex = tmpZBinIndex[geoID];
122  // ignore the current tmpZBins in case we already reached
123  // it's end
124  if ( curTmpZBinIndex >= tmpZBins[geoID].size()) continue;
125  double curZ = tmpZBins[geoID][curTmpZBinIndex];
126  // curZ==0 -> skip this one
127  if ( fabs(curZ)<m_tolerance) {
128  (tmpZBinIndex[geoID])++;
129  }
130  // curZ is the smallest z so far
131  // -> register it (minZ, minZGeoID)
132  // -> increment iterator for current tmpZBinIt
133  else if ( curZ<minZ) {
134  minZ = curZ;
135  minZGeoID = AtlasDetDescr::AtlasRegion(geoID);
136  }
137  double curR2 = tmpRBins[geoID][curTmpZBinIndex];
138 
139  ATH_MSG_VERBOSE("inserting pair: r="<< sqrt(curR2) <<
140  " geoID=" << geoID << " for minZ<=" << minZ);
141  curRadiusGeoIDs.insert( RadiusGeoIDPair(curR2, AtlasDetDescr::AtlasRegion(geoID)) );
142  } // geoID loop
143  // iterate the tmpZBinIndex for the one geoID giving the smallest z
144  (tmpZBinIndex[minZGeoID])++;
145  } while ( fabs(minZ-prevMinZ)<m_tolerance );
146 
147  // nothing more to do, all tmpZBins are read out already
148  if ( curRadiusGeoIDs.size()==0) break;
149  ATH_MSG_VERBOSE("Current minZ=" << minZ <<
150  " curRadiusGeoIDs.size()=" << curRadiusGeoIDs.size() );
151 
152  // add the current z bin to the temporary std vector
153  size_t curZBinGlobal = tmpZBinsGlobal.size();
154  tmpZBinsGlobal.push_back(minZ);
155  tmpRBinsGlobal[curZBinGlobal] = curRadiusGeoIDs;
156  };
157 
158  ATH_MSG_DEBUG("Converting volume representation into faster format");
159  // finally write the information in tmpZBinsGlobal and tmpRBinsGlobal
160  // into the m_zBins and m_radiusBins
161  m_numZBins = tmpZBinsGlobal.size();
162  m_zBins = new double[m_numZBins];
163  m_radiusBins = new RadiusGeoIDPair[(m_numZBins+1)*m_maxRBins];
164  // loop over m_zBins
165  for (int i=0; i<m_numZBins; i++) {
166  m_zBins[i] = tmpZBinsGlobal[i];
167  ATH_MSG_VERBOSE(" zBin=" << i << " for z<" << m_zBins[i]);
168 
169  RadiusGeoIDPairSet::iterator radIt = tmpRBinsGlobal[i].begin();
170  RadiusGeoIDPairSet::iterator radItEnd = tmpRBinsGlobal[i].end();
171  size_t ii = 0;
172  for ( ; radIt!=radItEnd; ++radIt) {
173  double curR = sqrt((*radIt).first);
174  // skip this one if it has radius==0
175  if (curR<m_tolerance) continue;
176 
177  ATH_MSG_VERBOSE(" radius<" << curR <<
178  " --> geoID=" << (*radIt).second);
179  m_radiusBins[i*m_maxRBins+ii++] = (*radIt);
180  }
181  // fill the last radius bin with fUndefinedGeoID
182  m_radiusBins[i*m_maxRBins+ii] = RadiusGeoIDPair( 1e99, AtlasDetDescr::fUndefinedAtlasRegion) ;
183  };
184 
185  return StatusCode::SUCCESS;
186 }
187 
188 
190 
191  // an arbitrary unitary direction with +1 in x,y,z
192  // (following this direction will cross any AtlasRegion boundary if position is close to it in the first place)
193  const Amg::Vector3D dir(1., 1., 1.);
194  const Amg::Vector3D dirUnit( dir.unit() );
195 
196  // create particle positions which are a bit forward and a bit aft of the current position
197  const Amg::Vector3D posFwd( pos + dirUnit*m_tolerance );
198  const Amg::Vector3D posAft( pos - dirUnit*m_tolerance );
199 
200  AtlasDetDescr::AtlasRegion geoIDFwd = identifyGeoID(posFwd);
201  AtlasDetDescr::AtlasRegion geoIDAft = identifyGeoID(posAft);
202 
203  // default case: particle is outside given geoID
205 
206  // only if either the fwd or the aft step is inside the given geoID,
207  // inside/surface cases need to be resolved
208  if ( (geoID == geoIDFwd) || (geoID == geoIDAft) ) {
209  // 1. inside
210  if ( geoIDFwd == geoIDAft ) {
212  // 2. surface
213  } else if ( geoIDFwd != geoIDAft ) {
215  }
216  }
217 
218  return where;
219 }
220 
221 
223 
224  // (1.) resolve z-bin number for the given z coordinate
225  // TODO: test if maybe a binary search is faster than
226  // this linear search
227  int zBin = 0;
228  double z = fabs(pos.z()) ;
229  while ( (zBin<m_numZBins) && (z>=m_zBins[zBin]) ) {
230  zBin++;
231  }
232  //ATH_MSG_VERBOSE(" zBin=" << zBin << " (z<"<<m_zBins[zBin]<<")");
233 
234  // (2.) use zBin to resolve the geoID via the m_radiusBins 2d-array
235  // TODO: test if maybe a binary search is faster than
236  // this linear search
237  int radiusBin = 0;
238  double r2 = pos.perp2();
239  while ( (m_radiusBins[zBin*m_maxRBins+radiusBin].second!=AtlasDetDescr::fUndefinedAtlasRegion) &&
240  (r2 >= m_radiusBins[zBin*m_maxRBins+radiusBin].first) ) {
241  radiusBin++;
242  }
243  //ATH_MSG_VERBOSE(" radiusBin=" << radiusBin <<
244  // " (r<"<< sqrt(m_radiusBins[zBin*m_maxRBins+radiusBin].first)<<")");
246  //ATH_MSG_VERBOSE(" --> geoID=" << m_radiusBins[zBin*m_maxRBins+radiusBin].second);
247 
248  // is AtlasDetDescr::fUndefinedAtlasRegion in case not found
249  AtlasDetDescr::AtlasRegion identifiedGeoID = m_radiusBins[zBin*m_maxRBins+radiusBin].second;
250  return identifiedGeoID;
251 }
252 
253 
255  const Amg::Vector3D &dir) const {
256 
257  // push the particle a little and check the volume it's in
258  AtlasDetDescr::AtlasRegion geoID = identifyGeoID( pos + dir.unit()*m_tolerance );
259 
260  // alternatively: before push-ing check the current position
261  //AtlasDetDescr::AtlasRegion geoID = identifyGeoID( pos);
262  //if (geoID == AtlasDetDescr::fUndefinedAtlasRegion) {
263  // const HepGeom::Vector3D<double> &posStep = pos + dir.unit();
264  // geoID = identifyGeoID( posStep);
265  //}
266 
267  return geoID;
268 }
269 
270 std::unique_ptr<ISF::RZPairList> ISF::GeoIDSvc::prepareRZPairs( AtlasDetDescr::AtlasRegion geoID) {
271  // fill RZPairLists with pairs of only positive z and only negative
272  // z values respectively. it is important to keep the pairs ordered
273  // in each list
274  //
275  std::unique_ptr<RZPairList> positiveZ = std::make_unique<RZPairList>();
276  std::unique_ptr<RZPairList> negativeZ = std::make_unique<RZPairList>();
277 
278  // ensure a proper numeric value for geoID
279  assertAtlasRegion(geoID);
280 
281  ATH_MSG_INFO( "Building envelope volume for '" << AtlasDetDescr::AtlasRegionHelper::getName(geoID)
282  << "' (GeoID="<< geoID << ").");
283 
284 
285  //
286  // fill the RZPairLists
287  //
288  {
289  // both RZPairList have to be empty
290  if ( positiveZ->size() || negativeZ->size() ) {
291  ATH_MSG_ERROR("Can not interpret the (r,z) pairs provided by the EnvelopeDefSvc");
292  positiveZ->clear();
293  negativeZ->clear();
294  return positiveZ;
295  }
296 
297  // retrieve the vector of (r,z) values from the EnvelopeDefSvc
298  const RZPairVector &rz = m_envDefSvc->getRZBoundary( geoID );
299 
300  // used in the loop over the RZPairVector entries
301  RZPairList *curRZList{};
302  RZPairList::iterator curRZInsertIt;
303  int signZChanges = 0; // count the number of pos/neg transitions in z
304  int prevZSign = sign(rz.at(0).second);
305 
306  // loop over the (r,z) pairs in the given RZPairVector
307  RZPairVector::const_iterator rzIt = rz.begin();
308  RZPairVector::const_iterator rzItEnd = rz.end();
309  for (; rzIt!=rzItEnd; ++rzIt) {
310  const RZPair &curRZ = *rzIt;
311  double curZ = curRZ.second;
312  int curZSign = sign(curZ);
313 
314  ATH_MSG_VERBOSE( " signZChanges=" << signZChanges<<
315  " curZSign=" <<curZSign<<
316  " prevZSign=" << prevZSign<<
317  " curZ=" <<curZ <<
318  " curR=" <<curRZ.first );
319 
320  // select negative RZPairList to fill
321  if ( curZSign==-1) curRZList = negativeZ.get();
322  // select positive RZPairList to fill
323  else if ( curZSign==1) curRZList = positiveZ.get();
324  // ignore 0.
325  else {
326  ATH_MSG_WARNING("Ignoring an (r,z) pair from the EnvelopeDefSvc with z==0.");
327  continue;
328  }
329 
330  // record if the sign has changed
331  if ( curZSign != prevZSign) {
332  signZChanges++;
333  prevZSign = curZSign;
334  // note the begin of the curRZList
335  // will be used in case the sign has changed twice
336  curRZInsertIt = curRZList->begin();
337  }
338 
339  // (#) the z sign changed at max once in this (r,z) list so far
340  // -> this is the simple case since we are filling the
341  // two RZPairLists from the to each
342  if ( signZChanges<2 ) {
343  curRZList->push_back(curRZ);
344  }
345 
346  // (#) the z sign changed twice in this (r,z) list so far
347  // -> insert the values from the front into the the current
348  // RZPairList
349  else if ( signZChanges==2 ) {
350  curRZList->insert( curRZInsertIt, curRZ );
351  }
352 
353  // (#) the z sign changed more than twice
354  // -> no implementation yet to handle this freakin' complicated case
355  else {
356  ATH_MSG_ERROR("Unable to interpret (r,z) pairs for envelope definition provided by the EnvelopeDefSvc" );
357  ATH_MSG_ERROR(" -> provided (r,z) pairs traverse the z==0 plane more than twice" );
358  positiveZ->clear();
359  negativeZ->clear();
360  return positiveZ;
361  }
362  }
363  }
364 
365  //
366  // verify that the RZPairLists are symmetric around z==0.
367  //
368  if ( (!checkSymmetric( *positiveZ, *negativeZ)) ) {
369  ATH_MSG_ERROR("(r,z) pairs received from EnvelopeDefSvc are not symmetric around z==0 plane");
370  positiveZ->clear();
371  negativeZ->clear();
372  return positiveZ;
373  }
374 
375  // add the z==0 entries to the RZList for the case of
376  // volumes crossing the z==0 plane
377  double frontR = positiveZ->front().first;
378  double backR = positiveZ->back().first;
379  positiveZ->push_front( RZPair(frontR, 0.) );
380  positiveZ->push_back( RZPair(backR , 0.) );
381 
382  // clear the RZPairList for negative z values
383  negativeZ->clear();
384 
385  // return the RZPairList for positive z values
386  return positiveZ;
387 }
388 
389 
391 bool ISF::GeoIDSvc::checkSymmetric( RZPairList& positiveZ, RZPairList& negativeZ) {
392  ATH_MSG_DEBUG("checking symmetry around z==0 plane for given (r,z) pairs");
393 
394  // require same size
395  if ( positiveZ.size() != negativeZ.size()) {
396  ATH_MSG_ERROR("Can not interpret the (r,z) pairs given by the EnvelopeDefSvc");
397  ATH_MSG_ERROR(" -> different number of (r,z) pairs on either side of the z==0 plane");
398  return false;
399  }
400 
401  // some debug output
402  //if ( msgLevel(MSG::VERBOSE)) {
403  // ATH_MSG_VERBOSE("(r,z) pairs on positive z side");
404  // RZPairList::iterator it = positiveZ.begin();
405  // RZPairList::iterator itEnd = positiveZ.end();
406  // for ( ; it!=itEnd; it++) ATH_MSG_VERBOSE(" r=" << it->first << " z=" << it->second);
407  // ATH_MSG_VERBOSE("(r,z) pairs on negative z side");
408  // it = negativeZ.begin();
409  // itEnd = negativeZ.end();
410  // for ( ; it!=itEnd; it++) ATH_MSG_VERBOSE(" r=" << it->first << " z=" << it->second);
411  //}
412 
413  // iterate over lists to compare (r,z) value pairs
414  RZPairList::iterator posIt = positiveZ.begin();
415  RZPairList::iterator posItEnd = positiveZ.end();
416  //RZPairList::iterator negItBegin = negativeZ.begin();
417  RZPairList::iterator negIt = negativeZ.end();
418 
419  while ( posIt != posItEnd) {
420  --negIt;
421 
422  // require that deltaR and deltaZ are the same within bounds
423  if ( fabs(negIt->first-posIt->first)>m_tolerance || fabs(negIt->second+posIt->second)>m_tolerance)
424  return false;
425 
426  ++posIt;
427  }
428 
429  // all fine
430  return true;
431 }
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
AtlasDetDescr::fNumAtlasRegions
@ fNumAtlasRegions
Definition: AtlasRegion.h:39
ISF::RadiusGeoIDPairSet
std::set< RadiusGeoIDPair, SortByRadius > RadiusGeoIDPairSet
Definition: GeoIDSvc.h:35
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
ISF::RadiusGeoIDPair
std::pair< double, AtlasDetDescr::AtlasRegion > RadiusGeoIDPair
Definition: GeoIDSvc.h:28
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
RZPairVector
std::vector< RZPair > RZPairVector
Definition: RZPair.h:18
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
AtlasDetDescr::AtlasRegion
AtlasRegion
Definition: AtlasRegion.h:27
ISF::InsideType
InsideType
Definition: IGeoIDSvc.h:22
AtlasDetDescr::fUndefinedAtlasRegion
@ fUndefinedAtlasRegion
Definition: AtlasRegion.h:29
ISF::fOutside
@ fOutside
Definition: IGeoIDSvc.h:23
ISF::GeoIDSvc::prepareRZPairs
std::unique_ptr< RZPairList > prepareRZPairs(AtlasDetDescr::AtlasRegion geoID)
Definition: GeoIDSvc.cxx:270
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
AtlasDetDescr::AtlasRegionHelper::getName
static const char * getName(int region)
Definition: AtlasRegionHelper.cxx:13
RZPair
std::pair< double, double > RZPair
Definition: RZPair.h:15
ISF::fSurface
@ fSurface
Definition: IGeoIDSvc.h:24
ISF::GeoIDSvc::initialize
StatusCode initialize()
Definition: GeoIDSvc.cxx:25
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
ISF::fInside
@ fInside
Definition: IGeoIDSvc.h:25
ISF::GeoIDSvc::identifyGeoID
AtlasDetDescr::AtlasRegion identifyGeoID(const Amg::Vector3D &pos) const
A static filter that returns the SimGeoID of the given position.
Definition: GeoIDSvc.cxx:222
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
ISF::RZPairList
std::list< RZPair > RZPairList
Definition: GeoIDSvc.h:29
lumiFormat.i
int i
Definition: lumiFormat.py:85
z
#define z
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
ISF::GeoIDSvc::identifyNextGeoID
AtlasDetDescr::AtlasRegion identifyNextGeoID(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const
Find the SimGeoID that the particle will enter with its next infinitesimal step along the given direc...
Definition: GeoIDSvc.cxx:254
sign
int sign(int a)
Definition: TRT_StrawNeighbourSvc.h:107
python.Utils.unixtools.where
def where(filename, prepath=[])
"which" for python files -------------------------------------------------—
Definition: unixtools.py:53
AtlasRegionHelper.h
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
ISF::GeoIDSvc::GeoIDSvc
GeoIDSvc(const std::string &name, ISvcLocator *svc)
Constructor with parameters.
Definition: GeoIDSvc.cxx:19
Handler::svc
AthROOTErrorHandlerSvc * svc
Definition: AthROOTErrorHandlerSvc.cxx:10
beamspotman.dir
string dir
Definition: beamspotman.py:623
ISF::GeoIDSvc::inside
ISF::InsideType inside(const Amg::Vector3D &pos, AtlasDetDescr::AtlasRegion geoID) const
Checks if the given position (or ISFParticle) is inside a given SimGeoID.
Definition: GeoIDSvc.cxx:189
GeoIDSvc.h
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:228
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
assertAtlasRegion
#define assertAtlasRegion(region)
Definition: AtlasRegion.h:16
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
ISF::GeoIDSvc::checkSymmetric
bool checkSymmetric(RZPairList &positiveZ, RZPairList &negativeZ)
Check if given RZPairLists are symmetric around z==0 plane.
Definition: GeoIDSvc.cxx:391
DeMoScan.first
bool first
Definition: DeMoScan.py:536
AtlasDetDescr::fFirstAtlasRegion
@ fFirstAtlasRegion
Definition: AtlasRegion.h:31