ATLAS Offline Software
ZDC_RPDModule.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "ZDC_RPDModule.h"
6 
7 #include "GeoModelKernel/GeoShape.h"
8 #include "GeoModelKernel/GeoBox.h"
9 #include "GeoModelKernel/GeoTube.h"
10 #include "GeoModelKernel/GeoLogVol.h"
11 #include "GeoModelKernel/GeoNameTag.h"
12 #include "GeoModelKernel/GeoPhysVol.h"
13 #include "GeoModelKernel/GeoFullPhysVol.h"
14 #include "GeoModelKernel/GeoTransform.h"
15 #include "GeoModelKernel/GeoIdentifierTag.h"
16 #include "GeoModelKernel/GeoAlignableTransform.h"
17 #include "GeoModelKernel/GeoDefinitions.h"
18 #include "GeoModelKernel/Units.h"
20 #include "GeoModelKernel/GeoMaterial.h"
21 #include "GaudiKernel/SystemOfUnits.h"
22 
24 #include "CLHEP/Geometry/Transform3D.h"
25 
26 void ZDC_RPDModule::create(GeoFullPhysVol* mother, GeoAlignableTransform* trf){
27 
28  MsgStream LogStream(Athena::getMessageSvc(), "ZDC_RPDModule::create");
29 
30  StoredMaterialManager *materialManager = nullptr;
31  if (StatusCode::SUCCESS != m_detectorStore->retrieve(materialManager, "MATERIALS")) {
32  MsgStream LogStream(Athena::getMessageSvc(), "ZDC_RPDModule::create");
33  LogStream << MSG::ERROR << "execute: Could not retrieve StoredMaterialManager object from the detector store" << endmsg;
34  return;
35  }
36 
37  const GeoMaterial *Aluminum = materialManager->getMaterial("std::Aluminium");
38  const GeoMaterial *OpAir = materialManager->getMaterial("ZDC::opticalAir");
39  const GeoMaterial *OpSilicaCore = materialManager->getMaterial("ZDC::opticalSilica");
40  const GeoMaterial *OpSilicaClad = materialManager->getMaterial("ZDC::opticalSilicaClad");
41  const GeoMaterial *OpKapton = materialManager->getMaterial("ZDC::opticalKapton");
42 
43  // All parameters are either in mm or are unitless
44  const int nRows = 4;
45  const int nCols = 4;
46  const float coreDia = 0.60; // Fiber core diameter
47  const float cladDia = 0.66; // Fiber cladding diameter
48  const float buffDia = 0.71; // Fiber buffer diameter
49  const float fiberPitchX = 1.425; // Spacing between fibers in X
50  const float fiberPitchZ = 1.63; // Spacing between fibers in Z
51  const float tileSize = 11.4; // Size of a square "tile"
52  const float housingThickness = 5; // Thickness of aluminum housing
53  const float detectorInnerWidth = 4 * tileSize; // Width (x) of the detector cavity which contains the fibers
54  const float detectorInnerDepth = 8 * fiberPitchZ + buffDia; // Depth (z) of the detector cavity which contains the fibers
55  const float footWidth = 91; // Width of the foot of the module
56  const float footDepth = 75; // Depth of the foot of the module
57  const float footHeight = 10; // Height of the foot of the module
58  const float posX = trf->getTransform().translation().x(); // X position of center of the tiles
59  const float posY = trf->getTransform().translation().y(); // Y position of center of the tiles
60  const float posZ = trf->getTransform().translation().z(); // Z position of center of the tiles
61 
62  const GeoBox* motherBox = dynamic_cast<const GeoBox*>(mother->getLogVol()->getShape());
63  const float halfY = motherBox->getYHalfLength();
64 
65  // Height of the extension between the main RPD body and the foot
66  const float detectorHeight = 2*halfY - footHeight; // Height of the detector minus the foot
67  const float readoutFiberLength = halfY - posY - 2*tileSize; // Length of the "readout" section of the fibers, not including the active area extension
68 
69  char volName[64];
70 
71  // Aluminum housing (case)
72  GeoBox *Housing_Box = new GeoBox((detectorInnerWidth + 2 * housingThickness) * Gaudi::Units::mm * 0.5,
73  detectorHeight * Gaudi::Units::mm * 0.5,
74  (detectorInnerDepth + 2 * housingThickness) * Gaudi::Units::mm * 0.5);
75 
76  GeoLogVol *Housing_Logical = new GeoLogVol("RPD_Housing_Logical", Housing_Box, Aluminum);
77  GeoFullPhysVol *Housing_Physical = new GeoFullPhysVol(Housing_Logical);
78 
79  // Detector inner volume
80  GeoBox *Module_Box = new GeoBox(detectorInnerWidth * Gaudi::Units::mm * 0.5,
81  readoutFiberLength * Gaudi::Units::mm * 0.5,
82  detectorInnerDepth * Gaudi::Units::mm * 0.5);
83 
84  GeoLogVol *Module_Logical = new GeoLogVol("RPD_Module_Logical", Module_Box, OpAir);
85  GeoPhysVol *Module_Physical = new GeoPhysVol(Module_Logical);
86 
87  // Foot
88  GeoBox *Foot_Box = new GeoBox(footWidth * Gaudi::Units::mm * 0.5,
89  footHeight * Gaudi::Units::mm * 0.5,
90  footDepth * Gaudi::Units::mm * 0.5);
91 
92  GeoLogVol *Foot_Logical = new GeoLogVol("RPD_Foot_Logical", Foot_Box, Aluminum);
93  GeoPhysVol *Foot_Physical = new GeoPhysVol(Foot_Logical);
94 
95  // Readout fiber volumes are made here because they're all the same length
96  // Core
97  GeoTube *Readout_Core_Tube = new GeoTube(0.0 * Gaudi::Units::mm, coreDia * Gaudi::Units::mm * 0.5, readoutFiberLength * Gaudi::Units::mm * 0.5);
98  GeoLogVol *Readout_Core_Logical = new GeoLogVol("RPD_Core_Readout_Logical", Readout_Core_Tube, OpSilicaCore);
99  GeoPhysVol *Readout_Core_Physical = new GeoPhysVol(Readout_Core_Logical);
100 
101  // Cladding
102  GeoTube *Readout_Clad_Tube = new GeoTube(coreDia * Gaudi::Units::mm * 0.5, cladDia * Gaudi::Units::mm * 0.5, readoutFiberLength * Gaudi::Units::mm * 0.5);
103  GeoLogVol *Readout_Clad_Logical = new GeoLogVol("RPD_Clad_Readout_Logical", Readout_Clad_Tube, OpSilicaClad);
104  GeoPhysVol *Readout_Clad_Physical = new GeoPhysVol(Readout_Clad_Logical);
105 
106  // Buffer
107  GeoTube *Readout_Buffer_Tube = new GeoTube(cladDia * Gaudi::Units::mm * 0.5, buffDia * Gaudi::Units::mm * 0.5, readoutFiberLength * Gaudi::Units::mm * 0.5);
108  GeoLogVol *Readout_Buffer_Logical = new GeoLogVol("RPD_Buff_Readout_Logical", Readout_Buffer_Tube, OpKapton);
109  GeoPhysVol *Readout_Buffer_Physical = new GeoPhysVol(Readout_Buffer_Logical);
110 
111  /***************************************************
112  *
113  * The fibers are positioned in a way that distributes of all channels in a given column evenly in z
114  * This is done by offsetting each fiber in x and z. For example, fibers for a single channel would look like this
115  *
116  * -0-------0--------
117  * ---0-------0------
118  * -----0-------0----
119  * -------0--------0-
120  *
121  * The cycle has been repeated twice in order to achieve a "tile" size of approximately 10mm (11.4) while maintaining maximum density of fibers
122  * Additionally this pattern is mirrored in z and interlaced with the first pattern. This is done to have uniformity in z for a given channel
123  *
124  * Pattern1 Pattern2 Sum
125  * -0-------0-------- -------0--------0- -0-----0-0------0-
126  * so ---0-------0------ + -----0-------0---- = ---0-0-----0-0----
127  * -----0-------0---- ---0-------0------ ---0-0-----0-0----
128  * -------0--------0- -0-------0-------- -0-----0-0------0-
129  *
130  * Everything above was for a single channel in row 0. Each row in a given colum starts the same pattern, just offset by fiberPitchZ
131  * So that looks like this, where the number represents the row
132  *
133  * -0--1--2--3--0--1--2--3--
134  * -3--0--1--2--3--0--1--2--
135  * -2--3--0--1--2--3--0--1--
136  * -1--2--3--0--1--2--3--0-
137  *
138  ****************************************************/
139 
140  float startX = tileSize * nCols * 0.5 - fiberPitchX / 4;
141  float startZ = -fiberPitchZ * (nCols - 0.5) * 0.5;
142  const unsigned int NFIBERS = 64; // Per row
143  for (int row = 0; row < nRows; ++row)
144  {
145  float fiberLength = (1 + row) * tileSize;
146  // float y = (-detectorHeight * 0.5 + housingThickness + tileSize * nRows - fiberLength * 0.5) * Gaudi::Units::mm;
147  float y = (posY - 0.5 * footHeight + 0.5 * tileSize * nRows - fiberLength * 0.5) * Gaudi::Units::mm;
148 
149  // Core
150  sprintf(volName, "RPD_Core_Active_Logical %d", row);
151  GeoTube *Active_Core_Tube = new GeoTube(0.0 * Gaudi::Units::mm, coreDia * Gaudi::Units::mm * 0.5, fiberLength * Gaudi::Units::mm * 0.5);
152  GeoLogVol *Active_Core_Logical= new GeoLogVol(volName, Active_Core_Tube, OpSilicaCore);
153  GeoPhysVol *Active_Core_Physical = new GeoPhysVol(Active_Core_Logical);
154 
155  // Cladding
156  sprintf(volName, "RPD_Clad_Active_Logical %d", row);
157  GeoTube *Active_Clad_Tube = new GeoTube(coreDia * Gaudi::Units::mm * 0.5, cladDia * Gaudi::Units::mm * 0.5, fiberLength * Gaudi::Units::mm * 0.5);
158  GeoLogVol *Active_Clad_Logical = new GeoLogVol(volName, Active_Clad_Tube, OpSilicaClad);
159  GeoPhysVol *Active_Clad_Physical = new GeoPhysVol(Active_Clad_Logical);
160 
161  // Buffer
162  sprintf(volName, "RPD_Buff_Active_Logical %d", row);
163  GeoTube *Active_Buffer_Tube = new GeoTube(cladDia * Gaudi::Units::mm * 0.5, buffDia * Gaudi::Units::mm * 0.5, fiberLength * Gaudi::Units::mm * 0.5);
164  GeoLogVol *Active_Buffer_Logical = new GeoLogVol(volName, Active_Buffer_Tube, OpKapton);
165  GeoPhysVol *Active_Buffer_Physical = new GeoPhysVol(Active_Buffer_Logical);
166 
167  for (uint fiber = 0; fiber < NFIBERS; ++fiber)
168  {
169 
170  // functions
171  int index = fiber * 0.5;
172  int pattern = fiber % 2;
173  int cycle = fiber / (2 * nCols) % 2;
174  int col = 2 * index / (nRows * nCols);
175  float cycleOffset = cycle * nCols * fiberPitchX;
176  float patternOffsetX = -pattern * fiberPitchX * 0.5;
177  float patternOffsetZ = pattern * fiberPitchZ * 0.5;
178 
179  float x = startX - tileSize * col - cycleOffset + patternOffsetX - index % 4 * fiberPitchX;
180  float z = startZ + fiberPitchZ * ((row + index % 4 + 2 * pattern) % 4) + patternOffsetZ;
181 
182  int channel = 4*row + col;
183 
184  std::string channelHashStr = m_zdcID->channel_id(m_side,m_module,ZdcIDType::ACTIVE,channel).getString();
186 
187 
188  /*******************************************
189  * Core
190  ********************************************/
191 
192  // Active region core get placed in aluminum
193 
194  // Active area
195  sprintf(volName, "ZDC::RPD_Core_Active %s", channelHashStr.c_str());
196  Housing_Physical->add(new GeoNameTag(volName));
197  Housing_Physical->add(new GeoIdentifierTag(channelHash));
198  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, y * Gaudi::Units::mm, z * Gaudi::Units::mm)));
199  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
200  Housing_Physical->add(Active_Core_Physical);
201 
202  // Readout Fiber
203  sprintf(volName, "ZDC::RPD_Core_Readout %s", channelHashStr.c_str());
204  Module_Physical->add(new GeoNameTag(volName));
205  Module_Physical->add(new GeoIdentifierTag(channelHash));
206  Module_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, 0.0, z * Gaudi::Units::mm)));
207  Module_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
208  Module_Physical->add(Readout_Core_Physical);
209 
210  /*******************************************
211  * Cladding
212  ********************************************/
213 
214  // Active area
215  sprintf(volName, "ZDC::RPD_Clad_Active %s", channelHashStr.c_str());
216  Housing_Physical->add(new GeoNameTag(volName));
217  Housing_Physical->add(new GeoIdentifierTag(channelHash));
218  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, y * Gaudi::Units::mm, z * Gaudi::Units::mm)));
219  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
220  Housing_Physical->add(Active_Clad_Physical);
221 
222  // Readout
223  sprintf(volName, "ZDC::RPD_Clad_Readout %s", channelHashStr.c_str());
224  Module_Physical->add(new GeoNameTag(volName));
225  Module_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, 0.0, z * Gaudi::Units::mm)));
226  Module_Physical->add(new GeoIdentifierTag(channelHash));
227  Module_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
228  Module_Physical->add(Readout_Clad_Physical);
229 
230  /*******************************************
231  * Buffer
232  ********************************************/
233 
234  // Active area
235  sprintf(volName, "ZDC::RPD_Buffer_Active %s", channelHashStr.c_str());
236  Housing_Physical->add(new GeoNameTag(volName));
237  Housing_Physical->add(new GeoIdentifierTag(channelHash));
238  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, y * Gaudi::Units::mm, z * Gaudi::Units::mm)));
239  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
240  Housing_Physical->add(Active_Buffer_Physical);
241 
242  // Readout Fiber
243  sprintf(volName, "ZDC::RPD_Buffer_Readout %s", channelHashStr.c_str());
244  Module_Physical->add(new GeoNameTag(volName));
245  Module_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, 0.0, z * Gaudi::Units::mm)));
246  Module_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
247  Module_Physical->add(new GeoIdentifierTag(channelHash));
248  Module_Physical->add(Readout_Buffer_Physical);
249 
250  } // end loop over fibers
251  }// end loop over rows
252 
253  Identifier id;
254 
255  // Place the fiber routing volume
257  sprintf(volName, "ZDC::RPD_Air_Cavity %s", id.getString().c_str());
258  Housing_Physical->add(new GeoNameTag(volName));
259  Housing_Physical->add(new GeoIdentifierTag( id.get_identifier32().get_compact()));
260  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::TranslateY3D( 0.5 * (detectorHeight - readoutFiberLength) * Gaudi::Units::mm)));
261  Housing_Physical->add(Module_Physical);
262 
263  // Place the foot in the mother volume
265  sprintf(volName, "ZDC::RPD_Foot %s",id.getString().c_str());
266  mother->add(new GeoNameTag(volName));
267  mother->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
268  mother->add(new GeoAlignableTransform(GeoTrf::Translate3D(posX * Gaudi::Units::mm, (-halfY + footHeight * 0.5) * Gaudi::Units::mm, posZ * Gaudi::Units::mm)));
269  mother->add(Foot_Physical);
270 
271  // Place the module in the mother volume
273  sprintf(volName, "Zdc::RPD_Mod %s", id.getString().c_str());
274  mother->add(new GeoNameTag(volName));
275  mother->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
276  mother->add(new GeoAlignableTransform(GeoTrf::Translate3D(posX * Gaudi::Units::mm, 0.5 * footHeight * Gaudi::Units::mm, posZ * Gaudi::Units::mm)));
277  mother->add(Housing_Physical);
278 
279 }
mergePhysValFiles.pattern
pattern
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:26
query_example.row
row
Definition: query_example.py:24
HOUSING
@ HOUSING
Definition: ZdcID.h:22
plotting.yearwise_efficiency.channel
channel
Definition: yearwise_efficiency.py:24
getMessageSvc.h
singleton-like access to IMessageSvc via open function and helper
ZDC_ModuleBase::m_module
int m_module
Definition: ZDC_ModuleBase.h:41
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
index
Definition: index.py:1
cycle
double cycle(double a, double b)
Definition: SiHitCollectionCnv_p2.cxx:38
ZDC_RPDModule::create
virtual void create(GeoFullPhysVol *mother, GeoAlignableTransform *trf) override
Definition: ZDC_RPDModule.cxx:26
Identifier::get_identifier32
Identifier32 get_identifier32() const
Get the 32-bit version Identifier, will be invalid if >32 bits needed.
deg
#define deg
Definition: SbPolyhedron.cxx:17
beamspotman.posX
posX
Definition: beamspotman.py:1624
AIR
@ AIR
Definition: ZdcID.h:22
x
#define x
Identifier32::get_compact
value_type get_compact() const
Get the compact id.
Definition: Identifier32.h:44
Athena::getMessageSvc
IMessageSvc * getMessageSvc(bool quiet=false)
Definition: getMessageSvc.cxx:20
ZDC_RPDModule.h
NFIBERS
#define NFIBERS
Definition: TileLaserDefaultCalibTool.h:40
StoreGateSvc::retrieve
StatusCode retrieve(const T *&ptr) const
Retrieve the default object into a const T*.
ZdcID::channel_id
Identifier channel_id(int side, int module, int type, int channel) const
Definition: ZdcID.h:205
uint
unsigned int uint
Definition: LArOFPhaseFill.cxx:20
z
#define z
ZDC_ModuleBase::m_detectorStore
StoreGateSvc * m_detectorStore
Definition: ZDC_ModuleBase.h:39
ZDC_ModuleBase::m_zdcID
const ZdcID * m_zdcID
Definition: ZDC_ModuleBase.h:42
beamspotman.posZ
posZ
Definition: beamspotman.py:1624
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
RPDUtils::nCols
unsigned constexpr int nCols
Definition: RPDUtils.h:25
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:227
StoredMaterialManager.h
query_example.col
col
Definition: query_example.py:7
ZDC_ModuleBase::m_side
int m_side
Definition: ZDC_ModuleBase.h:40
beamspotman.posY
posY
Definition: beamspotman.py:1624
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
Identifier::getString
std::string getString() const
Provide a string form of the identifier - hexadecimal.
Definition: Identifier.cxx:25
y
#define y
StoredMaterialManager::getMaterial
virtual const GeoMaterial * getMaterial(const std::string &name)=0
StoredMaterialManager
This class holds one or more material managers and makes them storeable, under StoreGate.
Definition: StoredMaterialManager.h:28
ACTIVE
@ ACTIVE
Definition: ZdcID.h:21
RPDUtils::nRows
unsigned constexpr int nRows
Definition: RPDUtils.h:24
CaloLCW_tf.trf
trf
Definition: CaloLCW_tf.py:20
INACTIVE
@ INACTIVE
Definition: ZdcID.h:21
Identifier
Definition: IdentifierFieldParser.cxx:14