ATLAS Offline Software
Loading...
Searching...
No Matches
PLRGmxInterface.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "PLRGmxInterface.h"
6
17
18
19namespace InDetDD
20{
21
23 SiCommonItems *commonItems,
24 WaferTree *moduleTree)
25 : PixelGmxInterface(detectorManager, commonItems, moduleTree)
26{}
27
28int PLRGmxInterface::sensorId(std::map<std::string, int> &index) const
29{
30 // Return the Simulation HitID (nothing to do with "ATLAS Identifiers" aka "Offline Identifiers")
31
32 // Check if identifier is valid
33 // TODO: drop this check in the future
34 const PLR_ID *pixelIdHelper = dynamic_cast<const PLR_ID *>(m_commonItems->getIdHelper());
35 if (not pixelIdHelper){
36 ATH_MSG_ERROR("Failed dynamic_cast to PLR_ID in PLRGmxInterface::sensorId");
37 return -1;
38 }
39 Identifier id = pixelIdHelper->wafer_id(index["barrel_endcap"],
40 index["layer_wheel"],
41 index["phi_module"],
42 index["eta_module"]);
43 IdentifierHash hashId = pixelIdHelper->wafer_hash(id);
44 if (!hashId.is_valid()) {
45 ATH_MSG_WARNING("PLR Invalid hash for Index list: " << index["barrel_endcap"] << " " << index["layer_wheel"] << " "
46 << index["eta_module"] << " " << index["phi_module"] << " " << index["side"]);
47 return -1;
48 }
49 // Compute the actuall SiHitId, first number is the part number: lumi=2
50 int hitIdOfModule = SiHitIdHelper::GetHelper()->buildHitId(2,
51 index["barrel_endcap"],
52 index["layer_wheel"],
53 index["eta_module"],
54 index["phi_module"],
55 index["side"]);
56 ATH_MSG_DEBUG("Index list: " << index["barrel_endcap"] << " " << index["layer_wheel"] << " "
57 << index["eta_module"] << " " << index["phi_module"] << " " << index["side"]);
58 ATH_MSG_DEBUG("hitIdOfModule = " << std::hex << hitIdOfModule << std::dec);
59 ATH_MSG_DEBUG(" bec = " << SiHitIdHelper::GetHelper()->getBarrelEndcap(hitIdOfModule)
60 << " lay = " << SiHitIdHelper::GetHelper()->getLayerDisk(hitIdOfModule)
61 << " eta = " << SiHitIdHelper::GetHelper()->getEtaModule(hitIdOfModule)
62 << " phi = " << SiHitIdHelper::GetHelper()->getPhiModule(hitIdOfModule)
63 << " side = " << SiHitIdHelper::GetHelper()->getSide(hitIdOfModule));
64
65 return hitIdOfModule;
66}
67
68
69void PLRGmxInterface::addSensorType(const std::string& clas,
70 const std::string& typeName,
71 const std::map<std::string, std::string>& parameters)
72{
73 ATH_MSG_DEBUG("addSensorType called for class " << clas << ", typeName " << typeName);
74 // only load the sensor type that the PLR will use
75 if (clas == "SingleChip_RD53" && (typeName == "RD53_20x19_Single_25x100" || typeName == "PLR_20x19_Single_25x100")) {
76 makePLRModule(typeName, parameters);
77 }
78}
79
80
81void PLRGmxInterface::addSensor(const std::string& typeName,
82 std::map<std::string, int> &index,
83 int /*sensitiveId*/,
84 GeoVFullPhysVol *fpv)
85{
86 //
87 // Get the ATLAS "Offline" wafer identifier
88 //
89 const PLR_ID *pixelIdHelper = dynamic_cast<const PLR_ID *>(m_commonItems->getIdHelper());
90 if (not pixelIdHelper){
91 ATH_MSG_ERROR("Failed dynamic_cast to PLR_ID in PLRGmxInterface::addSensor");
92 return;
93 }
94 Identifier id = pixelIdHelper->wafer_id(index["barrel_endcap"],
95 index["layer_wheel"],
96 index["phi_module"],
97 index["eta_module"]);
98 IdentifierHash hashId = pixelIdHelper->wafer_hash(id);
99 //
100 // Now do our best to check if this is a valid id. If either the gmx file is wrong, or the xml file
101 // defining the allowed id's is wrong, you can get disallowed id's. These cause a crash later
102 // if allowed through. To do the check, we ask for the hash-id of this id. Invalid ids give a
103 // special invalid hash-id (0xFFFFFFFF). But we don't exit the run, to help debug things quicker.
104 //
105 if (!hashId.is_valid()) {
106 ATH_MSG_ERROR("Invalid id for sensitive module " << typeName << " volume with indices");
107 for (const auto& [key, value] : index) {
108 msg() << MSG::ERROR << key << " = " << value << "; ";
109 }
110 msg() << MSG::ERROR << endmsg;
111 ATH_MSG_ERROR("Refusing to make it into a sensitive element. Incompatible gmx and identifier-xml files.");
112 return;
113 }
114
115 //
116 // Create the detector element and add to the DetectorManager
117 //
118 auto it = m_geometryMap.find(typeName);
119 if(it == m_geometryMap.end()) {
120 ATH_MSG_ERROR("addSensor: Error: Readout sensor type " << typeName << " not found.");
121 throw std::runtime_error("readout sensor type " + typeName + " not found.");
122 }
123 const SiDetectorDesign *design = m_detectorManager->getDesign(it->second);
124 ATH_MSG_VERBOSE("Adding sensor with design: " << typeName << " " << design);
125 if (design == nullptr) {
126 ATH_MSG_ERROR("addSensor: Error: Readout sensor type " << typeName << " not found.");
127 throw std::runtime_error("readout sensor type " + typeName + " not found.");
128 }
129
130 m_detectorManager->addDetectorElement(new SiDetectorElement(id, design, fpv, m_commonItems));
131
132 //
133 // Build up a map-structure for numerology
134 //
135 Wafer module((unsigned int) hashId);
136 std::string errorMessage("");
137 if (!m_moduleTree->add(index["barrel_endcap"],
138 index["layer_wheel"],
139 index["eta_module"],
140 index["phi_module"],
141 module,
142 errorMessage)) {
143 ATH_MSG_ERROR(errorMessage);
144 }
145
146 return;
147}
148
149
150void PLRGmxInterface::makePLRModule(const std::string &typeName,
151 const std::map<std::string, std::string> &parameters)
152{
153 int circuitsPerEta{1}; // row
154 int circuitsPerPhi{1}; // column
155 double thickness{0.150};
156 double pitchEta{};
157 double pitchPhi{};
158 double pitchEtaLong{};
159 double pitchPhiLong{};
160 double pitchEtaEnd{};
161 double pitchPhiEnd{};
162 int nEtaLongPerSide{};
163 int nPhiLongPerSide{};
164 int nEtaEndPerSide{};
165 int nPhiEndPerSide{};
166 int rowsPerCircuit{};
167 int columnsPerCircuit{};
168
169 // unused
171 int readoutSide{1};
172 bool is3D{true};
173
174 // read parameters
175 getParameter(typeName, parameters, "circuitsPerEta", circuitsPerEta);
176 getParameter(typeName, parameters, "circuitsPerPhi", circuitsPerPhi);
177 getParameter(typeName, parameters, "thickness", thickness);
178 getParameter(typeName, parameters, "is3D", is3D);
179 getParameter(typeName, parameters, "rows", rowsPerCircuit);
180 getParameter(typeName, parameters, "columns", columnsPerCircuit);
181 getParameter(typeName, parameters, "pitchEta", pitchEta);
182 getParameter(typeName, parameters, "pitchPhi", pitchPhi);
183 getParameter(typeName, parameters, "pitchEtaLong", pitchEtaLong);
184 getParameter(typeName, parameters, "pitchPhiLong", pitchPhiLong);
185 getParameter(typeName, parameters, "pitchEtaEnd", pitchEtaEnd);
186 getParameter(typeName, parameters, "pitchPhiEnd", pitchPhiEnd);
187 getParameter(typeName, parameters, "nPhiLongPerSide", nPhiLongPerSide);
188 getParameter(typeName, parameters, "nEtaLongPerSide", nEtaLongPerSide);
189 getParameter(typeName, parameters, "nPhiEndPerSide", nPhiEndPerSide);
190 getParameter(typeName, parameters, "nEtaEndPerSide", nEtaEndPerSide);
191
193
194 // helper function to associate attributes to sub-matrices and diodes.
195 auto computeAttribute = [pitchPhi,
196 pitchEta,
197 rowsPerCircuit,
198 columnsPerCircuit
199 ](const std::array<PixelDiodeTree::IndexType,2> &split_idx,
200 const PixelDiodeTree::Vector2D &diode_width,
201 [[maybe_unused]] const std::array<bool,4> &ganged,
202 [[maybe_unused]] unsigned int split_i,
203 PixelDiodeTree::AttributeType current_matrix_attribute,
204 PixelDiodeTree::AttributeType current_diode_attribute)
205 -> std::tuple<PixelDiodeTree::AttributeType,PixelDiodeTree::AttributeType>
206 {
207 assert (readoutTechnology==InDetDD::PixelReadoutTechnology::RD53);
208 // split_idx the absolute index at which this sub-matrix is split into 4 sub-sub-matrices
209 // diode_width the diode pitch in both directions
210 // ganged ganged[0],ganged[1] whether the pixel diode is ganged in the corresponding direction
211 // ganged[2],ganged[3] whether the diode is inside (true) or outside the dead zone
212 // where ganged[2] denotes the flag in local-x and ganged[3] in local-y direction
213 //
214 // split_i defines which of the 4 areas the diode belongs to : 2 | 3 ^
215 // ----- | local-y (chip-columns)
216 // 0 | 1 |
217 // ---> local-x (chip-rows)
218 //
219 // current_matrix_attribute the default attribute for the unsplit sub-matrix assigned by the builder
220 // current_diode_attribute the default attribute assigned to the current diode associated to the split
221 // area specified by split_i
222 // return new matrix attribute, new diode attribute
223
224 // if the pixel is significantly wider in one direction consider the pixel to be long
225 // or if wider in both directions large
226 assert(split_idx[0]>=0 && split_idx[1]>=0);
227 std::array<int,2> chip_idx{split_idx[0]/rowsPerCircuit, split_idx[1]/columnsPerCircuit};
228
229 unsigned int n_large_dimensions = ( (std::abs(diode_width[0]-pitchPhi)>pitchPhi*.25)
230 +(std::abs(diode_width[1]-pitchEta)>pitchEta*.25));
231 switch (n_large_dimensions) {
232 case 1:
234 break;
235 case 2:
237 break;
238 default:
240 }
241
242 current_matrix_attribute = InDetDD::detail::makeAttributeType(chip_idx[1] + chip_idx[0]*2);
243 return std::make_tuple(current_matrix_attribute, current_diode_attribute);
244 };
245
246 PixelDiodeTree diode_tree
247 = createPixelDiodeTree(std::array<unsigned int,2>{static_cast<unsigned int>(circuitsPerPhi),static_cast<unsigned int>(circuitsPerEta)},
248 std::array<unsigned int,2>{static_cast<unsigned int>(rowsPerCircuit),static_cast<unsigned int>(columnsPerCircuit)},
249 PixelDiodeTree::Vector2D{pitchPhi,pitchEta}, // regular ptich
250 std::array<std::array<unsigned int,2>, 2>{ std::array<unsigned int,2>{static_cast<unsigned int>(nPhiEndPerSide),
251 static_cast<unsigned int>(nEtaEndPerSide)}, // outer edge in pixels
252 std::array<unsigned int,2>{static_cast<unsigned int>(nPhiLongPerSide),
253 static_cast<unsigned int>(nEtaLongPerSide)}}, // inner edge in pixels
254 std::array<PixelDiodeTree::Vector2D,2>{PixelDiodeTree::Vector2D{pitchPhiEnd, pitchEtaEnd}, // outer edge pitch (correct?)
255 PixelDiodeTree::Vector2D{pitchPhiLong,pitchEtaLong} // inner edge pitch
256 },
257 std::array<std::array<unsigned int,2>, 2>{ std::array<unsigned int,2>{0u,0u}, // @TODO add dead zone for run1-3 pixels
258 std::array<unsigned int,2>{0u,0u} // @TODO add dead zone for run1-3 pixels
259 },
260 computeAttribute,
261 nullptr);
262
263 // Setting module identifier to InDetDD::PLR
264 // (so far) primarily useful to avoid orientation warnings
266
267 auto design = std::make_unique<PixelModuleDesign>(thickness,
268 circuitsPerPhi, circuitsPerEta,
269 columnsPerCircuit, rowsPerCircuit,
270 columnsPerCircuit, rowsPerCircuit,
271 std::move(diode_tree), carrier,
272 readoutSide, is3D, detectorType,
273 readoutTechnology);
274
275 ATH_MSG_DEBUG("readout geo - design " << typeName << " " << design->width() << "x" << design->length() << "x" << design->thickness()
276 << " " << design->rows() << "x" << design->columns()
277 << ", " << circuitsPerPhi << "x" << circuitsPerEta << " "
278 << rowsPerCircuit << "x" << columnsPerCircuit
279 << " carrier " << carrier << " readout side " << readoutSide << ":\n"
280 << diode_tree.debugStringRepr());
281
282 [[maybe_unused]] auto observedPtr = m_detectorManager->addDesign(std::move(design));
283
284 // Add to map for addModule routine
285 m_geometryMap[typeName] = m_detectorManager->numDesigns() - 1;
286}
287
288} // namespace InDetDD
#define endmsg
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
MsgStream & msg() const
The standard message stream.
This is a "hash" representation of an Identifier.
bool is_valid() const
Check if id is in a valid state.
PixelDetectorManager * m_detectorManager
PixelGmxInterface(PixelDetectorManager *detectorManager, SiCommonItems *commonItems, WaferTree *moduleTree)
std::map< std::string, int > m_geometryMap
void makePLRModule(const std::string &typeName, const std::map< std::string, std::string > &parameters)
virtual void addSensorType(const std::string &clas, const std::string &typeName, const std::map< std::string, std::string > &parameters) override final
virtual int sensorId(std::map< std::string, int > &index) const override final
PLRGmxInterface(PixelDetectorManager *detectorManager, SiCommonItems *commonItems, WaferTree *moduleTree)
virtual void addSensor(const std::string &typeName, std::map< std::string, int > &index, int sequentialId, GeoVFullPhysVol *fpv) override final
Dedicated detector manager extending the functionality of the SiDetectorManager with dedicated pixel ...
Tree structure to find the position, index or pitch of a pixel on a semi-regular grid The grid is con...
std::string debugStringRepr() const
Dump the diode tree structure into a string.
Helper class to concentrate common items, such as the pointer to the IdHelper, the lorentzAngle tool ...
Base class for the detector design classes for Pixel and SCT.
Class to hold geometrical description of a silicon detector element.
This is a Identifier helper class for the PLR subdetector.
Definition PLR_ID.h:22
Identifier wafer_id(int barrel_ec, int layer_disk, int phi_module, int eta_module) const
For a single crystal.
Definition PixelID.h:360
IdentifierHash wafer_hash(Identifier wafer_id) const
wafer hash from id
Definition PixelID.h:383
int buildHitId(const int, const int, const int, const int, const int, const int) const
static const SiHitIdHelper * GetHelper()
InDetDD::PixelDiodeTree::AttributeType makeAttributeType(T val)
convenience method to convert the given value into an attribute
Message Stream Member.
PixelDiodeTree createPixelDiodeTree(const std::array< unsigned int, 2 > &chip_dim, const std::array< unsigned int, 2 > &chip_matrix_dim, const PixelDiodeTree::Vector2D &pitch, const std::array< std::array< unsigned int, 2 >, 2 > &edge_dim, const std::array< PixelDiodeTree::Vector2D, 2 > &edge_pitch, const std::array< std::array< unsigned int, 2 >, 2 > &dead_zone, const AttributeRefiner &func_compute_attribute, std::ostream *debug_out=nullptr)
Create a pixel diode tree.
Definition index.py:1