ATLAS Offline Software
Loading...
Searching...
No Matches
BeamPipeDetectorFactory.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8#include "GeoModelKernel/GeoMaterial.h"
9#include "GeoModelKernel/GeoPcon.h"
10#include "GeoModelKernel/GeoTube.h"
11#include "GeoModelKernel/GeoCons.h"
12#include "GeoModelKernel/GeoLogVol.h"
13#include "GeoModelKernel/GeoNameTag.h"
14#include "GeoModelKernel/GeoPhysVol.h"
15#include "GeoModelKernel/GeoFullPhysVol.h"
16#include "GeoModelKernel/GeoTransform.h"
17#include "GeoModelKernel/GeoDefinitions.h"
18
20
24
26#include "GaudiKernel/MsgStream.h"
27#include "GaudiKernel/SystemOfUnits.h"
28
29#include <iomanip>
30#include <utility>
31#include <vector>
32
33
42
44= default;
45
46void BeamPipeDetectorFactory::create(GeoPhysVol *world)
47{
49
50 if (StatusCode::SUCCESS != m_detectorStore->retrieve(m_materialManager, std::string("MATERIALS"))) {
51 return;
52 }
53
54 IRDBRecordset_ptr atlasMother = m_access->getRecordsetPtr("AtlasMother",m_versionTag,m_versionNode);
55 IRDBRecordset_ptr bpipeGeneral = m_access->getRecordsetPtr("BPipeGeneral",m_versionTag,m_versionNode);
56 IRDBRecordset_ptr bpipeEnvelope = m_access->getRecordsetPtr("BPipeEnvelope",m_versionTag,m_versionNode);
57 IRDBRecordset_ptr bpipePosition = m_access->getRecordsetPtr("BPipePosition",m_versionTag,m_versionNode);
58
59 // Get the materials
60 const GeoMaterial *air = m_materialManager->getMaterial("std::Air");
61
62 // Create beam pipe top level envelopes
63 // It is split into 3 sections.
64 // left, right and central. This is to allow different truth scoring in the different regions.
65
66 m_centralRegionZMax = 1500 * Gaudi::Units::mm; // For backward compatibility in DB.
67 if (bpipeGeneral->size() != 0) m_centralRegionZMax = (*bpipeGeneral)[0]->getDouble("CENTRALZMAX") * Gaudi::Units::mm;
68
69 const GeoMaterial* ether = m_materialManager->getMaterial("special::Ether");
70 GeoTube* dummytube= new GeoTube(0., 4711., 4711.);
71 GeoLogVol* dummyBeamPipe = new GeoLogVol("BeamPipe",dummytube,ether);
72 GeoRef<GeoPhysVol> theBeamPipe (new GeoPhysVol(dummyBeamPipe));
73
74 EnvelopeShapes envelopes;
75
76 if (bpipeEnvelope->size() != 0) {
77 envelopes = makeEnvelope(bpipeEnvelope);
78 } else {
79 envelopes = makeEnvelopeOld(atlasMother);
80 }
81
82 GeoLogVol* lvMotherCentral = new GeoLogVol("BeamPipeCentral",envelopes.centralShape,air);
83 GeoPhysVol* pvMotherCentral = new GeoPhysVol(lvMotherCentral);
84
85
86 // The treetops need to have unique physical volumes so
87 // we create pvMotherFwdMinus which is identical pvMotherFwdPlus.
88 GeoLogVol* lvMotherFwd = new GeoLogVol("BeamPipeFwd",envelopes.fwdShape,air);
89 GeoPhysVol* pvMotherFwdPlus = new GeoPhysVol(lvMotherFwd);
90 GeoPhysVol* pvMotherFwdMinus = new GeoPhysVol(lvMotherFwd);
91
92
93 // Add sections
94 addSections(pvMotherCentral, 0);
95 addSections(pvMotherFwdPlus, 1);
96 addSections(pvMotherFwdMinus, 1);
97
98 // We have to give them all the name "BeamPipe"
99 // This is the name used by HepVis viewer
100 GeoNameTag *tag = new GeoNameTag("BeamPipe");
101
102 double beamx = 0.0;
103 double beamy = 0.0;
104 double beamz = 0.0;
105 if (bpipePosition->size() != 0) {
106 beamx = (*bpipePosition)[0]->getDouble("POSX") * Gaudi::Units::mm;
107 beamy = (*bpipePosition)[0]->getDouble("POSY") * Gaudi::Units::mm;
108 beamz = (*bpipePosition)[0]->getDouble("POSZ") * Gaudi::Units::mm;
109 }
110
111 if (m_mode=="AssemblyBeamPipe"){
112 // Only shift the central section
113 // Central
114 theBeamPipe->add(tag);
115 theBeamPipe->add(new GeoTransform(GeoTrf::Translate3D(beamx,beamy,beamz)));
116 theBeamPipe->add(pvMotherCentral);
117
118 // FwdPlus
119 theBeamPipe->add(tag);
120 theBeamPipe->add(pvMotherFwdPlus);
121
122 // FwdMinus
123 theBeamPipe->add(tag);
124 theBeamPipe->add(new GeoTransform(GeoTrf::RotateY3D(180*Gaudi::Units::degree)));
125 theBeamPipe->add(pvMotherFwdMinus);
126
127 const GeoShape *shape = envelopes.bpShape;
128 GeoLogVol* lvMother = new GeoLogVol("BeamPipe",shape,air);
129 GeoPhysVol* pvMother = new GeoPhysVol(lvMother);
130 pvMother->add(tag);
131 pvMother->add(theBeamPipe);
132
133 world->add(tag);
134 world->add(pvMother);
135 m_detectorManager->addTreeTop(pvMother);
136 }
137 else{
138 // Default beam pipe, union of central and forward beampipes rather than assembly volume
139 // Central
140 world->add(tag);
141 world->add(new GeoTransform(GeoTrf::Translate3D(beamx,beamy,beamz)));
142 world->add(pvMotherCentral);
143 m_detectorManager->addTreeTop(pvMotherCentral); //
144 // FwdPlus
145 world->add(tag);
146 world->add(pvMotherFwdPlus);
147 m_detectorManager->addTreeTop(pvMotherFwdPlus);
148 // FwdMinus
149 world->add(tag);
150 world->add(new GeoTransform(GeoTrf::RotateY3D(180*Gaudi::Units::degree)));
151 world->add(pvMotherFwdMinus);
152 m_detectorManager->addTreeTop(pvMotherFwdMinus);
153 }
154}
155
156void BeamPipeDetectorFactory::addSections(GeoPhysVol* parent, int region)
157{
158
159 IRDBRecordset_ptr bpipeSections = m_access->getRecordsetPtr("BPipeSections",m_versionTag,m_versionNode);
160
161 bool central = (region == 0);
162
163 // Sections 2 & 3 are placed in section 1.
164 // pvMotherSection will point to section 1.
165 GeoPhysVol* pvMotherSection = nullptr;
166 bool addToFirstSection = true;
167 double rminSec1 = 0;
168 double rmaxSec1 = 0;
169 double zminSec1 = 0;
170 double zmaxSec1 = 0;
171
172 for (unsigned int itemp=0; itemp<bpipeSections->size(); itemp++)
173 {
174 std::string material = (*bpipeSections)[itemp]->getString("MATERIAL");
175 double rMin1 = (*bpipeSections)[itemp]->getDouble("RMIN1") * Gaudi::Units::mm;
176 double rMax1 = (*bpipeSections)[itemp]->getDouble("RMAX1") * Gaudi::Units::mm;
177 double rMin2 = (*bpipeSections)[itemp]->getDouble("RMIN2") * Gaudi::Units::mm;
178 double rMax2 = (*bpipeSections)[itemp]->getDouble("RMAX2") * Gaudi::Units::mm;
179 double z = (*bpipeSections)[itemp]->getDouble("Z") * Gaudi::Units::mm;
180 double dZ = (*bpipeSections)[itemp]->getDouble("DZ") * Gaudi::Units::mm;
181 int secNum = (*bpipeSections)[itemp]->getInt("SECNUM");
182
183 double zmin = z - dZ;
184 double zmax = z + dZ;
185
186
187 // Check if in central or fwd region or if it is split.
188 // We assume it is left/right symmetric.
189 if (central) {
190 if (zmin > m_centralRegionZMax) continue;
191 if (zmax > m_centralRegionZMax) zmax = m_centralRegionZMax;
192 if (zmax < -m_centralRegionZMax) continue;
193 if (zmin < -m_centralRegionZMax) zmin = -m_centralRegionZMax;
194 } else {
195 if (zmax < m_centralRegionZMax) continue;
196 if (zmin < m_centralRegionZMax) zmin = m_centralRegionZMax;
197 }
198
199
200 double znew = 0.5 * (zmin + zmax);
201 double dZnew = 0.5 * (zmax - zmin);
202
203 std::ostringstream os;
204 if (central) {
205 os << "SectionC";
206 } else {
207 os << "SectionF";
208 }
209 os << std::setw(2) << std::setfill('0') << secNum;
210 std::string name = os.str();
211
212 //std::cout << "Adding section: " << name
213 // << " rmin1,rmin2,rmax1,rmax2,z,dz = "
214 // << rMin1 << ", "
215 // << rMin2 << ", "
216 // << rMax1 << ", "
217 // << rMax2 << ", "
218 // << znew << ", "
219 // << dZnew << ", "
220 // << material << std::endl;
221
222 bool isTube = true;
223 GeoShape* shape;
224 if((rMin1==rMin2)&&(rMax1==rMax2)) {
225 shape = new GeoTube(rMin1,rMax1,dZnew);
226 isTube = true;
227 } else {
228 shape = new GeoCons(rMin1,rMin2,
229 rMax1,rMax2,
230 dZnew,
231 0*Gaudi::Units::deg,360*Gaudi::Units::deg);
232 isTube = false;
233 }
234
235 const GeoMaterial* mat = m_materialManager->getMaterial(material);
236 if (mat == nullptr) {
237 // For backward compatibility - older geometry versions didn't specify the
238 // material namespace
239 // std::cout << "Material """ << material << """ not found. Trying std::" << material << std::endl;
240 mat = m_materialManager->getMaterial("std::"+material);
241 }
242
243 GeoLogVol* lvSection = new GeoLogVol(name,shape,mat);
244 GeoIntrusivePtr<GeoPhysVol> pvSection{new GeoPhysVol(lvSection)};
245
246 // Determine if this is a geometry where the first section can act as the mother of the following
247 // sections. The following sections are only added to this if their ave radius is within the radial
248 // extent and their ave z is within the z extent.
249 // As soon as one section fails to meet this the latter sections are not considered.
250 if(secNum==1) {
251 pvMotherSection = pvSection;
252 rminSec1 = rMin1;
253 rmaxSec1 = rMax1;
254 zminSec1 = zmin;
255 zmaxSec1 = zmax;
256 }
257
258 if (addToFirstSection && secNum != 1) {
259 double rAve = 0.5*(rMin1+rMax1);
260 addToFirstSection = (znew > zminSec1 && znew < zmaxSec1 &&
261 rAve > rminSec1 && rAve < rmaxSec1);
262 }
263
264
265 GeoTransform* tfSection = nullptr;
266 if (znew != 0 && (secNum==1 || !addToFirstSection)) tfSection = new GeoTransform(GeoTrf::TranslateZ3D(znew));
267 GeoIntrusivePtr<GeoNameTag> ntSection{new GeoNameTag(name)};
268
269 if (addToFirstSection && secNum!=1) {
270 if (!pvMotherSection) {
271 MsgStream gLog(Athena::getMessageSvc(), "BeamPipeDetectorFactory");
272 gLog << MSG::ERROR << "Logic error building beam pipe." << endmsg;
273 }
274 else {
275 //std::cout << "Placing section " << secNum << " in Section1" << std::endl;
276 pvMotherSection->add(ntSection);
277 pvMotherSection->add(pvSection);
278 }
279 } else {
280 //std::cout << "Placing section " << secNum << " in mother envelope" << std::endl;
281 parent->add(ntSection);
282 if (tfSection) parent->add(tfSection);
283 parent->add(pvSection);
284 }
285
286 // Not needed, but just in case in the future we have +/- sections in central region
287 if(central && z!=0.) {
288 // add rotated section as well
289 GeoTransform* tfSectionRot = nullptr;
290 if (isTube) {
291 // No need for rotation.
292 tfSectionRot = new GeoTransform(GeoTrf::TranslateZ3D(-znew));
293 } else {
294 // For cone we need to rotate around Y axis.
295 tfSectionRot = new GeoTransform(GeoTrf::TranslateZ3D(-znew)*GeoTrf::RotateY3D(180*Gaudi::Units::deg));
296 }
297 parent->add(ntSection);
298 parent->add(tfSectionRot);
299 parent->add(pvSection);
300 }
301
302 }
303}
304
309
310void BeamPipeDetectorFactory::setTagNode(std::string tag, std::string node, std::string mode)
311{
312 m_versionTag = std::move(tag);
313 m_versionNode = std::move(node);
314 m_mode = std::move(mode);
315}
316
317
320{
321 EnvelopeShapes envelopes;
322
323 std::vector<EnvelopeEntry> centralEntry;
324 std::vector<EnvelopeEntry> fwdEntry;
325
326 for (unsigned int i=0; i<bpipeEnvelope->size(); i++) {
327 double z = (*bpipeEnvelope)[i]->getDouble("Z") * Gaudi::Units::mm;
328 double r = (*bpipeEnvelope)[i]->getDouble("R") * Gaudi::Units::mm;
329 EnvelopeEntry entry(z,r);
330 if (z < m_centralRegionZMax) {
331 centralEntry.push_back(entry);
332 } else {
333 fwdEntry.push_back(entry);
334 }
335 }
336
337 double rFwd = 0;
338 if (!fwdEntry.empty()) {
339 rFwd = fwdEntry[0].r();
340 } else if (!centralEntry.empty()) {
341 rFwd = centralEntry[0].r();
342 } else {
343 std::cout << "Unexpected condition when building beam pipe." << std::endl;
344 }
345
346 // central
347 if (centralEntry.empty()) {
348 envelopes.centralShape = new GeoTube(0, rFwd, m_centralRegionZMax);
349 } else {
350 // This case probably will never get used and is untested.
351 GeoRef<GeoPcon> pcone (new GeoPcon(0, 360*Gaudi::Units::deg));
352
353 pcone->addPlane(-m_centralRegionZMax,0,rFwd);
354 for (int i=centralEntry.size()-1; i>=0; i--) {
355 double z = centralEntry[i].z();
356 double r = centralEntry[i].r();
357 pcone->addPlane(-z,0,r);
358 }
359 for (unsigned int i=0; i<centralEntry.size(); i++) {
360 double z = centralEntry[i].z();
361 double r = centralEntry[i].r();
362 pcone->addPlane(z,0,r);
363 }
364 pcone->addPlane(m_centralRegionZMax,0,rFwd);
365 envelopes.centralShape = pcone;
366 }
367
368
369 // forward
370 {
371 GeoRef<GeoPcon> pcone (new GeoPcon(0, 360*Gaudi::Units::deg));
372 pcone->addPlane(m_centralRegionZMax,0,rFwd);
373 if (fwdEntry.empty()) {
374 // Unlikely case but for completeness
375 // we make small fwd region if everything is in central region.
376 pcone->addPlane(m_centralRegionZMax+0.1*Gaudi::Units::mm,0,rFwd);
377 }
378 for (unsigned int i=0; i<fwdEntry.size(); i++) {
379 double z = fwdEntry[i].z();
380 double r = fwdEntry[i].r();
381 pcone->addPlane(z,0,r);
382 }
383 envelopes.fwdShape = pcone;
384 }
385
386 //central+fwd
387 {
388 GeoRef<GeoPcon> Pcone =(new GeoPcon(0, 360*Gaudi::Units::deg));
389 for (int i=fwdEntry.size()-1; i>=0; i--) {
390 double z = fwdEntry[i].z();
391 double r = fwdEntry[i].r();
392 Pcone->addPlane(-z,0,r);
393 }
394 Pcone->addPlane(-m_centralRegionZMax,0,rFwd);
395 Pcone->addPlane(m_centralRegionZMax,0,rFwd);
396 for (unsigned int i=0; i<fwdEntry.size(); i++) {
397 double z = fwdEntry[i].z();
398 double r = fwdEntry[i].r();
399 Pcone->addPlane(z,0,r);
400 }
401 envelopes.bpShape = Pcone;
402 }
403
404 return envelopes;
405
406}
407
408
411{
412
413 double iir = (*atlasMother)[0]->getDouble("IDETIR")*Gaudi::Units::cm;
414 double cir = (*atlasMother)[0]->getDouble("CALOIR")*Gaudi::Units::cm;
415 double mir = (*atlasMother)[0]->getDouble("MUONIR")*Gaudi::Units::cm;
416 double totlen = (*atlasMother)[0]->getDouble("ZMAX")*Gaudi::Units::cm;
417 double ilen = (*atlasMother)[0]->getDouble("IDETZMX")*Gaudi::Units::cm;
418 double clen = (*atlasMother)[0]->getDouble("CALOZMX")*Gaudi::Units::cm;
419
420 // Central Section.
421 GeoRef<GeoTube> bpipeCentralShape (new GeoTube(0, iir, m_centralRegionZMax));
422
423 // Left/Right section. We create this once (as the +ve z section) and
424 // place th -ve section by doing a rotation.
425
426 // Right section (+ve z)
427
428 GeoRef<GeoPcon> bpipeEnvPcone (new GeoPcon(0, 360*Gaudi::Units::deg));
429 bpipeEnvPcone->addPlane(m_centralRegionZMax,0,iir);
430 bpipeEnvPcone->addPlane(ilen,0,iir);
431 bpipeEnvPcone->addPlane(ilen,0,cir);
432 bpipeEnvPcone->addPlane(clen,0,cir);
433 bpipeEnvPcone->addPlane(clen,0,mir);
434 bpipeEnvPcone->addPlane(totlen,0,mir);
435
436 // These get returned.
437 EnvelopeShapes envelopes;
438 envelopes.centralShape = bpipeCentralShape;
439 envelopes.fwdShape = bpipeEnvPcone;
440
441 return envelopes;
442}
443
444
#define endmsg
GeoIntrusivePtr< T > GeoRef
Definition GeoRef.h:20
Definition of the abstract IRDBAccessSvc interface.
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
#define z
EnvelopeShapes makeEnvelope(const IRDBRecordset_ptr &bpipeEnvelope)
virtual void create(GeoPhysVol *world) override
EnvelopeShapes makeEnvelopeOld(const IRDBRecordset_ptr &atlasMother)
void addSections(GeoPhysVol *parent, int region)
BeamPipeDetectorManager * m_detectorManager
void setTagNode(std::string tag, std::string node, std::string mode)
StoredMaterialManager * m_materialManager
virtual const BeamPipeDetectorManager * getDetectorManager() const override
BeamPipeDetectorFactory(StoreGateSvc *pDetStore, IRDBAccessSvc *pAccess)
IRDBAccessSvc is an abstract interface to the athena service that provides the following functionalit...
virtual unsigned int size() const =0
The Athena Transient Store API.
Definition node.h:24
singleton-like access to IMessageSvc via open function and helper
int r
Definition globals.cxx:22
IMessageSvc * getMessageSvc(bool quiet=false)
=============================================================================