ATLAS Offline Software
Loading...
Searching...
No Matches
PLRGmxInterface.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "PLRGmxInterface.h"
6
18
22#include <GeoModelRead/ReadGeoModel.h>
23#include <GeoModelKernel/GeoFullPhysVol.h>
24
25
26
27namespace InDetDD
28{
29
31 SiCommonItems *commonItems,
32 WaferTree *moduleTree)
33 : PixelGmxInterface(detectorManager, commonItems, moduleTree)
34{}
35
36int PLRGmxInterface::sensorId(std::map<std::string, int> &index) const
37{
38 // Return the Simulation HitID (nothing to do with "ATLAS Identifiers" aka "Offline Identifiers")
39
40 // Check if identifier is valid
41 // TODO: drop this check in the future
42 const PLR_ID *pixelIdHelper = dynamic_cast<const PLR_ID *>(m_commonItems->getIdHelper());
43 if (not pixelIdHelper){
44 ATH_MSG_ERROR("Failed dynamic_cast to PLR_ID in PLRGmxInterface::sensorId");
45 return -1;
46 }
47 Identifier id = pixelIdHelper->wafer_id(index["barrel_endcap"],
48 index["layer_wheel"],
49 index["phi_module"],
50 index["eta_module"]);
51 IdentifierHash hashId = pixelIdHelper->wafer_hash(id);
52 if (!hashId.is_valid()) {
53 ATH_MSG_WARNING("PLR Invalid hash for Index list: " << index["barrel_endcap"] << " " << index["layer_wheel"] << " "
54 << index["eta_module"] << " " << index["phi_module"] << " " << index["side"]);
55 return -1;
56 }
57 // Compute the actuall SiHitId, first number is the part number: lumi=2
58 int hitIdOfModule = SiHitIdHelper::GetHelper()->buildHitId(2,
59 index["barrel_endcap"],
60 index["layer_wheel"],
61 index["eta_module"],
62 index["phi_module"],
63 index["side"]);
64 ATH_MSG_DEBUG("Index list: " << index["barrel_endcap"] << " " << index["layer_wheel"] << " "
65 << index["eta_module"] << " " << index["phi_module"] << " " << index["side"]);
66 ATH_MSG_DEBUG("hitIdOfModule = " << std::hex << hitIdOfModule << std::dec);
67 ATH_MSG_DEBUG(" bec = " << SiHitIdHelper::GetHelper()->getBarrelEndcap(hitIdOfModule)
68 << " lay = " << SiHitIdHelper::GetHelper()->getLayerDisk(hitIdOfModule)
69 << " eta = " << SiHitIdHelper::GetHelper()->getEtaModule(hitIdOfModule)
70 << " phi = " << SiHitIdHelper::GetHelper()->getPhiModule(hitIdOfModule)
71 << " side = " << SiHitIdHelper::GetHelper()->getSide(hitIdOfModule));
72
73 return hitIdOfModule;
74}
75
76
77void PLRGmxInterface::addSensorType(const std::string& clas,
78 const std::string& typeName,
79 const std::map<std::string, std::string>& parameters)
80{
81 ATH_MSG_DEBUG("addSensorType called for class " << clas << ", typeName " << typeName);
82 // only load the sensor type that the PLR will use
83 if (clas == "SingleChip_RD53" && (typeName == "RD53_20x19_Single_25x100" || typeName == "PLR_20x19_Single_25x100")) {
84 makePLRModule(typeName, parameters);
85 }
86}
87
88
89void PLRGmxInterface::addSensor(const std::string& typeName,
90 std::map<std::string, int> &index,
91 int /*sensitiveId*/,
92 GeoVFullPhysVol *fpv)
93{
94 //
95 // Get the ATLAS "Offline" wafer identifier
96 //
97 const PLR_ID *pixelIdHelper = dynamic_cast<const PLR_ID *>(m_commonItems->getIdHelper());
98 if (not pixelIdHelper){
99 ATH_MSG_ERROR("Failed dynamic_cast to PLR_ID in PLRGmxInterface::addSensor");
100 return;
101 }
102 Identifier id = pixelIdHelper->wafer_id(index["barrel_endcap"],
103 index["layer_wheel"],
104 index["phi_module"],
105 index["eta_module"]);
106 IdentifierHash hashId = pixelIdHelper->wafer_hash(id);
107 //
108 // Now do our best to check if this is a valid id. If either the gmx file is wrong, or the xml file
109 // defining the allowed id's is wrong, you can get disallowed id's. These cause a crash later
110 // if allowed through. To do the check, we ask for the hash-id of this id. Invalid ids give a
111 // special invalid hash-id (0xFFFFFFFF). But we don't exit the run, to help debug things quicker.
112 //
113 if (!hashId.is_valid()) {
114 ATH_MSG_ERROR("Invalid id for sensitive module " << typeName << " volume with indices");
115 for (const auto& [key, value] : index) {
116 msg() << MSG::ERROR << key << " = " << value << "; ";
117 }
118 msg() << MSG::ERROR << endmsg;
119 ATH_MSG_ERROR("Refusing to make it into a sensitive element. Incompatible gmx and identifier-xml files.");
120 return;
121 }
122
123 //
124 // Create the detector element and add to the DetectorManager
125 //
126 auto it = m_geometryMap.find(typeName);
127 if(it == m_geometryMap.end()) {
128 ATH_MSG_ERROR("addSensor: Error: Readout sensor type " << typeName << " not found.");
129 throw std::runtime_error("readout sensor type " + typeName + " not found.");
130 }
131 const SiDetectorDesign *design = m_detectorManager->getDesign(it->second);
132 ATH_MSG_VERBOSE("Adding sensor with design: " << typeName << " " << design);
133 if (design == nullptr) {
134 ATH_MSG_ERROR("addSensor: Error: Readout sensor type " << typeName << " not found.");
135 throw std::runtime_error("readout sensor type " + typeName + " not found.");
136 }
137
138 m_detectorManager->addDetectorElement(new SiDetectorElement(id, design, fpv, m_commonItems));
139
140 //
141 // Build up a map-structure for numerology
142 //
143 Wafer module((unsigned int) hashId);
144 std::string errorMessage("");
145 if (!m_moduleTree->add(index["barrel_endcap"],
146 index["layer_wheel"],
147 index["eta_module"],
148 index["phi_module"],
149 module,
150 errorMessage)) {
151 ATH_MSG_ERROR(errorMessage);
152 }
153
154 return;
155}
156
157
158void PLRGmxInterface::buildReadoutGeometryFromSqlite(IRDBAccessSvc * rdbAccessSvc,GeoModelIO::ReadGeoModel* sqlreader){
159
160 const std::array<std::string,1> sensorTypes{"SingleChip_RD53"};
161 const std::array<std::string,17> ParamNames{"circuitsPerEta", "circuitsPerPhi", "thickness", "is3D", "rows", "columns", "pitchEta", "pitchPhi", "pitchEtaLong", "pitchPhiLong", "pitchEtaEnd", "pitchPhiEnd", "nPhiLongPerSide", "nEtaLongPerSide", "nPhiEndPerSide", "nEtaEndPerSide", "detectorType"};
162 static const std::string empty;
163 for(const std::string & sType:sensorTypes){
164
165 IRDBRecordset_ptr PLR_module = rdbAccessSvc->getRecordsetPtr(sType,empty);
166
167 if(PLR_module->size() != 0){
168
169 for (const auto& typeParams : *PLR_module){
170 std::map<std::string,std::string> PLR_moduleMap;
171
172 for(const std::string & paramName:ParamNames){
173 std::string paramValue = typeParams->getString(paramName);
174 PLR_moduleMap[paramName] = std::move(paramValue);
175 }
176 std::string sensorName = typeParams->getString("SensorType");
177 addSensorType(sType, sensorName, PLR_moduleMap);
178 }
179 } else ATH_MSG_WARNING("Could not retrieve "<<sType<<" table");
180 }
181
182 //Now, loop over the FullPhysVols and create the SiDetectorElements
183 //lots of string parsing...
184 const std::array<std::string,5> fields{"barrel_endcap","layer_wheel","phi_module","eta_module","side"};
185 //First, find which name the tables are in the file under (depends upon the plugin used to create the input file)
186 //sort these in order of precedence - ITkPlugin, then ITkPixelPlugin, then GeoModelXMLPlugin
187 const std::array<std::string,3> publishers({"ITk","ITkPixel","GeoModelXML"});
188 //The below is a map of string keys which will contain all the Identifier/DetElement relevant info, and the associated FullPhysVol
189 // (once filled from the published table in the SQLite)
190 std::map<std::string, GeoFullPhysVol*> mapFPV;
191 for (auto & iPub : publishers){
192 //setting the "checkTable" option to true, so that an empty map will be returned if not found and we can try the next one
193 mapFPV = sqlreader->getPublishedNodes<std::string, GeoFullPhysVol*>(iPub,true);
194 if (!mapFPV.empty()) {
195 ATH_MSG_INFO("Using FPV tables from publisher "<<iPub);
196 break;
197 }
198 }
199 if (mapFPV.empty()) ATH_MSG_ERROR("Could not find any FPV tables under the expected names: "<<publishers);
200
201 for (const auto&[fullPhysVolInfoString, fullPhysVolPointer] : mapFPV){
202 //find the name of the corresponding detector design type
203 size_t startRG = fullPhysVolInfoString.find("PLR_");
204 if(startRG==std::string::npos){
205 ATH_MSG_DEBUG("GeoFullPhysVol "<<fullPhysVolInfoString<<" does not have the expected format. Skipping");
206 continue;
207 }
208 std::string typeName = fullPhysVolInfoString.substr(startRG);
209 std::map<std::string, int> index;
210 for (const std::string & field:fields){
211 size_t first = fullPhysVolInfoString.find(field+"_");
212 size_t last = fullPhysVolInfoString.find('_',first+field.size()+1); //start looking only after end of first delimiter (plus 1 for the "_" appended) ends
213 if(first==std::string::npos || last==std::string::npos){
214 ATH_MSG_WARNING("Could not extract "<<field<<" from "<<fullPhysVolInfoString<<". Skipping");
215 continue;
216 }
217 std::string strNew = fullPhysVolInfoString.substr(first+field.size()+1,last-(first+field.size()+1));
218 index[field] = std::stoi(strNew);
219 }
220 addSensor(typeName,index,0,fullPhysVolPointer);
221 }
222}
223
224
225
226void PLRGmxInterface::makePLRModule(const std::string &typeName,
227 const std::map<std::string, std::string> &parameters)
228{
229 int circuitsPerEta{1}; // row
230 int circuitsPerPhi{1}; // column
231 double thickness{0.150};
232 double pitchEta{};
233 double pitchPhi{};
234 double pitchEtaLong{};
235 double pitchPhiLong{};
236 double pitchEtaEnd{};
237 double pitchPhiEnd{};
238 int nEtaLongPerSide{};
239 int nPhiLongPerSide{};
240 int nEtaEndPerSide{};
241 int nPhiEndPerSide{};
242 int rowsPerCircuit{};
243 int columnsPerCircuit{};
244
245 // unused
247 int readoutSide{1};
248 bool is3D{true};
249
250 // read parameters
251 getParameter(typeName, parameters, "circuitsPerEta", circuitsPerEta);
252 getParameter(typeName, parameters, "circuitsPerPhi", circuitsPerPhi);
253 getParameter(typeName, parameters, "thickness", thickness);
254 getParameter(typeName, parameters, "is3D", is3D);
255 getParameter(typeName, parameters, "rows", rowsPerCircuit);
256 getParameter(typeName, parameters, "columns", columnsPerCircuit);
257 getParameter(typeName, parameters, "pitchEta", pitchEta);
258 getParameter(typeName, parameters, "pitchPhi", pitchPhi);
259 getParameter(typeName, parameters, "pitchEtaLong", pitchEtaLong);
260 getParameter(typeName, parameters, "pitchPhiLong", pitchPhiLong);
261 getParameter(typeName, parameters, "pitchEtaEnd", pitchEtaEnd);
262 getParameter(typeName, parameters, "pitchPhiEnd", pitchPhiEnd);
263 getParameter(typeName, parameters, "nPhiLongPerSide", nPhiLongPerSide);
264 getParameter(typeName, parameters, "nEtaLongPerSide", nEtaLongPerSide);
265 getParameter(typeName, parameters, "nPhiEndPerSide", nPhiEndPerSide);
266 getParameter(typeName, parameters, "nEtaEndPerSide", nEtaEndPerSide);
267
269
270 // helper function to associate attributes to sub-matrices and diodes.
271 auto computeAttribute = [pitchPhi,
272 pitchEta,
273 rowsPerCircuit,
274 columnsPerCircuit
275 ](const std::array<PixelDiodeTree::IndexType,2> &split_idx,
276 const PixelDiodeTree::Vector2D &diode_width,
277 [[maybe_unused]] const std::array<bool,4> &ganged,
278 [[maybe_unused]] unsigned int split_i,
279 PixelDiodeTree::AttributeType current_matrix_attribute,
280 PixelDiodeTree::AttributeType current_diode_attribute)
281 -> std::tuple<PixelDiodeTree::AttributeType,PixelDiodeTree::AttributeType>
282 {
283 assert (readoutTechnology==InDetDD::PixelReadoutTechnology::RD53);
284 // split_idx the absolute index at which this sub-matrix is split into 4 sub-sub-matrices
285 // diode_width the diode pitch in both directions
286 // ganged ganged[0],ganged[1] whether the pixel diode is ganged in the corresponding direction
287 // ganged[2],ganged[3] whether the diode is inside (true) or outside the dead zone
288 // where ganged[2] denotes the flag in local-x and ganged[3] in local-y direction
289 //
290 // split_i defines which of the 4 areas the diode belongs to : 2 | 3 ^
291 // ----- | local-y (chip-columns)
292 // 0 | 1 |
293 // ---> local-x (chip-rows)
294 //
295 // current_matrix_attribute the default attribute for the unsplit sub-matrix assigned by the builder
296 // current_diode_attribute the default attribute assigned to the current diode associated to the split
297 // area specified by split_i
298 // return new matrix attribute, new diode attribute
299
300 // if the pixel is significantly wider in one direction consider the pixel to be long
301 // or if wider in both directions large
302 assert(split_idx[0]>=0 && split_idx[1]>=0);
303 std::array<int,2> chip_idx{split_idx[0]/rowsPerCircuit, split_idx[1]/columnsPerCircuit};
304
305 unsigned int n_large_dimensions = ( (std::abs(diode_width[0]-pitchPhi)>pitchPhi*.25)
306 +(std::abs(diode_width[1]-pitchEta)>pitchEta*.25));
307 switch (n_large_dimensions) {
308 case 1:
310 break;
311 case 2:
313 break;
314 default:
316 }
317
318 current_matrix_attribute = InDetDD::detail::makeAttributeType(chip_idx[1] + chip_idx[0]*2);
319 return std::make_tuple(current_matrix_attribute, current_diode_attribute);
320 };
321
322 PixelDiodeTree diode_tree
323 = createPixelDiodeTree(std::array<unsigned int,2>{static_cast<unsigned int>(circuitsPerPhi),static_cast<unsigned int>(circuitsPerEta)},
324 std::array<unsigned int,2>{static_cast<unsigned int>(rowsPerCircuit),static_cast<unsigned int>(columnsPerCircuit)},
325 PixelDiodeTree::Vector2D{pitchPhi,pitchEta}, // regular ptich
326 std::array<std::array<unsigned int,2>, 2>{ std::array<unsigned int,2>{static_cast<unsigned int>(nPhiEndPerSide),
327 static_cast<unsigned int>(nEtaEndPerSide)}, // outer edge in pixels
328 std::array<unsigned int,2>{static_cast<unsigned int>(nPhiLongPerSide),
329 static_cast<unsigned int>(nEtaLongPerSide)}}, // inner edge in pixels
330 std::array<PixelDiodeTree::Vector2D,2>{PixelDiodeTree::Vector2D{pitchPhiEnd, pitchEtaEnd}, // outer edge pitch (correct?)
331 PixelDiodeTree::Vector2D{pitchPhiLong,pitchEtaLong} // inner edge pitch
332 },
333 std::array<std::array<unsigned int,2>, 2>{ std::array<unsigned int,2>{0u,0u}, // @TODO add dead zone for run1-3 pixels
334 std::array<unsigned int,2>{0u,0u} // @TODO add dead zone for run1-3 pixels
335 },
336 computeAttribute,
337 nullptr);
338
339 // Setting module identifier to InDetDD::PLR
340 // (so far) primarily useful to avoid orientation warnings
342
343 auto design = std::make_unique<PixelModuleDesign>(thickness,
344 circuitsPerPhi, circuitsPerEta,
345 columnsPerCircuit, rowsPerCircuit,
346 columnsPerCircuit, rowsPerCircuit,
347 std::move(diode_tree), carrier,
348 readoutSide, is3D, detectorType,
349 readoutTechnology);
350
351 ATH_MSG_DEBUG("readout geo - design " << typeName << " " << design->width() << "x" << design->length() << "x" << design->thickness()
352 << " " << design->rows() << "x" << design->columns()
353 << ", " << circuitsPerPhi << "x" << circuitsPerEta << " "
354 << rowsPerCircuit << "x" << columnsPerCircuit
355 << " carrier " << carrier << " readout side " << readoutSide << ":\n"
356 << diode_tree.debugStringRepr());
357
358 [[maybe_unused]] auto observedPtr = m_detectorManager->addDesign(std::move(design));
359
360 // Add to map for addModule routine
361 m_geometryMap[typeName] = m_detectorManager->numDesigns() - 1;
362}
363
364} // namespace InDetDD
#define endmsg
#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)
Definition of the abstract IRDBAccessSvc interface.
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
static const Attributes_t empty
MsgStream & msg() const
The standard message stream.
IRDBAccessSvc is an abstract interface to the athena service that provides the following functionalit...
virtual IRDBRecordset_ptr getRecordsetPtr(std::string_view node, std::string_view tag, std::string_view tag2node="", std::string_view connName="ATLASDD")=0
Provides access to the Recordset object containing HVS-tagged data.
virtual unsigned int size() const =0
This is a "hash" representation of an Identifier.
constexpr bool is_valid() const
PixelDetectorManager * m_detectorManager
PixelGmxInterface(PixelDetectorManager *detectorManager, SiCommonItems *commonItems, WaferTree *moduleTree)
std::map< std::string, int, std::less<> > 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
virtual void buildReadoutGeometryFromSqlite(IRDBAccessSvc *RDBAccessSvc, GeoModelIO::ReadGeoModel *sqlreader)
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:355
IdentifierHash wafer_hash(Identifier wafer_id) const
wafer hash from id
Definition PixelID.h:378
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