ATLAS Offline Software
Loading...
Searching...
No Matches
ZDC_RPDModule.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_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#include "GaudiKernel/MsgStream.h"
24#include "ZdcIdentifier/ZdcID.h"
25#include "CLHEP/Geometry/Transform3D.h"
26#include <stdexcept>
27
28void ZDC_RPDModule::create(GeoFullPhysVol* mother, StoredMaterialManager *materialManager, const ZdcID *zdcID){
29
30 MsgStream LogStream(Athena::getMessageSvc(), "ZDC_RPDModule::create");
31
32 const GeoMaterial *Aluminum = materialManager->getMaterial("std::Aluminium");
33 const GeoMaterial *OpAir = materialManager->getMaterial("ZDC::opticalAir");
34 const GeoMaterial *OpSilicaCore = materialManager->getMaterial("ZDC::opticalSilica");
35 const GeoMaterial *OpSilicaClad = materialManager->getMaterial("ZDC::opticalSilicaClad");
36 const GeoMaterial *OpKapton = materialManager->getMaterial("ZDC::opticalKapton");
37
38 // All parameters are either in mm or are unitless
39 const int nRows = 4;
40 const int nCols = 4;
41 const float coreDia = 0.60; // Fiber core diameter
42 const float cladDia = 0.66; // Fiber cladding diameter
43 const float buffDia = 0.71; // Fiber buffer diameter
44 const float fiberPitchX = 1.425; // Spacing between fibers in X
45 const float fiberPitchZ = 1.63; // Spacing between fibers in Z
46 const float tileSize = 11.4; // Size of a square "tile"
47 const float housingThickness = 5; // Thickness of aluminum housing
48 const float detectorInnerWidth = 4 * tileSize; // Width (x) of the detector cavity which contains the fibers
49 const float detectorInnerDepth = 8 * fiberPitchZ + buffDia; // Depth (z) of the detector cavity which contains the fibers
50 const float footWidth = 91; // Width of the foot of the module
51 const float footDepth = 75; // Depth of the foot of the module
52 const float footHeight = 10; // Height of the foot of the module
53 const float posY = m_trf.translation().y(); // Y position of center of the tiles
54
55 const GeoBox* motherBox = dynamic_cast<const GeoBox*>(mother->getLogVol()->getShape());
56 if (not motherBox){
57 throw (std::runtime_error("ZDC_RPDModule::create: motherBox is a nullptr"));
58 }
59 const float halfY = motherBox->getYHalfLength();
60
61 // Height of the extension between the main RPD body and the foot
62 const float detectorHeight = 2*halfY - footHeight; // Height of the detector minus the foot
63 const float readoutFiberLength = halfY - posY - 2*tileSize; // Length of the "readout" section of the fibers, not including the active area extension
64
65 // Build the main transforms here
66 //The foot has to be placed at the bottom of the TAN/TAXN slot
67 const GeoTrf::Transform3D footTrf = GeoTrf::TranslateY3D((-halfY - posY + footHeight * 0.5) * Gaudi::Units::mm) * m_trf;
68
69 //The main housing is shifted up by half the foot height
70 const GeoTrf::Transform3D moduleTrf = GeoTrf::TranslateY3D((0.5 * footHeight - posY) * Gaudi::Units::mm) * m_trf;
71
72 char volName[64];
73
74 // Aluminum housing (case)
75 GeoBox *Housing_Box = new GeoBox((detectorInnerWidth + 2 * housingThickness) * Gaudi::Units::mm * 0.5,
76 detectorHeight * Gaudi::Units::mm * 0.5,
77 (detectorInnerDepth + 2 * housingThickness) * Gaudi::Units::mm * 0.5);
78
79 GeoLogVol *Housing_Logical = new GeoLogVol("RPD_Housing_Logical", Housing_Box, Aluminum);
80 GeoFullPhysVol *Housing_Physical = new GeoFullPhysVol(Housing_Logical);
81
82 // Detector inner volume
83 GeoBox *Module_Box = new GeoBox(detectorInnerWidth * Gaudi::Units::mm * 0.5,
84 readoutFiberLength * Gaudi::Units::mm * 0.5,
85 detectorInnerDepth * Gaudi::Units::mm * 0.5);
86
87 GeoLogVol *Module_Logical = new GeoLogVol("RPD_Module_Logical", Module_Box, OpAir);
88 GeoPhysVol *Module_Physical = new GeoPhysVol(Module_Logical);
89
90 // Foot
91 GeoBox *Foot_Box = new GeoBox(footWidth * Gaudi::Units::mm * 0.5,
92 footHeight * Gaudi::Units::mm * 0.5,
93 footDepth * Gaudi::Units::mm * 0.5);
94
95 GeoLogVol *Foot_Logical = new GeoLogVol("RPD_Foot_Logical", Foot_Box, Aluminum);
96 GeoPhysVol *Foot_Physical = new GeoPhysVol(Foot_Logical);
97
98 // Readout fiber volumes are made here because they're all the same length
99 // Core
100 GeoTube *Readout_Core_Tube = new GeoTube(0.0 * Gaudi::Units::mm, coreDia * Gaudi::Units::mm * 0.5, readoutFiberLength * Gaudi::Units::mm * 0.5);
101 GeoLogVol *Readout_Core_Logical = new GeoLogVol("RPD_Core_Readout_Logical", Readout_Core_Tube, OpSilicaCore);
102 GeoPhysVol *Readout_Core_Physical = new GeoPhysVol(Readout_Core_Logical);
103
104 // Cladding
105 GeoTube *Readout_Clad_Tube = new GeoTube(coreDia * Gaudi::Units::mm * 0.5, cladDia * Gaudi::Units::mm * 0.5, readoutFiberLength * Gaudi::Units::mm * 0.5);
106 GeoLogVol *Readout_Clad_Logical = new GeoLogVol("RPD_Clad_Readout_Logical", Readout_Clad_Tube, OpSilicaClad);
107 GeoPhysVol *Readout_Clad_Physical = new GeoPhysVol(Readout_Clad_Logical);
108
109 // Buffer
110 GeoTube *Readout_Buffer_Tube = new GeoTube(cladDia * Gaudi::Units::mm * 0.5, buffDia * Gaudi::Units::mm * 0.5, readoutFiberLength * Gaudi::Units::mm * 0.5);
111 GeoLogVol *Readout_Buffer_Logical = new GeoLogVol("RPD_Buff_Readout_Logical", Readout_Buffer_Tube, OpKapton);
112 GeoPhysVol *Readout_Buffer_Physical = new GeoPhysVol(Readout_Buffer_Logical);
113
114 /***************************************************
115 *
116 * The fibers are positioned in a way that distributes of all channels in a given column evenly in z
117 * This is done by offsetting each fiber in x and z. For example, fibers for a single channel would look like this
118 *
119 * -0-------0--------
120 * ---0-------0------
121 * -----0-------0----
122 * -------0--------0-
123 *
124 * The cycle has been repeated twice in order to achieve a "tile" size of approximately 10mm (11.4) while maintaining maximum density of fibers
125 * 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
126 *
127 * Pattern1 Pattern2 Sum
128 * -0-------0-------- -------0--------0- -0-----0-0------0-
129 * so ---0-------0------ + -----0-------0---- = ---0-0-----0-0----
130 * -----0-------0---- ---0-------0------ ---0-0-----0-0----
131 * -------0--------0- -0-------0-------- -0-----0-0------0-
132 *
133 * Everything above was for a single channel in row 0. Each row in a given colum starts the same pattern, just offset by fiberPitchZ
134 * So that looks like this, where the number represents the row
135 *
136 * -0--1--2--3--0--1--2--3--
137 * -3--0--1--2--3--0--1--2--
138 * -2--3--0--1--2--3--0--1--
139 * -1--2--3--0--1--2--3--0-
140 *
141 ****************************************************/
142
143 float startX = tileSize * nCols * 0.5 - fiberPitchX / 4;
144 float startZ = -fiberPitchZ * (nCols - 0.5) * 0.5;
145 const unsigned int NFIBERS = 64; // Per row
146 for (int row = 0; row < nRows; ++row)
147 {
148 float fiberLength = (1 + row) * tileSize;
149 // float y = (-detectorHeight * 0.5 + housingThickness + tileSize * nRows - fiberLength * 0.5) * Gaudi::Units::mm;
150 float y = (posY - 0.5 * footHeight + 0.5 * tileSize * nRows - fiberLength * 0.5) * Gaudi::Units::mm;
151
152 // Core
153 sprintf(volName, "RPD_Core_Active_Logical %d", row);
154 GeoTube *Active_Core_Tube = new GeoTube(0.0 * Gaudi::Units::mm, coreDia * Gaudi::Units::mm * 0.5, fiberLength * Gaudi::Units::mm * 0.5);
155 GeoLogVol *Active_Core_Logical= new GeoLogVol(volName, Active_Core_Tube, OpSilicaCore);
156 GeoPhysVol *Active_Core_Physical = new GeoPhysVol(Active_Core_Logical);
157
158 // Cladding
159 sprintf(volName, "RPD_Clad_Active_Logical %d", row);
160 GeoTube *Active_Clad_Tube = new GeoTube(coreDia * Gaudi::Units::mm * 0.5, cladDia * Gaudi::Units::mm * 0.5, fiberLength * Gaudi::Units::mm * 0.5);
161 GeoLogVol *Active_Clad_Logical = new GeoLogVol(volName, Active_Clad_Tube, OpSilicaClad);
162 GeoPhysVol *Active_Clad_Physical = new GeoPhysVol(Active_Clad_Logical);
163
164 // Buffer
165 sprintf(volName, "RPD_Buff_Active_Logical %d", row);
166 GeoTube *Active_Buffer_Tube = new GeoTube(cladDia * Gaudi::Units::mm * 0.5, buffDia * Gaudi::Units::mm * 0.5, fiberLength * Gaudi::Units::mm * 0.5);
167 GeoLogVol *Active_Buffer_Logical = new GeoLogVol(volName, Active_Buffer_Tube, OpKapton);
168 GeoPhysVol *Active_Buffer_Physical = new GeoPhysVol(Active_Buffer_Logical);
169
170 for (uint fiber = 0; fiber < NFIBERS; ++fiber)
171 {
172
173 // functions
174 int index = fiber * 0.5;
175 int pattern = fiber % 2;
176 int cycle = fiber / (2 * nCols) % 2;
177 int col = 2 * index / (nRows * nCols);
178 float cycleOffset = cycle * nCols * fiberPitchX;
179 float patternOffsetX = -pattern * fiberPitchX * 0.5;
180 float patternOffsetZ = pattern * fiberPitchZ * 0.5;
181
182 float x = startX - tileSize * col - cycleOffset + patternOffsetX - index % 4 * fiberPitchX;
183 float z = startZ + fiberPitchZ * ((row + index % 4 + 2 * pattern) % 4) + patternOffsetZ;
184
185 int channel = 4*row + col;
186
187 std::string channelHashStr = zdcID->channel_id(m_side,m_module,ZdcIDType::ACTIVE,channel).getString();
188 uint32_t channelHash = zdcID->channel_id(m_side,m_module,ZdcIDType::ACTIVE,channel).get_identifier32().get_compact();
189
190
191 /*******************************************
192 * Core
193 ********************************************/
194
195 // Active region core get placed in aluminum
196
197 // Active area
198 sprintf(volName, "ZDC::RPD_Core_Active %s", channelHashStr.c_str());
199 Housing_Physical->add(new GeoNameTag(volName));
200 Housing_Physical->add(new GeoIdentifierTag(channelHash));
201 Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, y * Gaudi::Units::mm, z * Gaudi::Units::mm)));
202 Housing_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
203 Housing_Physical->add(Active_Core_Physical);
204
205 // Readout Fiber
206 sprintf(volName, "ZDC::RPD_Core_Readout %s", channelHashStr.c_str());
207 Module_Physical->add(new GeoNameTag(volName));
208 Module_Physical->add(new GeoIdentifierTag(channelHash));
209 Module_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, 0.0, z * Gaudi::Units::mm)));
210 Module_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
211 Module_Physical->add(Readout_Core_Physical);
212
213 /*******************************************
214 * Cladding
215 ********************************************/
216
217 // Active area
218 sprintf(volName, "ZDC::RPD_Clad_Active %s", channelHashStr.c_str());
219 Housing_Physical->add(new GeoNameTag(volName));
220 Housing_Physical->add(new GeoIdentifierTag(channelHash));
221 Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, y * Gaudi::Units::mm, z * Gaudi::Units::mm)));
222 Housing_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
223 Housing_Physical->add(Active_Clad_Physical);
224
225 // Readout
226 sprintf(volName, "ZDC::RPD_Clad_Readout %s", channelHashStr.c_str());
227 Module_Physical->add(new GeoNameTag(volName));
228 Module_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, 0.0, z * Gaudi::Units::mm)));
229 Module_Physical->add(new GeoIdentifierTag(channelHash));
230 Module_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
231 Module_Physical->add(Readout_Clad_Physical);
232
233 /*******************************************
234 * Buffer
235 ********************************************/
236
237 // Active area
238 sprintf(volName, "ZDC::RPD_Buffer_Active %s", channelHashStr.c_str());
239 Housing_Physical->add(new GeoNameTag(volName));
240 Housing_Physical->add(new GeoIdentifierTag(channelHash));
241 Housing_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, y * Gaudi::Units::mm, z * Gaudi::Units::mm)));
242 Housing_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
243 Housing_Physical->add(Active_Buffer_Physical);
244
245 // Readout Fiber
246 sprintf(volName, "ZDC::RPD_Buffer_Readout %s", channelHashStr.c_str());
247 Module_Physical->add(new GeoNameTag(volName));
248 Module_Physical->add(new GeoAlignableTransform(GeoTrf::Translate3D(x * Gaudi::Units::mm, 0.0, z * Gaudi::Units::mm)));
249 Module_Physical->add(new GeoAlignableTransform(GeoTrf::RotateX3D(90 * Gaudi::Units::deg)));
250 Module_Physical->add(new GeoIdentifierTag(channelHash));
251 Module_Physical->add(Readout_Buffer_Physical);
252
253 } // end loop over fibers
254 }// end loop over rows
255
256 Identifier id;
257
258 // Place the fiber routing volume
260 sprintf(volName, "ZDC::RPD_Air_Cavity %s", id.getString().c_str());
261 Housing_Physical->add(new GeoNameTag(volName));
262 Housing_Physical->add(new GeoIdentifierTag( id.get_identifier32().get_compact()));
263 Housing_Physical->add(new GeoAlignableTransform(GeoTrf::TranslateY3D( 0.5 * (detectorHeight - readoutFiberLength) * Gaudi::Units::mm)));
264 Housing_Physical->add(Module_Physical);
265
266 // Place the foot in the mother volume
268 sprintf(volName, "ZDC::RPD_Foot %s",id.getString().c_str());
269 mother->add(new GeoNameTag(volName));
270 mother->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
271 mother->add(new GeoAlignableTransform( footTrf ));
272 mother->add(Foot_Physical);
273
274 // Place the module in the mother volume
276 sprintf(volName, "Zdc::RPD_Mod %s", id.getString().c_str());
277 mother->add(new GeoNameTag(volName));
278 mother->add(new GeoIdentifierTag(id.get_identifier32().get_compact()));
279 mother->add(new GeoAlignableTransform( moduleTrf));
280 mother->add(Housing_Physical);
281
282}
unsigned int uint
double cycle(double a, double b)
#define NFIBERS
#define y
#define x
#define z
@ ACTIVE
Definition ZdcID.h:21
@ INACTIVE
Definition ZdcID.h:21
@ AIR
Definition ZdcID.h:22
@ HOUSING
Definition ZdcID.h:22
value_type get_compact() const
Get the compact id.
std::string getString() const
Provide a string form of the identifier - hexadecimal.
Identifier32 get_identifier32() const
Get the 32-bit version Identifier, will be invalid if >32 bits needed.
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)
Definition index.py:1