Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
ZDC_ZDCModule.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 "ZDC_ZDCModule.h"
6 
7 #include "GeoModelKernel/GeoElement.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/GeoIdentifierTag.h"
15 #include "GeoModelKernel/GeoAlignableTransform.h"
16 #include "GeoModelKernel/GeoDefinitions.h"
17 #include "GeoModelKernel/Units.h"
18 #include "GaudiKernel/SystemOfUnits.h"
19 #include "StoreGate/StoreGateSvc.h"
21 #include "GeoModelKernel/GeoMaterial.h"
22 
23 #include "ZdcIdentifier/ZdcID.h"
25 #include "CLHEP/Geometry/Transform3D.h"
26 
28  : ZDC_ModuleBase(),
29  m_modType(1)
30 {
31 }
32 
33 ZDC_ZDCModule::ZDC_ZDCModule(const std::string& name, int side, int module, int modType)
35  m_modType(modType)
36 {
37 }
38 
41 {
42  m_modType = right->m_modType;
43 }
44 
45 
46 void ZDC_ZDCModule::create(GeoFullPhysVol* mother, StoredMaterialManager *materialManager, const ZdcID *zdcID){
47 
48  MsgStream LogStream(Athena::getMessageSvc(), "ZDC_ZDCModule::create");
49 
50  const GeoMaterial *OpAir = materialManager->getMaterial("ZDC::opticalAir" );
51  const GeoMaterial *OpSilica = materialManager->getMaterial("ZDC::opticalSilica");
52  const GeoMaterial *Silica = materialManager->getMaterial("std::Quartz" );
53  const GeoMaterial *Tungsten = materialManager->getMaterial("ZDC::Tungsten" );
54  const GeoMaterial *Steel = materialManager->getMaterial("ZDC::Steel" );
55 
56  // geometric constants. All units are in millimeters unless otherwise specified.
57  // All dimensions are gathered from technical drawings available at TODO: insert link to tech drawings
58 
59  // Dimensions determined by the pixel modules
60  // Both modules with pixels equipped and without have features determined by the pixel geometry, namely the gap number and spacing between
61  // groups of vertical radiator rods
62  const float pixelPitch = 10.3; // pixel rod pitch in both x and y
63  const float pixelGap = 1.2; // distance between the main fiber channels for the pixel fibers to be routed
64  const float pixelRodDia = 1.0; // diameter of the quartz rods used for the pixel
65  const float pixelHoleDia = 1.35; // diameter of the holes drilled in the tungsten plates which the pixel rods pass through
66  const int nPixelHolesX = 8; // number of positions for pixel rods in x (May or may not contain a quartz rod)
67  const int nPixelHolesY = 16; // number of positions for pixel rods in y (May or may not contain a quartz rod)
68  const float firstPixelX = -pixelPitch * (nPixelHolesX - 1) * 0.5; // Position of the outter most pixel placement in x
69  const float firstPixelY = -pixelPitch * (nPixelHolesY - 1) * 0.5; // Position of the lowest pixel placement in y
70 
71 
72  // These dimensions exist independent of the pixels (Though some still involve pixel dimensions for inter compatibility)
73  const float radiator_gap_depth = 2.0; // Depth of the radiator gap
74  const int nRadGaps = 12; // number of radiator gaps
75  const float strip_diameter = 1.5; // Diameter of the vertical quartz rods
76  const float absorber_width = 89.57; // Width (x) of the tungsten absorber
77  const float absorber_depth = 10.0; // Depth (z) of the tungsten absorber
78  const float absorber_height = 180.0; // Height (y) of the tungsten absorber
79  const float wallThicknessFront = 10.0; // Depth (z) of the steel case wall closest to the IP
80  const float wallThicknessSide = 1.21; // Thickness of the side walls (x) of the module
81  const float floorThickness = 1.21; // Thickness of the bottom of the module
82  const float zPitch = radiator_gap_depth + absorber_depth; // tungsten plate/quartz rod pitch in z
83  const float strip_gap_center = pixelPitch - pixelGap; // Width of the center channels for quartz rods
84  const float strip_gap_edge = (absorber_width - pixelPitch * (nPixelHolesX - 1) - pixelGap) * 0.5; // Width of the edge channels for quartz rods
85  const int nRods_center_gap = 6; // Number of rods in the center gaps
86  const int nRods_edge_gap = 5; // Number of rods in the edge gaps
87  const float housing_width = absorber_width + 2 * wallThicknessSide; // Width (x) of the steel module case
88  const float housing_height = absorber_height + floorThickness; // Height (y) of the steel module case
89 
90 
91  // These dimensions are for the default module type 1, but are modified by the presence of pixels
92  float zBackCavity = 0.0; // extra air cavity for pixel rods routing to the readout
93  float wallThicknessBack = 10.0; // Depth (z) of the steel case wall furthest from the IP
94  float rearCoverThickness = 0.0; // Thickness of additional rear cover for pixel modules
95  int pixelStart = 0, pixelStop = 0; // Start and stop rows for pixel rods
96 
97  //Set the dimensions for module type 2 or 3
98  switch (m_modType){
99  case 1: //type 1 (no pixel)
100  break;
101  case 2: //type 2 (pixel)
102  pixelStop = 9;
103  wallThicknessBack = 8.0;
104  rearCoverThickness = 1.21;
105  zBackCavity = 28;
106  break;
107  case 3: //type 3 (Bigger back cavity)
108  pixelStart = 1;
109  pixelStop = 8;
110  wallThicknessBack = 8.0;
111  rearCoverThickness = 1.21;
112  zBackCavity = 102;
113  break;
114  default:
115  LogStream << MSG::ERROR << "Invalid module type: " << m_modType << endmsg;
116  return;
117  }
118 
119 
120  // Finally calculate the total module z depth
121  const float housing_depth = (nRadGaps - 1) * zPitch + radiator_gap_depth + wallThicknessFront + wallThicknessBack + zBackCavity + rearCoverThickness;
122 
123  /*************************************************
124  * Create the volumes that are used independent of
125  * module type
126  **************************************************/
127  GeoTube *Strip_Tube = new GeoTube (0.0 * Gaudi::Units::mm , strip_diameter * Gaudi::Units::mm * 0.5, absorber_height * Gaudi::Units::mm * 0.5);
128  GeoBox *Steel_Box = new GeoBox (housing_width * Gaudi::Units::mm * 0.5, housing_height * Gaudi::Units::mm * 0.5, housing_depth * Gaudi::Units::mm * 0.5);
129  GeoBox *RadGap_Box = new GeoBox (absorber_width * Gaudi::Units::mm * 0.5, absorber_height * Gaudi::Units::mm * 0.5, radiator_gap_depth * Gaudi::Units::mm * 0.5);
130  GeoBox *Abs_Box = new GeoBox (absorber_width * Gaudi::Units::mm * 0.5, absorber_height * Gaudi::Units::mm * 0.5, absorber_depth * Gaudi::Units::mm * 0.5);
131 
132  GeoLogVol *Strip_Logical = new GeoLogVol("Strip_Logical" , Strip_Tube , OpSilica );
133  GeoLogVol *Steel_Logical = new GeoLogVol("Steel_Logical" , Steel_Box , Steel );
134  GeoLogVol *RadGap_Logical = new GeoLogVol("RadGap_Logical" , RadGap_Box , OpAir );
135  GeoLogVol *Abs_Plate_Logical = new GeoLogVol("Abs_Plate_Logical" , Abs_Box , Tungsten );
136 
137  GeoFullPhysVol *Housing_Physical = new GeoFullPhysVol(Steel_Logical );
138  GeoFullPhysVol *Abs_Plate = new GeoFullPhysVol(Abs_Plate_Logical);
139  GeoFullPhysVol *RadiatorGap = new GeoFullPhysVol(RadGap_Logical );
140 
141  // Surrogate ID and string to give the volumes dynamic references
142  Identifier id;
143  char volName[256];
144 
145  /*************************************************
146  * Pre-assemble tungsten plates, radiator gaps, and
147  * steel housing with pixel holes and rods if applicable
148  **************************************************/
149  if(m_modType > 1){
150 
151  // Z position of the inner wall that the pixel rods pass through
152  const float inner_wall_z = -0.5 * housing_depth + wallThicknessFront + (nRadGaps - 1) * zPitch + radiator_gap_depth + 0.5 * wallThicknessBack ;
153 
154  GeoTube *Pixel_Rod_Abs = new GeoTube ( 0.0 * Gaudi::Units::mm , pixelRodDia * Gaudi::Units::mm * 0.5 , absorber_depth * Gaudi::Units::mm * 0.5 );
155  GeoTube *Pixel_Rod_Rad = new GeoTube ( 0.0 * Gaudi::Units::mm , pixelRodDia * Gaudi::Units::mm * 0.5 , radiator_gap_depth * Gaudi::Units::mm * 0.5 );
156  GeoTube *Pixel_Rod_Housing = new GeoTube ( 0.0 * Gaudi::Units::mm , pixelRodDia * Gaudi::Units::mm * 0.5 , wallThicknessBack * Gaudi::Units::mm * 0.5 );
157  GeoTube *Pixel_Hole_Abs = new GeoTube ( 0.0 * Gaudi::Units::mm , pixelHoleDia * Gaudi::Units::mm * 0.5 , absorber_depth * Gaudi::Units::mm * 0.5 );
158  GeoTube *Pixel_Hole_Housing = new GeoTube ( 0.0 * Gaudi::Units::mm , pixelHoleDia * Gaudi::Units::mm * 0.5 , wallThicknessBack * Gaudi::Units::mm * 0.5 );
159  GeoBox *Pixel_Routing_Box = new GeoBox (absorber_width * Gaudi::Units::mm* 0.5, absorber_height * Gaudi::Units::mm * 0.5 , zBackCavity * Gaudi::Units::mm * 0.5 );
160 
161  GeoLogVol *Pixel_Abs_Logical = new GeoLogVol("Pixel_Abs_Logical" , Pixel_Rod_Abs , Silica );
162  GeoLogVol *Pixel_Rad_Logical = new GeoLogVol("Pixel_Rad_Logical" , Pixel_Rod_Rad , Silica );
163  GeoLogVol *Pixel_House_Logical = new GeoLogVol("Pixel_House_Logical" , Pixel_Rod_Housing , Silica );
164  GeoLogVol *Pixel_Hole_Abs_Logical = new GeoLogVol("Pixel_Hole_Logical" , Pixel_Hole_Abs , OpAir );
165  GeoLogVol *Pixel_Hole_House_Logical = new GeoLogVol("Pixel_Hole_House_Logical" , Pixel_Hole_Housing , OpAir );
166  GeoLogVol *Pixel_Routing_Logical = new GeoLogVol("Pixel_Routing_Logical" , Pixel_Routing_Box , OpAir );
167 
168 
169  /*************************************************
170  * Place the cavity the pixel rods are routed in
171  **************************************************/
173  sprintf(volName, "ZDC::Pixel_Routing %s", id.getString().c_str());
174  Housing_Physical->add(new GeoNameTag(volName));
175  Housing_Physical->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
176  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(0.0, 0.5 * floorThickness * Gaudi::Units::mm, (housing_depth * 0.5 - rearCoverThickness - zBackCavity * 0.5) * Gaudi::Units::mm)));
177  Housing_Physical->add(new GeoFullPhysVol(Pixel_Routing_Logical));
178 
179  /*************************************************
180  * Make unpopulated and populated holes for the
181  * tungsten plates
182  **************************************************/
183  GeoFullPhysVol *Pixel_Hole_Abs_Empty = new GeoFullPhysVol(Pixel_Hole_Abs_Logical);
184 
185  GeoFullPhysVol *Pixel_Hole_Abs_Filled = new GeoFullPhysVol(Pixel_Hole_Abs_Logical);
187  sprintf(volName, "ZDC::Pixel %s", id.getString().c_str());
188  Pixel_Hole_Abs_Filled->add(new GeoNameTag(volName));
189  Pixel_Hole_Abs_Filled->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
190  Pixel_Hole_Abs_Filled->add(new GeoFullPhysVol(Pixel_Abs_Logical));
191 
192  /*************************************************
193  * Make unpopulated and populated holes for the
194  * inner wall
195  **************************************************/
196  GeoFullPhysVol *Pixel_Hole_House_Empty = new GeoFullPhysVol(Pixel_Hole_House_Logical);
197 
198  GeoFullPhysVol *Pixel_Hole_House_Filled = new GeoFullPhysVol(Pixel_Hole_House_Logical);
200  sprintf(volName, "ZDC::Pixel %s", id.getString().c_str());
201  Pixel_Hole_House_Filled->add(new GeoNameTag(volName));
202  Pixel_Hole_House_Filled->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
203  Pixel_Hole_House_Filled->add(new GeoFullPhysVol(Pixel_House_Logical));
204 
205  /*************************************************
206  * Make a pixel rod for the radiator gaps
207  **************************************************/
208  GeoFullPhysVol *Pixel_Rad = new GeoFullPhysVol(Pixel_Rad_Logical);
209 
210  // Populate the absorber, air gaps, and inner housing with the pixel rods and holes
211  for (int rodChannel = 0; rodChannel < nPixelHolesX; ++rodChannel){
212  float pixelX = firstPixelX + pixelPitch * rodChannel;
213 
214  for (int pixelLayer = 0; pixelLayer <= nPixelHolesY; ++pixelLayer){
215  float pixelY = firstPixelY + pixelPitch * pixelLayer;
216 
217  if (pixelLayer >= pixelStart && pixelLayer <= pixelStop){//Populated holes
218  // Place pixel rods in the radiator gaps
220  sprintf(volName, "ZDC::Pixel_Rad %s", id.getString().c_str());
221  RadiatorGap->add(new GeoNameTag(volName));
222  RadiatorGap->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
223  RadiatorGap->add(new GeoAlignableTransform(GeoTrf::Translate3D(pixelX * Gaudi::Units::mm, pixelY * Gaudi::Units::mm, 0.0 * Gaudi::Units::mm)));
224  RadiatorGap->add(Pixel_Rad);
225 
226  // Place a pixel rod in the tungsten plate
227  sprintf(volName, "ZDC::Pixel_Abs %s", id.getString().c_str());
228  Abs_Plate->add(new GeoNameTag(volName));
229  Abs_Plate->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
230  Abs_Plate->add(new GeoAlignableTransform(GeoTrf::Translate3D(pixelX * Gaudi::Units::mm, pixelY * Gaudi::Units::mm, 0.0 * Gaudi::Units::mm)));
231  Abs_Plate->add(Pixel_Hole_Abs_Filled);
232 
233  // Place a pixel rod in the inner housing
235  sprintf(volName, "ZDC::Pixel_Housing %s", id.getString().c_str());
236  Housing_Physical->add(new GeoNameTag(volName));
237  Housing_Physical->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
238  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(pixelX * Gaudi::Units::mm, 0.5 * floorThickness + pixelY * Gaudi::Units::mm, inner_wall_z * Gaudi::Units::mm)));
239  Housing_Physical->add(Pixel_Hole_House_Filled);
240 
241  }else{// Unpopulated holes
243  sprintf(volName, "ZDC::Pixel_Hole %s", id.getString().c_str());
244 
245  // Place an unpopulated hole in the tungsten plate
246  Abs_Plate->add(new GeoNameTag(volName));
247  Abs_Plate->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
248  Abs_Plate->add(new GeoAlignableTransform(GeoTrf::Translate3D(pixelX * Gaudi::Units::mm, pixelY * Gaudi::Units::mm, 0.0 * Gaudi::Units::mm)));
249  Abs_Plate->add(Pixel_Hole_Abs_Empty);
250 
251  // Place an unpopulated hole in the housing
252  Housing_Physical->add(new GeoNameTag(volName));
253  Housing_Physical->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
254  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(pixelX * Gaudi::Units::mm, 0.5 * floorThickness + pixelY * Gaudi::Units::mm, inner_wall_z * Gaudi::Units::mm)));
255  Housing_Physical->add(Pixel_Hole_House_Empty);
256  }
257  } // end loop over pixel y placement
258  }// end loop over pixel x placement
259  }// end if pixel module
260 
261 
262 
263  /*************************************************
264  * Place the pre-assembled tungsten plates and
265  * radiator gaps in the steel housing. Also,
266  * add the vertical quartz rods to the radiator gaps
267  **************************************************/
268  for (int radGap = 0; radGap < nRadGaps; ++radGap){
269  float zRadGap = -housing_depth * 0.5 + wallThicknessFront + radiator_gap_depth * 0.5 + zPitch * radGap;
270  float zAbsorber = zRadGap + radiator_gap_depth * 0.5 + absorber_depth * 0.5;
271 
272  /*************************************************
273  * Place tungsten plates
274  **************************************************/
275  if (radGap != nRadGaps - 1){ // Don't place a tungsten plate after the last radiator gap
277  sprintf(volName, "ZDC::W_Mod %s", id.getString().c_str());
278  Housing_Physical->add(new GeoNameTag(volName));
279  Housing_Physical->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
280  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(0.0, 0.5 * floorThickness * Gaudi::Units::mm, zAbsorber * Gaudi::Units::mm)));
281  Housing_Physical->add(Abs_Plate);
282  }
283 
284  /*************************************************
285  * Place vertical quartz rods
286  **************************************************/
287 
288  // Clone the air gap so we can place rods in the clone
289  // Unless it's the last volume, then we can just use the original
290  // so GeoModel can take ownership of it
291  GeoFullPhysVol *thisRadGap = (radGap == nRadGaps - 1) ? RadiatorGap : RadiatorGap->clone(false);
292 
293  for (int rodChannel = 0; rodChannel < nPixelHolesX + 1; ++rodChannel){
294  //Default values are for central gaps
295  int nRods = nRods_center_gap;
296  float rodPitch = strip_gap_center / nRods;
297  float startX = pixelPitch * (-(nPixelHolesX - 1) * 0.5 + rodChannel - 1) + (pixelGap + rodPitch) * 0.5; // Location of the first rod in this set
298 
299  // The first and last channels are smaller and contain one fewer rods
300  if (rodChannel == 0 || rodChannel == nPixelHolesX){
301  // Making this a bit flexible in case I find the dimensions are different from the drawings
302  nRods = nRods_edge_gap;
303  rodPitch = strip_gap_edge / nRods;
304  // The first edge has unique placement, but the last one can use the normal method
305  if (rodChannel == 0){
306  startX = (-absorber_width + rodPitch) * 0.5;
307  }
308  }
309 
310  id = zdcID->channel_id(m_side,m_module,ZdcIDType::ACTIVE, radGap*(nPixelHolesX+1) + rodChannel);
311  sprintf(volName, "ZDC::Strip %s", id.getString().c_str());
312  for (int rod = 0; rod < nRods; ++rod){
313  thisRadGap->add(new GeoNameTag(volName));
314  thisRadGap->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
315  thisRadGap->add(new GeoAlignableTransform(GeoTrf::TranslateX3D((startX + rod * rodPitch) * Gaudi::Units::mm)));
316  thisRadGap->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
317  thisRadGap->add(new GeoFullPhysVol(Strip_Logical));
318  } // end vertical rod placement
319  } // end loop over rod channels
320 
321  /*************************************************
322  * Place the radiator gap
323  **************************************************/
325  sprintf(volName, "ZDC::Rad_Gap %s", id.getString().c_str());
326  Housing_Physical->add(new GeoNameTag(volName));
327  Housing_Physical->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
328  Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(0.0, 0.5 * floorThickness * Gaudi::Units::mm, zRadGap * Gaudi::Units::mm)));
329  Housing_Physical->add(thisRadGap);
330  }// end loop over radiator gaps
331 
332  // Place the steel case in the mother volume
334  sprintf(volName, "Zdc::ZDC_Mod %s", id.getString().c_str());
335  mother->add(new GeoNameTag(volName));
336  mother->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
337  mother->add(new GeoAlignableTransform( m_trf ));
338  mother->add(Housing_Physical);
339 
340 }
ZDC_ZDCModule::m_modType
int m_modType
Definition: ZDC_ZDCModule.h:21
HOUSING
@ HOUSING
Definition: ZdcID.h:22
getMessageSvc.h
singleton-like access to IMessageSvc via open function and helper
ZDC_ModuleBase::m_module
int m_module
Definition: ZDC_ModuleBase.h:48
ZDC_ModuleBase
Definition: ZDC_ModuleBase.h:18
deg
#define deg
Definition: SbPolyhedron.cxx:17
AIR
@ AIR
Definition: ZdcID.h:22
ZDC_ModuleBase::m_trf
GeoTrf::Transform3D m_trf
Definition: ZDC_ModuleBase.h:50
ZDC_ZDCModule.h
Athena::getMessageSvc
IMessageSvc * getMessageSvc(bool quiet=false)
Definition: getMessageSvc.cxx:20
ZdcID::channel_id
Identifier channel_id(int side, int module, int type, int channel) const
Definition: ZdcID.h:205
TRT::Hit::side
@ side
Definition: HitInfo.h:83
python.PyAthena.module
module
Definition: PyAthena.py:131
ZDC_ZDCModule::ZDC_ZDCModule
ZDC_ZDCModule()
Definition: ZDC_ZDCModule.cxx:27
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
RunTileMonitoring.rod
rod
Definition: RunTileMonitoring.py:134
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:239
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
StoredMaterialManager.h
TUNGSTEN
@ TUNGSTEN
Definition: ZdcID.h:22
ZDC_ZDCModule::create
virtual void create(GeoFullPhysVol *mother, StoredMaterialManager *materialManager, const ZdcID *zdcID) override
Definition: ZDC_ZDCModule.cxx:46
ZDC_ModuleBase::m_side
int m_side
Definition: ZDC_ModuleBase.h:47
ZDC_ZDCModule
Definition: ZDC_ZDCModule.h:10
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
ZdcID.h
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
INACTIVE
@ INACTIVE
Definition: ZdcID.h:21
StoreGateSvc.h
ZdcID
Definition: ZdcID.h:25
PIXEL
@ PIXEL
Definition: RegSelEnums.h:24
Identifier
Definition: IdentifierFieldParser.cxx:14