ATLAS Offline Software
Loading...
Searching...
No Matches
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"
21#include "GeoModelKernel/GeoMaterial.h"
22
23#include "ZdcIdentifier/ZdcID.h"
25#include "CLHEP/Geometry/Transform3D.h"
26
32
33ZDC_ZDCModule::ZDC_ZDCModule(const std::string& name, int side, int module, int modType)
34 : ZDC_ModuleBase(name, side, module),
35 m_modType(modType)
36{
37}
38
39ZDC_ZDCModule::ZDC_ZDCModule(ZDC_ZDCModule *right, int side, int module)
40 : ZDC_ModuleBase((ZDC_ModuleBase*)right, side, module)
41{
42 m_modType = right->m_modType;
43}
44
45
46void 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}
#define endmsg
@ ACTIVE
Definition ZdcID.h:21
@ INACTIVE
Definition ZdcID.h:21
@ AIR
Definition ZdcID.h:22
@ HOUSING
Definition ZdcID.h:22
@ TUNGSTEN
Definition ZdcID.h:22
@ PIXEL
Definition ZdcID.h:22
This class holds one or more material managers and makes them storeable, under StoreGate.
virtual const GeoMaterial * getMaterial(const std::string &name)=0
GeoTrf::Transform3D m_trf
virtual void create(GeoFullPhysVol *mother, StoredMaterialManager *materialManager, const ZdcID *zdcID) override
Definition ZdcID.h:25
Identifier channel_id(int side, int module, int type, int channel) const
Definition ZdcID.h:205
singleton-like access to IMessageSvc via open function and helper
IMessageSvc * getMessageSvc(bool quiet=false)