ATLAS Offline Software
Loading...
Searching...
No Matches
SCT_DetectorManager.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
10#include "Identifier/Identifier.h"
17
18#include <iostream>
19
20namespace InDetDD {
21
22 const int FIRST_HIGHER_LEVEL = 2;
23
24
27
29 const std::string& name,
30 const bool doEndcapEtaNeighbour )
31 : SiDetectorManager(detStore,name),
32 m_idHelper(nullptr),
33 m_isLogical(false), // Change to true to change the definition of local module corrections
34 m_doEndcapEtaNeighbour(doEndcapEtaNeighbour)
35 {
36 ATH_MSG_VERBOSE("Creating SCT_DetectorManager named " << name);
37 //
38 // Initialized the Identifier helper.
39 //
40 StatusCode sc = detStore->retrieve(m_idHelper, "SCT_ID");
41 if (sc.isFailure()) {
42 ATH_MSG_ERROR("Could not retrieve SCT id helper");
43 }
44 // Initialize the collections.
45 if (m_idHelper) {
46 m_elementCollection.resize(m_idHelper->wafer_hash_max());
47 m_alignableTransforms.resize(m_idHelper->wafer_hash_max());
48 m_moduleAlignableTransforms.resize(m_idHelper->wafer_hash_max()/2);
49 }
50 }
51
53 {
54 return m_volume.size();
55 }
56
57 PVConstLink SCT_DetectorManager::getTreeTop(unsigned int i) const
58 {
59 return m_volume[i];
60 }
61
62 void SCT_DetectorManager::addTreeTop(const PVConstLink& vol){
63 m_volume.push_back(vol);
64 }
65
67 {
68 // NB the id helpers implementation for getting a hash is not optimal.
69 // Essentially does a binary search.
70 // Make sure it is a wafer Id
71 Identifier waferId = m_idHelper->wafer_id(id);
72 IdentifierHash idHash = m_idHelper->wafer_hash(waferId);
73 if (idHash.is_valid()) {
74 return m_elementCollection[idHash];
75 } else {
76 return nullptr;
77 }
78 }
79
81 {
82 return m_elementCollection[idHash];
83 }
84
85 const SiDetectorElement* SCT_DetectorManager::getDetectorElement(int barrel_endcap, int layer_wheel, int phi_module, int eta_module, int side) const
86 {
87 return getDetectorElement(m_idHelper->wafer_id(barrel_endcap, layer_wheel, phi_module, eta_module, side));
88 }
89
94
99
104
109
114
115
116
118 {
119 IdentifierHash idHash = element->identifyHash();
120 if (idHash >= m_elementCollection.size())
121 throw std::runtime_error("SCT_DetectorManager: Error adding detector element.");
122 m_elementCollection[idHash] = element;
123 }
124
126 {
128
129 // Loop over all elements and set the neighbours
130 for (iter = m_elementCollection.begin(); iter != m_elementCollection.end(); ++iter){
131
132 SiDetectorElement * element = *iter;
133 if (element) {
134
135 IdentifierHash idHash = element->identifyHash();
136 IdentifierHash idHashOther;
137
138 int result;
139 // If no neighbour, result != 0 in which case we leave neighbour as null
140 if(element->isBarrel()){
141 result = m_idHelper->get_next_in_eta(idHash, idHashOther);
142 if (result==0) element->setNextInEta(m_elementCollection[idHashOther]);
143 }
144 else if(m_doEndcapEtaNeighbour){
145 // In endcaps the neighbours cannot be found with id+/-1, therefore we cannot rely on SCT_ID and need
146 // a dedicated search, considering only neighbour at larger radius (compatible wih outgoing particle)
147 result = getStripEndcapEtaNeighbour(element, idHashOther, false);
148 if(result==0) element->setNextInEta(m_elementCollection[idHashOther]);
149
150 // In ITk strip endcap, when we move from eta_module=9 to eta_module=10 we have change of module
151 // granularity in phi: twice more module in eta_module=10, therefore for module at eta_module=9
152 // and phi_module=phi we have two neighbours at larger radius: both at eta_module=10, but one with
153 // phi_module=2*phi the other with phi_module=2*phi+1, for completeness we store this neighbour in
154 // "PrevInEta" even if it is a misnomer in this case
155 if( m_idHelper->eta_module(element->identify())==9 ){
156 result = getStripEndcapEtaNeighbour(element, idHashOther, true);
157 if(result==0) element->setPrevInEta(m_elementCollection[idHashOther]);
158 }
159 }
160
161 result = m_idHelper->get_prev_in_eta(idHash, idHashOther);
162 if (result==0) element->setPrevInEta(m_elementCollection[idHashOther]);
163
164 result = m_idHelper->get_next_in_phi(idHash, idHashOther);
165 if (result==0) element->setNextInPhi(m_elementCollection[idHashOther]);
166
167 result = m_idHelper->get_prev_in_phi(idHash, idHashOther);
168 if (result==0) element->setPrevInPhi(m_elementCollection[idHashOther]);
169
170 result = m_idHelper->get_other_side(idHash, idHashOther);
171 if (result==0) element->setOtherSide(m_elementCollection[idHashOther]);
172 }
173 }
174 }
175
177 IdentifierHash& idHashNeighbour,
178 const bool phi_plus_one) const
179{
180 // Check we are well in strip endcap
181 if( !(element->isSCT() && element->isEndcap()) ) return 1;
182
183 // Now we try to find a neighbour at larger radius
184 Identifier id = element->identify();
185 int bec = m_idHelper->barrel_ec(id);
186 int layer_disk = m_idHelper->layer_disk(id);
187 int phi_module = m_idHelper->phi_module(id);
188 int eta_module = m_idHelper->eta_module(id);
189 int side = m_idHelper->side(id);
190
191 // We want to find neighbour only for elements on "main" side
192 // since the space points are made from trigger cluster (on side 0 for ITk)
193 // and stero cluster (on side 1 for ITk)
194 if(element->isStereo()) return 1;
195
196 // Most of the time we want to find neighbours in same phi
197 // but in transition region (eta_module 9->10) the module granularity in phi changes
198 // we have to look for two neighours, at: 2*phi and 2*phi+1
199 int target_phi = phi_module;
200 if (eta_module==9) target_phi = (phi_plus_one)? 2*phi_module+1 : 2*phi_module;
201
202 // Brute force search, loop on all elements to find a neighbour
203 for(const SiDetectorElement* other_element : m_elementCollection){
204
205 Identifier other_id = other_element->identify();
206
207 // To speed up the search, screening firt on bec, then layer_disk, etc...
208 int other_bec = m_idHelper->barrel_ec(other_id);
209 if(other_bec != bec) continue;
210
211 int other_layer_disk = m_idHelper->layer_disk(other_id);
212 if(other_layer_disk != layer_disk) continue;
213
214 int other_phi_module = m_idHelper->phi_module(other_id);
215 if(other_phi_module != target_phi) continue;
216
217 // We keep only neighbour at eta_module+1 (larger radius)
218 int other_eta_module = m_idHelper->eta_module(other_id);
219 if( (other_eta_module-eta_module) != 1 ) continue;
220
221 // We keep only neighbour on stereo side (side=1 for ITk)
222 int other_side = m_idHelper->side(other_id);
223 if(other_side==side) continue;
224
225 // If we are here, we found it!
226 idHashNeighbour = other_element->identifyHash();
227 ATH_MSG_VERBOSE(__FUNCTION__<<"found strip endcap neighbour for id="<<id<<" neigh="<<other_id
228 <<" eta:"<<eta_module<<" "<<other_eta_module);
229 return 0;
230 }
231
232 return 1;
233}
234
236 {
237 return m_idHelper;
238 }
239
240
242 const Identifier & id,
243 const Amg::Transform3D & delta,
244 FrameType frame,
245 GeoVAlignmentStore* alignStore) const
246 {
247
248 if (level == 0) { // 0 - At the element level
249
250 // We retrieve it via a hashId.
251 IdentifierHash idHash = m_idHelper->wafer_hash(id);
252 if (!idHash.is_valid()) return false;
253
254 if (frame == InDetDD::global) { // global shift
255 // Its a global transform
256 return setAlignableTransformGlobalDelta(m_alignableTransforms[idHash].get(), delta, alignStore);
257
258 } else if (frame == InDetDD::local) { // local shift
259
260 const SiDetectorElement * element = m_elementCollection[idHash];
261 if (!element) return false;
262
263
264 // Its a local transform
265 //See header file for definition of m_isLogical
266 if( m_isLogical ){
267 //Ensure cache is up to date and use the alignment corrected local to global transform
268 element->updateCache();
269 return setAlignableTransformLocalDelta(m_alignableTransforms[idHash].get(), element->transform(), delta, alignStore);
270 } else
271 //Use default local to global transform
272 return setAlignableTransformLocalDelta(m_alignableTransforms[idHash].get(), element->defTransform(), delta, alignStore);
273
274 } else {
275 // other not supported
276 ATH_MSG_WARNING("Frames other than global or local are not supported.");
277 return false;
278 }
279
280 } else if (level == 1) { // module level
281
282 // We retrieve it via a hashId.
283 IdentifierHash idHash = m_idHelper->wafer_hash(id);
284 if (!idHash.is_valid()) return false;
285
286 int idModuleHash = idHash / 2;
287
288 if (idHash%2) {
289 ATH_MSG_WARNING("Side 1 wafer id used for module id");
290 return false;
291 }
292
293 if (frame == InDetDD::global) { // global shift
294 // Its a global transform
295 return setAlignableTransformGlobalDelta(m_moduleAlignableTransforms[idModuleHash].get(), delta, alignStore);
296 } else if (frame == InDetDD::local) { // local shift
297 const SiDetectorElement * element = m_elementCollection[idHash];
298 if (!element) return false;
299
300 // Its a local transform
301 //See header file for definition of m_isLogical
302 if( m_isLogical ){
303 //Ensure cache is up to date and use the alignment corrected local to global transform
304 element->updateCache();
305 return setAlignableTransformLocalDelta(m_moduleAlignableTransforms[idModuleHash].get(), element->moduleTransform(), delta, alignStore);
306 } else
307 //Use default local to global transform
308 return setAlignableTransformLocalDelta(m_moduleAlignableTransforms[idModuleHash].get(), element->defModuleTransform(), delta, alignStore);
309
310 } else {
311 // other not supported
312 ATH_MSG_WARNING("Frames other than global or local are not supported.");
313 return false;
314 }
315
316 } else { // higher level
317
318 if (frame != InDetDD::global) {
319 ATH_MSG_WARNING("Non global shift at higher levels is not supported.");
320 return false;
321 }
322
323 int index = level - FIRST_HIGHER_LEVEL; // level 0 and 1 is treated separately.
324 if (index >= static_cast<int>(m_higherAlignableTransforms.size())) return false;
325
326 // We retrieve it from a map.
327 AlignableTransformMap::const_iterator iter;
328 iter = m_higherAlignableTransforms[index].find(id);
329 if (iter == m_higherAlignableTransforms[index].end()) return false;
330
331 // Its a global transform
332 return setAlignableTransformGlobalDelta((iter->second).get(), delta, alignStore);
333 }
334
335 }
336
338 const Identifier & id,
339 GeoAlignableTransform *transform,
340 const GeoVPhysVol * child)
341 {
342 if (m_idHelper) {
343
344 const GeoVFullPhysVol * childFPV = dynamic_cast<const GeoVFullPhysVol *>(child);
345 if (!childFPV) {
346 ATH_MSG_ERROR("Child of alignable transform is not a full physical volume");
347 } else {
348 addAlignableTransform (level, id, transform, childFPV);
349 }
350 }
351 }
352
354 const Identifier & id,
355 GeoAlignableTransform *transform,
356 const GeoVFullPhysVol * child)
357 {
358 if (m_idHelper) {
359 if (level == 0) {
360 // Element
361 IdentifierHash idHash = m_idHelper->wafer_hash(id);
362 if (idHash.is_valid()) {
363 m_alignableTransforms[idHash] = std::make_unique<ExtendedAlignableTransform>(transform, child);
364 }
365 } else if (level == 1) {
366 // Module
367 IdentifierHash idHash = m_idHelper->wafer_hash(id);
368 if (idHash.is_valid()) {
369 m_moduleAlignableTransforms[idHash/2] = std::make_unique<ExtendedAlignableTransform>(transform, child);
370 }
371
372 } else {
373
374 // Higher levels are saved in a map. NB level=0,1 is treated above.
375 int index = level - FIRST_HIGHER_LEVEL; // level 0 and 1 is treated separately.
376 if (index >= static_cast<int>(m_higherAlignableTransforms.size())) m_higherAlignableTransforms.resize(index+1);
377 m_higherAlignableTransforms[index][id] = std::make_unique<ExtendedAlignableTransform>(transform, child);
378 }
379 }
380 }
381
382 bool
384 {
385 return getIdHelper()->is_sct(id);
386 }
387
388
390 {
391 return dynamic_cast<const SCT_ModuleSideDesign *>(getDesign(i));
392 }
393
394 // New global alignment folders
395 bool SCT_DetectorManager::processGlobalAlignment(const std::string & key, int level, FrameType frame,
396 const CondAttrListCollection* obj, GeoVAlignmentStore* alignStore) const
397 {
398 ATH_MSG_INFO("Processing new global alignment containers with key " << key << " in the " << frame << " frame at level ");
399
400 const CondAttrListCollection* atrlistcol=obj;
401 if(atrlistcol==nullptr and m_detStore->retrieve(atrlistcol,key)!=StatusCode::SUCCESS) {
402 ATH_MSG_WARNING("Cannot find new global align Container for key "
403 << key << " - no new global alignment ");
404 return false;
405 }
406
407 bool alignmentChange = false;
408 Identifier ident=Identifier();
409
410 // loop over objects in collection
411 for (CondAttrListCollection::const_iterator citr=atrlistcol->begin(); citr!=atrlistcol->end();++citr) {
412 const coral::AttributeList& atrlist=citr->second;
413 // SCT manager, therefore ignore all that is not a SCT Identifier
414 if (atrlist["det"].data<int>()!=2) continue;
415
416 ident = getIdHelper()->wafer_id(atrlist["bec"].data<int>(),
417 atrlist["layer"].data<int>(),
418 atrlist["ring"].data<int>(),
419 atrlist["sector"].data<int>(),
420 0); // The last is the module side which is at this ident-level always the 0-side
421
422 // construct new transform
423 // Order of rotations is defined as around z, then y, then x.
424 Amg::Translation3D newtranslation(atrlist["Tx"].data<float>(),atrlist["Ty"].data<float>(),atrlist["Tz"].data<float>());
425 Amg::Transform3D newtrans = newtranslation * Amg::RotationMatrix3D::Identity();
426 newtrans *= Amg::AngleAxis3D(atrlist["Rz"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,0.,1.));
427 newtrans *= Amg::AngleAxis3D(atrlist["Ry"].data<float>()*CLHEP::mrad, Amg::Vector3D(0.,1.,0.));
428 newtrans *= Amg::AngleAxis3D(atrlist["Rx"].data<float>()*CLHEP::mrad, Amg::Vector3D(1.,0.,0.));
429
430 ATH_MSG_DEBUG("New global DB -- channel: " << citr->first
431 << " ,det: " << atrlist["det"].data<int>()
432 << " ,bec: " << atrlist["bec"].data<int>()
433 << " ,layer: " << atrlist["layer"].data<int>()
434 << " ,ring: " << atrlist["ring"].data<int>()
435 << " ,sector: " << atrlist["sector"].data<int>()
436 << " ,Tx: " << atrlist["Tx"].data<float>()
437 << " ,Ty: " << atrlist["Ty"].data<float>()
438 << " ,Tz: " << atrlist["Tz"].data<float>()
439 << " ,Rx: " << atrlist["Rx"].data<float>()
440 << " ,Ry: " << atrlist["Ry"].data<float>()
441 << " ,Rz: " << atrlist["Rz"].data<float>());
442
443 // Set the new transform; Will replace existing one with updated transform
444 bool status = setAlignableTransformDelta(level,
445 ident,
446 newtrans,
447 frame,
448 alignStore);
449
450 if (!status) {
451 ATH_MSG_DEBUG("Cannot set AlignableTransform for identifier."
452 << getIdHelper()->show_to_string(ident)
453 << " at level " << level << " for new global DB ");
454 }
455
456 alignmentChange = (alignmentChange || status);
457 }
458 return alignmentChange;
459 }
460
462 const std::string &, InDetDD::AlignFolderType) {
463 return false;
464}
465
466bool SCT_DetectorManager::processSpecialAlignment(const std::string& /*key*/,
467 const CondAttrListCollection* /*obj*/,
468 GeoVAlignmentStore* /*alignStore*/) const {
469 return false;
470
471}
472
473 void SCT_DetectorManager::addMotherDesign(std::unique_ptr<const SCT_ModuleSideDesign>&& motherDesign){
474 m_motherDesigns.push_back(std::move(motherDesign));
475 }
476
477} // namespace InDetDD
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
This file defines the class for a collection of AttributeLists where each one is associated with a ch...
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static Double_t sc
This is an Identifier helper class for the SCT subdetector.
bool is_sct(Identifier id) const
This class is a collection of AttributeLists where each one is associated with a channel number.
const_iterator end() const
const_iterator begin() const
Access to Chan/AttributeList pairs via iterators.
ChanAttrListMap::const_iterator const_iterator
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
DataModel_detail::iterator< DataVector > iterator
Definition DataVector.h:842
This is a "hash" representation of an Identifier.
bool is_valid() const
Check if id is in a valid state.
std::vector< std::unique_ptr< ExtendedAlignableTransform > > m_moduleAlignableTransforms
virtual void addDetectorElement(SiDetectorElement *element) override
Add elememts during construction.
virtual SiDetectorElementCollection::const_iterator getDetectorElementBegin() const override
virtual void initNeighbours() override
Initialize the neighbours. This can only be done when all elements are built.
SiDetectorElementCollection m_elementCollection
virtual const SCT_ID * getIdHelper() const override
virtual SiDetectorElementCollection::const_iterator getDetectorElementEnd() const override
SCT_DetectorManager(StoreGateSvc *detStore)
Constructor.
virtual unsigned int getNumTreeTops() const override
virtual const SiDetectorElement * getDetectorElement(const Identifier &id) const override
access to individual elements via Identifier
std::vector< PVConstLink > m_volume
bool m_isLogical
This variable switches the how the local alignment corrections are applied If true they will be calcu...
virtual void addAlignableTransform(int level, const Identifier &id, GeoAlignableTransform *xf, const GeoVFullPhysVol *child)
Add alignable transforms. No access to these, they will be changed by manager:
virtual bool setAlignableTransformDelta(int level, const Identifier &id, const Amg::Transform3D &delta, FrameType frame, GeoVAlignmentStore *alignStore) const override
implements the main alignment update for delta transforms in different frames, it translates into the...
const SCT_ModuleSideDesign * getSCT_Design(int i) const
Access to module design, casts to SCT_ModuleSideDesign.
void addTreeTop(const PVConstLink &vol)
Add tree top.
void addMotherDesign(std::unique_ptr< const SCT_ModuleSideDesign > &&)
std::vector< AlignableTransformMap > m_higherAlignableTransforms
virtual PVConstLink getTreeTop(unsigned int i) const override
virtual bool identifierBelongs(const Identifier &id) const override
Check identifier is for this detector.
bool processSpecialAlignment(const std::string &key, InDetDD::AlignFolderType alignfolder) override
Comply with InDetDetectorManager interface (not implemented for SCT)
int getStripEndcapEtaNeighbour(const SiDetectorElement *element, IdentifierHash &idHashNeighbour, const bool phi_plus_one=false) const
std::vector< std::unique_ptr< const SCT_ModuleSideDesign > > m_motherDesigns
virtual const SiDetectorElementCollection * getDetectorElementCollection() const override
access to whole collectiom
std::vector< std::unique_ptr< ExtendedAlignableTransform > > m_alignableTransforms
virtual bool processGlobalAlignment(const std::string &, int level, FrameType frame, const CondAttrListCollection *obj, GeoVAlignmentStore *alignStore) const override
Process new global DB folders for L1 and L2.
Base class for the SCT module side design, extended by the Forward and Barrel module design.
Class to hold the SiDetectorElement objects to be put in the detector store.
Class to hold geometrical description of a silicon detector element.
void setPrevInEta(const SiDetectorElement *element)
bool isStereo() const
Check if it is the stereo side (useful for SCT)
void setPrevInPhi(const SiDetectorElement *element)
void setNextInEta(const SiDetectorElement *element)
Amg::Transform3D defModuleTransform() const
Default module to global frame transform, ie with no misalignment.
void setOtherSide(const SiDetectorElement *element)
For SCT only.
void setNextInPhi(const SiDetectorElement *element)
const Amg::Transform3D & moduleTransform() const
Module to global frame transform.
SiDetectorManager(StoreGateSvc *detStore, const std::string &name)
const SiDetectorDesign * getDesign(int i) const
static bool setAlignableTransformGlobalDelta(ExtendedAlignableTransform *extXF, const Amg::Transform3D &delta, GeoVAlignmentStore *alignStore=nullptr)
Helper method to set delta transform from a global delta - Amg interface.
static bool setAlignableTransformLocalDelta(ExtendedAlignableTransform *extXF, const Amg::Transform3D &localToGlobalXF, const Amg::Transform3D &delta, GeoVAlignmentStore *alignStore=nullptr)
Helper method to set delta transform from a local delta - Amg interface.
virtual const Amg::Transform3D & transform() const override final
Return local to global transform.
virtual IdentifierHash identifyHash() const override final
identifier hash (inline)
virtual Identifier identify() const override final
identifier of this detector element (inline)
virtual void updateCache() const
Recalculate cached values.
This is an Identifier helper class for the SCT subdetector.
Definition SCT_ID.h:68
Identifier wafer_id(int barrel_ec, int layer_disk, int phi_module, int eta_module, int side) const
For a single side of module.
Definition SCT_ID.h:459
The Athena Transient Store API.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
Eigen::AngleAxisd AngleAxis3D
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 3, 1 > Vector3D
Eigen::Translation< double, 3 > Translation3D
Message Stream Member.
const int FIRST_HIGHER_LEVEL
Definition index.py:1