ATLAS Offline Software
Loading...
Searching...
No Matches
ZDC_DetFactory.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "ZDC_DetFactory.h"
7#include "ZDC_ModuleBase.h"
8
9
11#include "GeoModelKernel/GeoMaterial.h"
12#include "GeoModelKernel/GeoElement.h"
13#include "GeoModelKernel/GeoBox.h"
14#include "GeoModelKernel/GeoNameTag.h"
15#include "GeoModelKernel/GeoPhysVol.h"
16#include "GeoModelKernel/GeoFullPhysVol.h"
17#include "GeoModelKernel/GeoIdentifierTag.h"
18#include "GeoModelKernel/Units.h"
20#include "GaudiKernel/SystemOfUnits.h"
21
22
23#include "GeoModelKernel/GeoMaterial.h"
26#include "GeoModelKernel/GeoAlignableTransform.h"
27
28// Author Chad Lantz
29// chad.stephen.lantz@cern.ch
30
31// This is the ZDC Geomodel description :: see some details at
32// https://atlasop.cern.ch/atlas-point1/twiki/pub/Main/ZDCOperationManualShifter/zdc_layout.png
33
34// Each mod is located at centered at 141.580 m
35// I have assumed that each module is 154mm which is 4 mm longer than the ones shown in the above webpage
36// thus my modules are 13.4cm tungsten +1cm steel on either side
37
38// I have assumed that the cavity is 1016mm (4*4=16mm larger than the one in the above webpage)
39// Ionization chamber material is air currently
40// Note: C side (side 0) EM module has pixels, A side (side 1) doesn't
41
43 AthMessaging("ZDC_DetFactory"),
45 m_detectorStore(detStore),
46 m_tanSlotTransform{ GeoTrf::Transform3D(), GeoTrf::Transform3D()},
47 m_tanW{0.0, 0.0},
48 m_tanH{0.0, 0.0},
49 m_tanD{0.0, 0.0}
50{
51 if (m_detectorStore->retrieve( m_zdcID ).isFailure() ) {
52 MsgStream LogStream(Athena::getMessageSvc(), "ZDC_DetectorFactory::ZDC_DetFactory");
53 LogStream << MSG::ERROR << "execute: Could not retrieve ZdcID object from the detector store" << endmsg;
54 }
55}
56
58
59void ZDC_DetFactory::setTANSlot(uint iside, double width, double height, double depth, const GeoTrf::Transform3D trf, const std::string& name){
60 m_tanW.at(iside) = width;
61 m_tanH.at(iside) = height;
62 m_tanD.at(iside) = depth;
63 m_tanSlotName.at(iside) = name;
64 m_tanSlotTransform.at(iside) = trf;
65}
66
67void ZDC_DetFactory::create(GeoPhysVol *world)
68{
70 MsgStream LogStream(Athena::getMessageSvc(), "ZDC_DetectorFactory::create");
71
72 StoredMaterialManager *theMaterialManager;
73 if (StatusCode::SUCCESS != m_detectorStore->retrieve(theMaterialManager, "MATERIALS")) {
74 MsgStream LogStream(Athena::getMessageSvc(), "ZDC_DetectorFactory::create");
75 LogStream << MSG::ERROR << "execute: Could not retrieve StoredMaterialManager object from the detector store" << endmsg;
76 return;
77 }
78
79 buildMaterials(theMaterialManager);
80
81 /*************************************************
82 * Create TAN/TAXN slots
83 **************************************************/
84 std::array<GeoFullPhysVol*, 2> Envelope_Physical;
85 for(uint side : {0,1}){
86 const GeoMaterial *Air = theMaterialManager->getMaterial("std::Air");
87 GeoBox *Envelope_Box = new GeoBox(m_tanW.at(side) * Gaudi::Units::mm * 0.5, m_tanH.at(side) * Gaudi::Units::mm * 0.5, m_tanD.at(side) * Gaudi::Units::mm * 0.5);
88 GeoLogVol *Envelope_Logical = new GeoLogVol("Envelope_Logical", Envelope_Box, Air);
89 Envelope_Physical.at(side) = new GeoFullPhysVol(Envelope_Logical);
90
91 LogStream << MSG::INFO << "Creating " << m_tanSlotName.at(side) << " with dimensions (x,y,z) (" << m_tanW.at(side) << ", " << m_tanH.at(side) << ", " << m_tanD.at(side) << ") at ATLAS coordinates (x,y,z) (" << m_tanSlotTransform.at(side).translation().x() << ", " << m_tanSlotTransform.at(side).translation().y() << ", " << m_tanSlotTransform.at(side).translation().z() << ")" << endmsg;
92 }
93
94 /*************************************************
95 * Place Detectors in TAN/TAXN slots
96 **************************************************/
97 for(auto&& module : m_modules){
98 int side = (module->getSide() > 0) ? 1 : 0;
99 LogStream << MSG::INFO << "Creating " << module->getName() << " at TAN coordinates (x,y,z): (" << module->getTransform().translation().x() << ", " << module->getTransform().translation().y() << ", " << module->getTransform().translation().z() << ")" << endmsg;
100 module->create(Envelope_Physical.at(side), theMaterialManager, m_zdcID);
101 }
102
103 /*************************************************
104 * Place TAN/TAXN slots
105 **************************************************/
106 for(int side : {0, 1}){
107 int sideSign = (side == 0) ? -1 : 1;
108 world->add(new GeoNameTag(m_tanSlotName.at(side)));
109 world->add(new GeoIdentifierTag(m_zdcID->channel_id(sideSign, 0, ZdcIDType::INACTIVE,ZdcIDVolChannel::AIR).get_identifier32().get_compact()));
110 world->add(new GeoAlignableTransform(m_tanSlotTransform.at(side)));
111 world->add(Envelope_Physical.at(side));
112
113 m_detectorManager->addTreeTop(Envelope_Physical.at(side));
114 }
115
116}
117
119
120 const GeoElement *Oxygen = materialManager->getElement("Oxygen");
121 const GeoElement *Silicon = materialManager->getElement("Silicon");
122 const GeoElement *Hydrogen = materialManager->getElement("Hydrogen");
123 const GeoElement *Nitrogen = materialManager->getElement("Nitrogen");
124 const GeoElement *Carbon = materialManager->getElement("Carbon");
125 const GeoElement *Argon = materialManager->getElement("Argon");
126 const GeoElement *Tung = materialManager->getElement("Wolfram");
127 const GeoElement *Iron = materialManager->getElement("Iron");
128 const GeoElement *Nickel = materialManager->getElement("Nickel");
129
130 const int nEntries = 50; // Number of data points in each array
131 double eV = Gaudi::Units::eV;
132 double cm = Gaudi::Units::cm;
133
134 //Evenly distributed photon energy bins for the coming arrays of material properties. Range is selected for a PMT which is sensitive from 300-650nm wavelength
135 double photonEnergy[nEntries] = {0};
136 double minEnergy = 1.90769 * eV; double maxEnergy = 4.08882 * eV;
137 double step = (maxEnergy-minEnergy)/nEntries;
138 for(int i=0; i<nEntries; ++i){
139 photonEnergy[i] = minEnergy + i*step;
140 }
141
142 // Optical Air density and composition obtained from
143 // From https://physics.nist.gov/cgi-bin/Star/compos.pl?matno=104
144 GeoExtendedMaterial *OpAir = new GeoExtendedMaterial("ZDC::opticalAir", 1.2e-3 * GeoModelKernelUnits::g / Gaudi::Units::cm3, stateGas, Gaudi::Units::STP_Temperature);
145 OpAir->add(Nitrogen, 0.755);
146 OpAir->add(Oxygen , 0.232);
147 OpAir->add(Argon , 0.013);
148
149 // The air in the modules must have refractive index defined for total internal reflection to work
150 // From NIST https://emtoolbox.nist.gov/wavelength/documentation.asp
151 double RefractiveIndexAir[nEntries];
152 for(int i=0; i<nEntries; ++i)
153 RefractiveIndexAir[i] = 1.000271800;
154
156 airMPT->AddProperty("RINDEX", photonEnergy, RefractiveIndexAir, nEntries);
157 OpAir->SetMaterialPropertiesTable(airMPT);
158 OpAir->lock();
159 materialManager->addMaterial("ZDC", OpAir);
160
161 // RPD fiber core and ZDC rod material
162 // Composition from https://physics.nist.gov/cgi-bin/Star/compos.pl?matno=245
163 GeoExtendedMaterial *OpSilicaCore = new GeoExtendedMaterial("ZDC::opticalSilica", 2.320 * GeoModelKernelUnits::g / Gaudi::Units::cm3, stateSolid, Gaudi::Units::STP_Temperature);
164 OpSilicaCore->add(Silicon, 0.467);
165 OpSilicaCore->add(Oxygen, 0.533);
166
167 // Refractive index of fused silica obtained from
168 // https://www.heraeus.com/media/media/hca/doc_hca/products_and_solutions_8/optics/Data_and_Properties_Optics_fused_silica_EN.pdf
169 double silica_RIND[] = {1.45656, 1.45694, 1.45737, 1.45781, 1.45825, 1.4587 , 1.45914, 1.45959, 1.46003, 1.46048,
170 1.46095, 1.46145, 1.46194, 1.46242, 1.46289, 1.4634 , 1.46394, 1.46448, 1.46502, 1.46556,
171 1.46608, 1.46666, 1.46725, 1.46784, 1.46843, 1.46902, 1.46961, 1.47024, 1.4709 , 1.47155,
172 1.4722 , 1.47288, 1.47356, 1.47425, 1.47494, 1.47566, 1.4764 , 1.47715, 1.4779 , 1.47864,
173 1.47935, 1.48014, 1.48093, 1.48172, 1.48254, 1.48339, 1.48424, 1.4851 , 1.48598, 1.48689};
174
175 // Absorption length index of fused silica derrived from
176 // https://www.heraeus.com/media/media/hca/doc_hca/products_and_solutions_8/optics/Data_and_Properties_Optics_fused_silica_EN.pdf
177 double silica_ABSL[] = {1.786e+04 * cm, 1.556e+04 * cm, 1.982e+04 * cm, 2.369e+04 * cm, 2.046e+04 * cm, 1.595e+04 * cm, 1.582e+04 * cm,
178 1.420e+04 * cm, 1.279e+04 * cm, 1.545e+04 * cm, 1.498e+04 * cm, 1.358e+04 * cm, 1.824e+04 * cm, 2.320e+04 * cm,
179 3.736e+04 * cm, 2.155e+04 * cm, 1.718e+04 * cm, 1.871e+04 * cm, 2.286e+04 * cm, 3.597e+04 * cm, 4.358e+04 * cm,
180 2.751e+04 * cm, 1.967e+04 * cm, 1.743e+04 * cm, 1.425e+04 * cm, 1.198e+04 * cm, 1.371e+04 * cm, 1.911e+04 * cm,
181 4.413e+04 * cm, 4.002e+04 * cm, 2.621e+04 * cm, 1.420e+04 * cm, 1.085e+04 * cm, 1.020e+04 * cm, 1.090e+04 * cm,
182 1.267e+04 * cm, 1.369e+04 * cm, 1.427e+04 * cm, 1.484e+04 * cm, 1.480e+04 * cm, 1.443e+04 * cm, 1.274e+04 * cm,
183 1.242e+04 * cm, 1.212e+04 * cm, 1.232e+04 * cm, 1.251e+04 * cm, 1.168e+04 * cm, 1.052e+04 * cm, 1.197e+04 * cm, 8.355e+03 * cm};
184
186 silicaCoreMPT->AddProperty("RINDEX" , photonEnergy, silica_RIND, nEntries); // index of refraction
187 silicaCoreMPT->AddProperty("ABSLENGTH", photonEnergy, silica_ABSL, nEntries); // absorption length
188 OpSilicaCore->SetMaterialPropertiesTable(silicaCoreMPT);
189 OpSilicaCore->lock();
190 materialManager->addMaterial("ZDC", OpSilicaCore);
191
192 // RPD fiber cladding
193 // Composition from https://physics.nist.gov/cgi-bin/Star/compos.pl?matno=245
194 GeoExtendedMaterial *OpSilicaClad = new GeoExtendedMaterial("ZDC::opticalSilicaClad", 2.320 * GeoModelKernelUnits::g / Gaudi::Units::cm3, stateSolid, Gaudi::Units::STP_Temperature);
195 OpSilicaClad->add(Silicon, 0.467);
196 OpSilicaClad->add(Oxygen, 0.533);
197
198 // Numerical aperture is given by data sheet as 0.22 and NA = sqrt( n1^2 - n2^2 ), so n2 = sqrt( n1^2 - NA^2 ) where n1 is silica_RIND
199 // https://www.content.molex.com/dxdam/literature/987650-8936.pdf
200 double silica_clad_RIND[] = {1.43985, 1.44023, 1.44067, 1.44112, 1.44156, 1.44201, 1.44246, 1.44291, 1.44336, 1.44381,
201 1.44429, 1.4448 , 1.44529, 1.44577, 1.44625, 1.44677, 1.44731, 1.44786, 1.44841, 1.44895,
202 1.44948, 1.45007, 1.45067, 1.45126, 1.45186, 1.45245, 1.45305, 1.45369, 1.45435, 1.45501,
203 1.45567, 1.45635, 1.45705, 1.45774, 1.45844, 1.45916, 1.45992, 1.46067, 1.46143, 1.46219,
204 1.4629 , 1.4637 , 1.46449, 1.46529, 1.46612, 1.46698, 1.46785, 1.46871, 1.4696 , 1.47052};
205
206 // Silica cladding
208 silicaCladMPT->AddProperty("RINDEX" , photonEnergy, silica_clad_RIND, nEntries); // index of refraction
209 silicaCladMPT->AddProperty("ABSLENGTH", photonEnergy, silica_ABSL , nEntries); // absorption length
210 OpSilicaClad->SetMaterialPropertiesTable(silicaCladMPT);
211 OpSilicaClad->lock();
212 materialManager->addMaterial("ZDC", OpSilicaClad);
213
214 // Kapton fiber optic buffer material
215 // Composition from https://physics.nist.gov/cgi-bin/Star/compos.pl?matno=179
216 GeoExtendedMaterial *OpKapton = new GeoExtendedMaterial("ZDC::opticalKapton", 1.42 * GeoModelKernelUnits::g / Gaudi::Units::cm3, stateSolid, Gaudi::Units::STP_Temperature);
217 OpKapton->add(Hydrogen, 0.026362);
218 OpKapton->add(Carbon , 0.691133);
219 OpKapton->add(Nitrogen, 0.073270);
220 OpKapton->add(Oxygen , 0.209235);
221
222 // Refractive index obtained from
223 // https://engineering.case.edu/centers/sdle/sites/engineering.case.edu.centers.sdle/files/optical_properties_of_materials.pdf
224 double kapton_RIND[] = {1.7095 , 1.7111 , 1.7143 , 1.7191, 1.7207 , 1.7255 , 1.7271 , 1.73157, 1.7351 , 1.7383 ,
225 1.7416 , 1.7464 , 1.74978, 1.7545, 1.7593 , 1.766 , 1.7692 , 1.7758 , 1.78179, 1.79009,
226 1.794 , 1.80245, 1.8074 , 1.8157, 1.82184, 1.82659, 1.8344 , 1.84222, 1.8514 , 1.8584 ,
227 1.86392, 1.8723 , 1.88251, 1.8959, 1.90567, 1.92604, 1.93911, 1.95036, 1.96867, 1.97804,
228 1.9905 , 1.99755, 2.00821, 2.0146, 2.03435, 2.05705, 2.08078, 2.10021, 2.12912, 2.14333};
229
230 // Reflectivity obtained from
231 // https://amostech.com/TechnicalPapers/2018/Poster/Bengtson.pdf
232 double kapton_REFL[] = {0.502195 , 0.473894 , 0.446164 , 0.413816 , 0.375095 , 0.336845 , 0.293879 , 0.239299 , 0.200573 , 0.141596 ,
233 0.0949924 , 0.0590249 , 0.0353952 , 0.0206475 , 0.01305 , 0.00915075, 0.00722501, 0.00551299, 0.00552271, 0.00553177,
234 0.00554062, 0.00554942, 0.00555642, 0.00556579, 0.0083157, 0.011944 , 0.0172255 , 0.0225071 , 0.0277887 , 0.0330702 ,
235 0.0383518 , 0.0436334 , 0.0489149 , 0.0541965 , 0.0594781, 0.0647597 , 0.0700412 , 0.0753228 , 0.0806044 , 0.0858859 ,
236 0.0911675 , 0.0964491 , 0.101731 , 0.107012 , 0.112294 , 0.117575 , 0.122857 , 0.128139 , 0.13342 , 0.138702 };
237
238 // Absorption length obtained from
239 // https://pubs.rsc.org/fa/content/articlehtml/2018/ra/c7ra12101f
240 double kapton_ABSL[] = {0.00867389 * cm, 0.00842316 * cm, 0.00818715 * cm, 0.00798542 * cm, 0.00774517 * cm, 0.00751684 * cm, 0.00729959 * cm, 0.00709258 * cm, 0.00685686 * cm, 0.0066337 * cm,
241 0.00642212 * cm, 0.00616231 * cm, 0.00587855 * cm, 0.00561968 * cm, 0.00541849 * cm, 0.0052337 * cm, 0.00504545 * cm, 0.00487671 * cm, 0.00474623 * cm, 0.00461459 * cm,
242 0.00449314 * cm, 0.00437628 * cm, 0.0042637 * cm, 0.00413695 * cm, 0.00401798 * cm, 0.00382827 * cm, 0.003625 * cm, 0.00335813 * cm, 0.00303474 * cm, 0.00264672 * cm,
243 0.00226016 * cm, 0.00185863 * cm, 0.00146109 * cm, 0.00116967 * cm, 0.000901973 * cm, 0.000721492 * cm, 0.000559526 * cm, 0.000463349 * cm, 0.00034795 * cm, 0.000317447 * cm,
244 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm, 0.000317447 * cm};
245
246 // Kapton
248 kaptonMPT->AddProperty("RINDEX" , photonEnergy, kapton_RIND, nEntries);
249 kaptonMPT->AddProperty("ABSLENGTH" , photonEnergy, kapton_ABSL, nEntries);
250 kaptonMPT->AddProperty("REFLECTIVITY", photonEnergy, kapton_REFL, nEntries);
251 OpKapton->SetMaterialPropertiesTable(kaptonMPT);
252 OpKapton->lock();
253 materialManager->addMaterial("ZDC", OpKapton);
254
255 // Absorber composition: savannah.cern.ch/task/download.php?file_id=22925
256 GeoMaterial *Tungsten = new GeoMaterial("ZDC::Tungsten", 18.155 * GeoModelKernelUnits::g / Gaudi::Units::cm3);
257 Tungsten->add(Tung , 0.948);
258 Tungsten->add(Nickel, 0.037);
259 Tungsten->add(Iron , 0.015);
260 Tungsten->lock();
261 materialManager->addMaterial("ZDC", Tungsten);
262
263 // ZDC housing material
264 GeoMaterial *Steel = new GeoMaterial("ZDC::Steel", 7.9 * GeoModelKernelUnits::g / Gaudi::Units::cm3);
265 Steel->add(Iron , 0.98);
266 Steel->add(Carbon, 0.02);
267 Steel->lock();
268 materialManager->addMaterial("ZDC", Steel);
269
270}
271
#define endmsg
Eigen::Affine3d Transform3D
@ stateSolid
unsigned int uint
const double width
@ INACTIVE
Definition ZdcID.h:21
@ AIR
Definition ZdcID.h:22
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
void SetMaterialPropertiesTable(GeoMaterialPropertiesTable *MPT)
void AddProperty(const char *key, double *PhotonMomenta, double *PropertyValues, int NumEntries)
The Athena Transient Store API.
This class holds one or more material managers and makes them storeable, under StoreGate.
virtual void addMaterial(const std::string &space, GeoMaterial *material)=0
virtual const GeoElement * getElement(const std::string &name)=0
virtual const GeoMaterial * getMaterial(const std::string &name)=0
std::vector< std::unique_ptr< ZDC_ModuleBase > > m_modules
const ZdcID * m_zdcID
virtual void create(GeoPhysVol *world) override
std::array< std::string, 2 > m_tanSlotName
ZDC_DetFactory(StoreGateSvc *)
std::array< GeoTrf::Transform3D, 2 > m_tanSlotTransform
void setTANSlot(uint iside, double width, double height, double depth, const GeoTrf::Transform3D trf, const std::string &name)
std::array< double, 2 > m_tanD
std::array< double, 2 > m_tanH
std::array< double, 2 > m_tanW
StoreGateSvc * m_detectorStore
virtual const ZDC_DetManager * getDetectorManager() const override
void buildMaterials(StoredMaterialManager *materialManager)
ZDC_DetManager * m_detectorManager
std::string depth
tag string for intendation
Definition fastadd.cxx:46
singleton-like access to IMessageSvc via open function and helper
IMessageSvc * getMessageSvc(bool quiet=false)