Project
Loading...
Searching...
No Matches
Geometry.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
17
18#include "FV0Base/Geometry.h"
19
20#include <cmath>
21
22#include <fairlogger/Logger.h>
23
24#include <TGeoBBox.h>
25#include <TGeoCompositeShape.h>
26#include <TGeoCone.h>
27#include <TGeoManager.h>
28#include <TGeoMatrix.h>
29#include <TGeoMedium.h>
30#include <TGeoTube.h>
31#include <TGeoVolume.h>
32
34
35using namespace o2::fv0;
36
37Geometry::Geometry(EGeoType initType) : mGeometryType(initType)
38{
39 initializeCellCenters();
40 initializeReadoutCenters();
41 if (initType != eUninitialized) {
42 initializeGeometry();
43 }
44}
45
46Geometry::Geometry(const Geometry& geometry) : mGeometryType(geometry.mGeometryType), mLeftTransformation(nullptr), mRightTransformation(nullptr)
47{
48 this->mEnabledComponents = geometry.mEnabledComponents;
49}
50
52{
53 if (mRightTransformation) {
54 delete mRightTransformation;
55 }
56 if (mLeftTransformation) {
57 delete mLeftTransformation;
58 }
59}
60
62{
63 int detectorHalfID = -1;
64 int sectorID = -1;
65 int ringID = -1;
66
67 fMC->CurrentVolOffID(2, detectorHalfID);
68 fMC->CurrentVolOffID(1, sectorID);
69 fMC->CurrentVolOffID(0, ringID);
70
71 sectorID += detectorHalfID * sNumberOfCellSectors;
72
73 LOG(debug) << "FV0 Geometry::getCurrentCellId(): \n"
74 << "Half id: " << detectorHalfID << "\n"
75 << "Half name: " << fMC->CurrentVolOffName(2) << "\n"
76 << "Sector id: " << sectorID << "\n"
77 << "Sector name: " << fMC->CurrentVolOffName(1) << "\n"
78 << "Ring id: " << ringID << "\n"
79 << "Ring name: " << fMC->CurrentVolOffName(0) << "\n"
80 << "Cell id : " << sectorID + 8 * ringID << "\n";
81
82 return sectorID + 8 * ringID;
83}
84
85bool Geometry::enableComponent(const EGeoComponent component, const bool enable)
86{
87 if (mEnabledComponents.find(component) == mEnabledComponents.end()) {
88 LOG(debug) << "FV0 Geometry::enableComponent(): Component not initialized and cannot be enabled/disabled!";
89 return false;
90 }
91
92 return mEnabledComponents[component] = enable;
93}
94
96{
97 TGeoVolume* vALIC = gGeoManager->GetVolume("barrel");
98 if (!vALIC) {
99 LOG(fatal) << "FV0: Could not find the top volume";
100 }
101
102 // Top volume of FV0 detector
103 TGeoVolumeAssembly* vFV0 = new TGeoVolumeAssembly(sDetectorName.c_str());
104 LOG(info) << "FV0: Building geometry. FV0 volume name is '" << vFV0->GetName() << "'";
105
106 TGeoVolumeAssembly* vFV0Right = new TGeoVolumeAssembly((sDetectorName + "RIGHT").c_str());
107 TGeoVolumeAssembly* vFV0Left = new TGeoVolumeAssembly((sDetectorName + "LEFT").c_str());
108
109 vFV0->AddNode(vFV0Right, 0, mRightTransformation);
110 vFV0->AddNode(vFV0Left, 1, mLeftTransformation);
111
112 assembleSensVols(vFV0Right, vFV0Left);
113 assembleNonSensVols(vFV0Right, vFV0Left);
114
115 vALIC->AddNode(vFV0, 1, new TGeoTranslation(sXGlobal, sYGlobal + 30., sZGlobal));
116}
117
118void Geometry::getGlobalPosition(float& x, float& y, float& z)
119{
120 x = sXGlobal;
121 y = sYGlobal;
122 z = sZGlobal;
123}
124
126{
127 return mCellCenter.at(cellId);
128}
129
131{
132 return mReadoutCenter.at(cellId);
133}
134
135bool Geometry::isRing5(UInt_t cellId)
136{
137 return cellId >= (sNumberOfCellRings - 1) * sNumberOfCellSectors * 2;
138}
139
140void Geometry::initializeGeometry()
141{
142 initializeMaps();
143 initializeVectors();
144 initializeTransformations();
145 initializeSensVols();
146 initializeNonSensVols();
147}
148
149void Geometry::initializeMaps()
150{
151 const bool isFull = mGeometryType == eFull;
152 const bool isRough = isFull || mGeometryType == eRough;
153 const bool hasScint = isRough || mGeometryType == eOnlySensitive;
154 mEnabledComponents.insert(std::pair<EGeoComponent, bool>(eScintillator, hasScint));
155 mEnabledComponents.insert(std::pair<EGeoComponent, bool>(ePlastics, isRough));
156 mEnabledComponents.insert(std::pair<EGeoComponent, bool>(ePmts, isFull));
157 mEnabledComponents.insert(std::pair<EGeoComponent, bool>(eFibers, isFull));
158 mEnabledComponents.insert(std::pair<EGeoComponent, bool>(eScrews, isFull));
159 mEnabledComponents.insert(std::pair<EGeoComponent, bool>(eRods, isFull));
160 mEnabledComponents.insert(std::pair<EGeoComponent, bool>(eContainer, isRough));
161}
162
163void Geometry::initializeVectors()
164{
165 initializeCellRingRadii();
166 initializeSectorTransformations();
167 initializeFiberVolumeRadii();
168 initializeFiberMedium();
169 initializeScrewAndRodRadii();
170 initializeScrewTypeMedium();
171 initializeRodTypeMedium();
172 initializeScrewAndRodPositionsAndDimensions();
173}
174
175void Geometry::initializeCellRingRadii()
176{
177 // Index of mRAvgRing is NOT linked directly to any ring number
178 mRAvgRing.assign(sCellRingRadii, sCellRingRadii + sNumberOfCellRings + 1);
179
180 // Set real scintillator radii (reduced by paint thickness and separation gap)
181 for (int i = 0; i < mRAvgRing.size() - 1; ++i) {
182 mRMinScintillator.push_back(mRAvgRing[i] + sDrSeparationScint);
183 mRMaxScintillator.push_back(mRAvgRing[i + 1] - sDrSeparationScint);
184 }
185 // Now indices of mRMinScint and mRMaxScint correspond to the same ring
186}
187
188void Geometry::initializeSectorTransformations()
189{
190 for (int iSector = 0; iSector < sNumberOfCellSectors; ++iSector) {
191 // iSector = 0 corresponds to the first sector clockwise from the y-axis
192 // iSector = 1 corresponds to the next sector in clockwise direction and so on
193
194 TGeoRotation* trans = createAndRegisterRot(sDetectorName + sSectorName + std::to_string(iSector) + "TRANS");
195
196 if (iSector == 2 || iSector == 3) {
197 // "a" and "b" mirrors.
198 // The reference to "a" and "b" can be understood with the CAD drawings of the detector.
199 trans->ReflectY(true);
200 }
201
202 mSectorTrans.push_back(trans);
203 }
204}
205
206void Geometry::initializeFiberVolumeRadii()
207{
208 for (int i = 0; i < sNumberOfCellRings; i++) {
209 mRMinFiber.push_back(sCellRingRadii[i] + sEpsilon / 2);
210 mRMaxFiber.push_back(sCellRingRadii[i + 1] - sEpsilon / 2);
211 }
212}
213
214void Geometry::initializeFiberMedium()
215{
216 TGeoMedium* medium;
217 TString mediumName;
218
219 // one fiber volume per ring
220 for (int i = 0; i < mRMinFiber.size(); i++) {
221 mediumName = Form("FV0_FiberRing%i$", i + 1);
222 medium = gGeoManager->GetMedium(mediumName);
223 if (!medium) {
224 LOG(warning) << Form("FV0 geometry: Fiber medium for ring no. %i (%s) not found!", i + 1, mediumName.Data());
225 }
226 mMediumFiberRings.push_back(medium);
227 }
228
229 // five fiber volumes in front of the PMTs, one from each scintillator cell (two volumes from cell 5 but they are identical)
230 for (int i = 0; i < sNumberOfPMTFiberVolumes; i++) {
231 mediumName = Form("FV0_FiberPMT%i$", i + 1);
232 medium = gGeoManager->GetMedium(mediumName);
233 if (!medium) {
234 LOG(warning) << Form("FV0 geometry: PMT fiber medium from cell no. %i (%s) not found!", i + 1, mediumName.Data());
235 }
236 mMediumFiberPMTs.push_back(medium);
237 }
238}
239
240void Geometry::initializeScrewAndRodRadii()
241{
242 mRScrewAndRod.push_back(mRAvgRing[1]);
243 mRScrewAndRod.push_back(mRAvgRing[2]);
244 mRScrewAndRod.push_back(mRAvgRing[3]);
245 mRScrewAndRod.push_back(mRAvgRing[4]);
246 mRScrewAndRod.push_back((mRAvgRing[4] + mRAvgRing[5]) / 2);
247 mRScrewAndRod.push_back(mRAvgRing[5]);
248}
249
250void Geometry::initializeScrewTypeMedium()
251{
252 // There are no further checks if the medium is actually found
253 TGeoMedium* medium = gGeoManager->GetMedium("FV0_Titanium$");
254 for (int i = 0; i < sNumberOfScrewTypes; ++i) {
255 mMediumScrewTypes.push_back(medium);
256 }
257}
258
259void Geometry::initializeRodTypeMedium()
260{
261 // There are no further checks if the medium is actually found
262 TGeoMedium* medium = gGeoManager->GetMedium("FV0_Aluminium$");
263 for (int i = 0; i < sNumberOfRodTypes; ++i) {
264 mMediumRodTypes.push_back(medium);
265 }
266}
267
268void Geometry::addScrewProperties(const int screwTypeID, const int iRing, const float phi)
269{
270 float r = mRScrewAndRod[iRing];
271 mScrewTypeIDs.push_back(screwTypeID);
272 mScrewPos.push_back(std::vector<float>{cosf(phi * M_PI / 180) * r,
273 sinf(phi * M_PI / 180) * r,
274 sZScintillator - sDzScintillator / 2 + sZShiftScrew + sDzMaxScrewTypes[screwTypeID] / 2});
275 mDrMinScrews.push_back(sDrMinScrewTypes[screwTypeID]);
276 mDrMaxScrews.push_back(sDrMaxScrewTypes[screwTypeID]);
277 mDzMaxScrews.push_back(sDzMaxScrewTypes[screwTypeID]);
278 mDzMinScrews.push_back(sDzMinScrewTypes[screwTypeID]);
279}
280
281void Geometry::addRodProperties(const int rodTypeID, const int iRing)
282{
283 mRodTypeIDs.push_back(rodTypeID);
284 mRodPos.push_back(std::vector<float>{sDxMinRodTypes[rodTypeID] / 2,
285 mRScrewAndRod[iRing],
286 sZScintillator - sDzScintillator / 2 + sZShiftRod + sDzMaxRodTypes[rodTypeID] / 2});
287 mDxMinRods.push_back(sDxMinRodTypes[rodTypeID]);
288 mDzMaxRods.push_back(sDxMaxRodTypes[rodTypeID]);
289 mDyMinRods.push_back(sDyMinRodTypes[rodTypeID]);
290 mDyMaxRods.push_back(sDyMaxRodTypes[rodTypeID]);
291 mDzMaxRods.push_back(sDzMaxRodTypes[rodTypeID]);
292 mDzMinRods.push_back(sDzMinRodTypes[rodTypeID]);
293
294 mRodTypeIDs.push_back(rodTypeID);
295 mRodPos.push_back(std::vector<float>{sDxMinRodTypes[rodTypeID] / 2,
296 -mRScrewAndRod[iRing],
297 sZScintillator - sDzScintillator / 2 + sZShiftRod + sDzMaxRodTypes[rodTypeID] / 2});
298 mDxMinRods.push_back(sDxMinRodTypes[rodTypeID]);
299 mDzMaxRods.push_back(sDxMaxRodTypes[rodTypeID]);
300 mDyMinRods.push_back(sDyMinRodTypes[rodTypeID]);
301 mDyMaxRods.push_back(sDyMaxRodTypes[rodTypeID]);
302 mDzMaxRods.push_back(sDzMaxRodTypes[rodTypeID]);
303 mDzMinRods.push_back(sDzMinRodTypes[rodTypeID]);
304}
305
306void Geometry::initializeScrewAndRodPositionsAndDimensions()
307{
308 for (int iRing = 0; iRing < mRScrewAndRod.size(); ++iRing) {
309 switch (iRing) {
310 case 0:
311 addRodProperties(0, iRing);
312 for (float phi = 45; phi >= -45; phi -= 45) {
313 addScrewProperties(0, iRing, phi);
314 }
315 break;
316 case 1:
317 addRodProperties(0, iRing);
318 for (float phi = 45; phi >= -45; phi -= 45) {
319 addScrewProperties(1, iRing, phi);
320 }
321 break;
322 case 2:
323 addRodProperties(1, iRing);
324 for (float phi = 67.5; phi >= -67.5; phi -= 22.5) {
325 addScrewProperties(2, iRing, phi);
326 }
327 break;
328 case 3:
329 addRodProperties(2, iRing);
330 for (float phi = 67.5; phi >= -67.5; phi -= 22.5) {
331 addScrewProperties(3, iRing, phi);
332 }
333 break;
334 case 4:
335 addRodProperties(3, iRing);
336 for (float phi = 45; phi >= -45; phi -= 45) {
337 addScrewProperties(4, iRing, phi);
338 }
339 break;
340 case 5:
341 addRodProperties(3, iRing);
342 for (float phi = 67.5; phi >= -67.5; phi -= 22.5) {
343 addScrewProperties(5, iRing, phi);
344 }
345 break;
346 default:
347 break;
348 }
349 }
350}
351
352void Geometry::initializeTransformations()
353{
354 TGeoTranslation leftTranslation(-sDxHalvesSeparation / 2, 0, 0);
355 TGeoRotation leftRotation;
356 leftRotation.ReflectX(true);
357 TGeoHMatrix leftTotalTransformation = leftTranslation * leftRotation;
358
359 mLeftTransformation = new TGeoHMatrix(leftTotalTransformation);
360 mRightTransformation = new TGeoTranslation(sDxHalvesSeparation / 2, sDyHalvesSeparation, sDzHalvesSeparation);
361}
362
363void Geometry::initializeSensVols()
364{
365 initializeScintCells();
366}
367
368void Geometry::initializeNonSensVols()
369{
370 initializeScrewHoles();
371 initializeRodHoles();
372 initializePlasticCells();
373 initializePmts();
374 initializeFibers();
375 initializeScrews();
376 initializeRods();
377 initializeMetalContainer();
378}
379
380void Geometry::initializeScrewHoles()
381{
382 std::string boolFormula = "";
383
384 for (int i = 0; i < mScrewPos.size(); ++i) {
385 std::string holeShapeName = sDetectorName + sScrewName + "HOLE" + std::to_string(i);
386 std::string holeTransName = sDetectorName + sScrewName + "HOLETRANS" + std::to_string(i);
387
388 createScrewShape(holeShapeName, mScrewTypeIDs[i], sEpsilon, sEpsilon);
389 createAndRegisterTrans(holeTransName, mScrewPos[i][0] + sXShiftScrews, mScrewPos[i][1], mScrewPos[i][2]);
390
391 boolFormula += ((i != 0) ? "+" : "") + holeShapeName + ":" + holeTransName;
392 }
393
394 new TGeoCompositeShape(sScrewHolesCSName.c_str(), boolFormula.c_str());
395}
396
397void Geometry::initializeRodHoles()
398{
399 std::string boolFormula = "";
400
401 for (int i = 0; i < mRodPos.size(); ++i) {
402 std::string holeShapeName = sDetectorName + sRodName + "HOLE" + std::to_string(i);
403 std::string holeTransName = sDetectorName + sRodName + "HOLETRANS" + std::to_string(i);
404
405 createRodShape(holeShapeName, mRodTypeIDs[i], sEpsilon, sEpsilon);
406 createAndRegisterTrans(holeTransName, mRodPos[i][0] + sXShiftScrews, mRodPos[i][1], mRodPos[i][2]);
407
408 boolFormula += ((i != 0) ? "+" : "") + holeShapeName + ":" + holeTransName;
409 }
410
411 new TGeoCompositeShape(sRodHolesCSName.c_str(), boolFormula.c_str());
412}
413
414void Geometry::initializeCells(const std::string& cellType, const float zThickness, const TGeoMedium* medium,
415 const bool isSensitive)
416{
417 // Creating the two types of cells, "a" and "b", for each ring.
418 // All sectors can be assembled with these cells.
419 //
420 // The reference to "a" and "b" can be understood with the CAD drawings of the detector.
421
422 const float dxHoleCut = sDxHoleExtensionScintillator; // width of extension of hole 1, 2 and 7 in the "a" cell
423 const float xHole = sDrSeparationScint + dxHoleCut; // x-placement of holes 1, 2 and 7 in the "a" cell
424
425 // Sector separation gap shape
426 const std::string secSepShapeName = "FV0_" + cellType + "SectorSeparation";
427 new TGeoBBox(secSepShapeName.c_str(), mRMaxScintillator.back() + sEpsilon, sDrSeparationScint, zThickness / 2);
428
429 // Sector separation gap rotations
430 const std::string secSepRot45Name = "FV0_" + cellType + "SecSepRot45";
431 const std::string secSepRot90Name = "FV0_" + cellType + "SecSepRot90";
432
433 createAndRegisterRot(secSepRot45Name, 45, 0, 0);
434 createAndRegisterRot(secSepRot90Name, 90, 0, 0);
435
436 // Hole shapes
437 const std::string holeSmallName = "FV0_" + cellType + "HoleSmall";
438 const std::string holeLargeName = "FV0_" + cellType + "HoleLarge";
439 const std::string holeSmallCutName = "FV0_" + cellType + "HoleSmallCut";
440 const std::string holeLargeCutName = "FV0_" + cellType + "HoleLargeCut";
441
442 new TGeoTube(holeSmallName.c_str(), 0, sDrHoleSmallScintillator, zThickness / 2);
443 new TGeoTube(holeLargeName.c_str(), 0, sDrHoleLargeScintillator, zThickness / 2);
444 new TGeoBBox(holeSmallCutName.c_str(), dxHoleCut, sDrHoleSmallScintillator, zThickness / 2);
445 new TGeoBBox(holeLargeCutName.c_str(), dxHoleCut, sDrHoleLargeScintillator, zThickness / 2);
446
447 for (int ir = 0; ir < sNumberOfCellRings; ++ir) {
448 // Radii without separation
449 const float rMin = mRAvgRing[ir];
450 const float rMax = mRAvgRing[ir + 1];
451 const float rMid = rMin + (rMax - rMin) / 2;
452
453 // "a"-type cell
454 //
455 // Initial placement:
456 //
457 // y
458 // ^
459 // | 1******
460 // | ************5
461 // | 7*****************
462 // | *********************3
463 // | *******************
464 // | 2**************8
465 // | 6********
466 // | **4
467 // |
468 // |
469 // | O
470 // ------------------------> x
471 //
472 // * = cell volume
473 // numbers = hole numbers (as numbered in the code below)
474 // O = beam pipe
475
476 const std::string aCellName = createVolumeName(cellType + sCellName + "a", ir);
477
478 // Base shape
479 const std::string aCellShapeName = aCellName + "Shape";
480
481 // The cells in the innermost ring have a slightly shifted inner radius origin.
482 if (ir == 0) {
483 // The innermost "a"-type cell
484 const std::string a1CellShapeFullName = aCellShapeName + "Full";
485 const std::string a1CellShapeHoleCutName = aCellShapeName + "HoleCut";
486 const std::string a1CellShapeHoleCutTransName = a1CellShapeHoleCutName + "Trans";
487
488 new TGeoTubeSeg(a1CellShapeFullName.c_str(), 0, mRMaxScintillator[ir], zThickness / 2 - sEpsilon, 45, 90);
489 new TGeoTube(a1CellShapeHoleCutName.c_str(), 0, mRMinScintillator[ir], zThickness);
490
491 createAndRegisterTrans(a1CellShapeHoleCutTransName, sXShiftInnerRadiusScintillator, 0, 0);
492
493 const std::string a1BoolFormula = a1CellShapeFullName + "-" + a1CellShapeHoleCutName + ":" + a1CellShapeHoleCutTransName;
494 new TGeoCompositeShape(aCellShapeName.c_str(), a1BoolFormula.c_str());
495 } else {
496 // The rest of the "a"-type cells
497 new TGeoTubeSeg(aCellShapeName.c_str(), mRMinScintillator[ir], mRMaxScintillator[ir], zThickness / 2, 45, 90);
498 }
499
500 // Translations for screw holes (inner = rmin, half-length = rmid, outer = rmax)
501 //
502 // 1 = outer left
503 // 2 = inner left
504 // 3 = outer right
505 // 4 = inner right
506 // 5 = outer middle
507 // 6 = inner middle
508 // 7 = half-length left
509 // 8 = half-length right
510 //
511 // holes 1, 2 and 7 are slightly shifted along the rim of the cell
512
513 const std::string aHole1TransName = aCellName + "Hole1Trans";
514 const std::string aHole2TransName = aCellName + "Hole2Trans";
515 const std::string aHole3TransName = aCellName + "Hole3Trans";
516 const std::string aHole4TransName = aCellName + "Hole4Trans";
517 const std::string aHole5TransName = aCellName + "Hole5Trans";
518 const std::string aHole6TransName = aCellName + "Hole6Trans";
519 const std::string aHole7TransName = aCellName + "Hole7Trans";
520 const std::string aHole8TransName = aCellName + "Hole8Trans";
521 const std::string aHole1CutTransName = aCellName + "Hole1CutTrans";
522 const std::string aHole2CutTransName = aCellName + "Hole2CutTrans";
523 const std::string aHole7CutTransName = aCellName + "Hole7CutTrans";
524
525 createAndRegisterTrans(aHole1TransName, xHole, cos(asin(xHole / rMax)) * rMax, 0);
526 createAndRegisterTrans(aHole2TransName, xHole, cos(asin(xHole / rMin)) * rMin, 0);
527 createAndRegisterTrans(aHole3TransName, sin(45 * M_PI / 180) * rMax, cos(45 * M_PI / 180) * rMax, 0);
528 createAndRegisterTrans(aHole4TransName, sin(45 * M_PI / 180) * rMin, cos(45 * M_PI / 180) * rMin, 0);
529 createAndRegisterTrans(aHole5TransName, sin(22.5 * M_PI / 180) * rMax, cos(22.5 * M_PI / 180) * rMax, 0);
530 createAndRegisterTrans(aHole6TransName, sin(22.5 * M_PI / 180) * rMin, cos(22.5 * M_PI / 180) * rMin, 0);
531 createAndRegisterTrans(aHole7TransName, xHole, cos(asin(xHole / rMid)) * rMid, 0);
532 createAndRegisterTrans(aHole8TransName, sin(45 * M_PI / 180) * rMid, cos(45 * M_PI / 180) * rMid, 0);
533 createAndRegisterTrans(aHole1CutTransName, 0, cos(asin(xHole / rMax)) * rMax, 0);
534 createAndRegisterTrans(aHole2CutTransName, 0, cos(asin(xHole / rMin)) * rMin, 0);
535 createAndRegisterTrans(aHole7CutTransName, 0, cos(asin(xHole / rMid)) * rMid, 0);
536
537 // Composite shape
538 std::string aBoolFormula = aCellShapeName;
539
540 // sector separation
541 aBoolFormula += "-" + secSepShapeName + ":" + secSepRot45Name;
542 aBoolFormula += "-" + secSepShapeName + ":" + secSepRot90Name;
543
544 // outer holes
545 aBoolFormula += "-" + ((ir < 2) ? holeSmallName : holeLargeName) + ":" + aHole1TransName;
546 aBoolFormula += "-" + ((ir < 2) ? holeSmallCutName : holeLargeCutName) + ":" + aHole1CutTransName;
547 aBoolFormula += "-" + ((ir < 2) ? holeSmallName : holeLargeName) + ":" + aHole3TransName;
548
549 // inner holes
550 if (ir > 0) {
551 const std::string screwHoleName = (ir < 3) ? holeSmallName : holeLargeName;
552 const std::string screwHoleCutName = (ir < 3) ? holeSmallCutName : holeLargeCutName;
553
554 aBoolFormula += "-" + screwHoleName + ":" + aHole2TransName;
555 aBoolFormula += "-" + screwHoleCutName + ":" + aHole2CutTransName;
556 aBoolFormula += "-" + screwHoleName + ":" + aHole4TransName;
557 }
558
559 // outer middle hole
560 if (ir > 1) {
561 aBoolFormula += "-" + holeLargeName + ":" + aHole5TransName;
562 }
563
564 // inner middle hole
565 if (ir > 2) {
566 aBoolFormula += "-" + holeLargeName + ":" + aHole6TransName;
567 }
568
569 // half-length holes
570 if (ir == 4) {
571 aBoolFormula += "-" + holeLargeName + ":" + aHole7TransName;
572 aBoolFormula += "-" + holeLargeCutName + ":" + aHole7CutTransName;
573 aBoolFormula += "-" + holeLargeName + ":" + aHole8TransName;
574 }
575
576 const std::string aCellCSName = aCellName + "CS";
577 const TGeoCompositeShape* aCellCs = new TGeoCompositeShape(aCellCSName.c_str(), aBoolFormula.c_str());
578
579 // Cell volume
580 const TGeoVolume* aCell = new TGeoVolume(aCellName.c_str(), aCellCs, medium);
581
582 // "b"-type cell
583 //
584 // Initial placement:
585 //
586 // y
587 // ^
588 // | 1
589 // | *****
590 // | *********
591 // | 7*************
592 // | ****************5
593 // | 2*******************
594 // | 6*****************
595 // | *****************
596 // | O 4*******8******3
597 // |
598 // ------------------------------> x
599 //
600 // * = cell volume
601 // numbers = number of holes (as numbered in the code below)
602 // O = beam pipe
603
604 const std::string bCellName = createVolumeName(cellType + sCellName + "b", ir);
605
606 // Base shape
607 const std::string bCellShapeName = bCellName + "Shape";
608
609 // The cells in the innermost ring are slightly different than the rest
610 if (ir == 0) {
611 // The innermost "b"-type cell
612 const std::string b1CellShapeFullName = bCellShapeName + "Full";
613 const std::string b1CellShapeHoleCutName = bCellShapeName + "Cut";
614 const std::string b1CellShapeHoleCutTransName = b1CellShapeHoleCutName + "Trans";
615
616 new TGeoTubeSeg(b1CellShapeFullName.c_str(), 0, mRMaxScintillator[ir], zThickness / 2 - sEpsilon, 0, 45);
617 new TGeoTube(b1CellShapeHoleCutName.c_str(), 0, mRMinScintillator[ir], zThickness);
618
619 createAndRegisterTrans(b1CellShapeHoleCutTransName, sXShiftInnerRadiusScintillator, 0, 0);
620
621 const std::string b1BoolFormula = b1CellShapeFullName + "-" + b1CellShapeHoleCutName + ":" + b1CellShapeHoleCutTransName;
622 new TGeoCompositeShape(bCellShapeName.c_str(), b1BoolFormula.c_str());
623 } else {
624 // The rest of the "b"-type cells
625 new TGeoTubeSeg(bCellShapeName.c_str(), mRMinScintillator[ir], mRMaxScintillator[ir], zThickness / 2, 0, 45);
626 }
627
628 // Translations for holes
629 //
630 // 1 = outer left
631 // 2 = inner left
632 // 3 = outer right
633 // 4 = inner right
634 // 5 = outer middle
635 // 6 = inner middle
636 // 7 = half-lenght left
637 // 8 = half-length right
638
639 const std::string bHole1TransName = bCellName + "Hole1Trans";
640 const std::string bHole2TransName = bCellName + "Hole2Trans";
641 const std::string bHole3TransName = bCellName + "Hole3Trans";
642 const std::string bHole4TransName = bCellName + "Hole4Trans";
643 const std::string bHole5TransName = bCellName + "Hole5Trans";
644 const std::string bHole6TransName = bCellName + "Hole6Trans";
645 const std::string bHole7TransName = bCellName + "Hole7Trans";
646 const std::string bHole8TransName = bCellName + "Hole8Trans";
647
648 createAndRegisterTrans(bHole1TransName, sin(45 * M_PI / 180) * rMax, cos(45 * M_PI / 180) * rMax, 0);
649 createAndRegisterTrans(bHole2TransName, sin(45 * M_PI / 180) * rMin, cos(45 * M_PI / 180) * rMin, 0);
650 createAndRegisterTrans(bHole3TransName, rMax, 0, 0);
651 createAndRegisterTrans(bHole4TransName, rMin, 0, 0);
652 createAndRegisterTrans(bHole5TransName, cos(22.5 * M_PI / 180) * rMax, sin(22.5 * M_PI / 180) * rMax, 0);
653 createAndRegisterTrans(bHole6TransName, cos(22.5 * M_PI / 180) * rMin, sin(22.5 * M_PI / 180) * rMin, 0);
654 createAndRegisterTrans(bHole7TransName, sin(45 * M_PI / 180) * rMid, cos(45 * M_PI / 180) * rMid, 0);
655 createAndRegisterTrans(bHole8TransName, rMid, 0, 0);
656
657 // Composite shape
658 std::string bBoolFormula = bCellShapeName;
659
660 // sector separation
661 bBoolFormula += "-" + secSepShapeName;
662 bBoolFormula += "-" + secSepShapeName + ":" + secSepRot45Name;
663
664 // outer holes
665 bBoolFormula += "-" + ((ir < 2) ? holeSmallName : holeLargeName) + ":" + bHole1TransName;
666 bBoolFormula += "-" + ((ir < 2) ? holeSmallName : holeLargeName) + ":" + bHole3TransName;
667
668 // inner holes
669 if (ir > 0) {
670 const std::string holeName = (ir < 3) ? holeSmallName : holeLargeName;
671
672 bBoolFormula += "-" + holeName + ":" + bHole2TransName;
673 bBoolFormula += "-" + holeName + ":" + bHole4TransName;
674 }
675
676 // outer middle hole
677 if (ir > 1) {
678 bBoolFormula += "-" + holeLargeName + ":" + bHole5TransName;
679 }
680
681 // inner middle hole
682 if (ir > 2) {
683 bBoolFormula += "-" + holeLargeName + ":" + bHole6TransName;
684 }
685
686 // half-lenght holes
687 if (ir == 4) {
688 bBoolFormula += "-" + holeLargeName + ":" + bHole7TransName;
689 bBoolFormula += "-" + holeLargeName + ":" + bHole8TransName;
690 }
691
692 const std::string bCellCSName = bCellName + "CS";
693 const TGeoCompositeShape* bCellCs = new TGeoCompositeShape(bCellCSName.c_str(), bBoolFormula.c_str());
694
695 // Cell volume
696 const TGeoVolume* bCell = new TGeoVolume(bCellName.c_str(), bCellCs, medium);
697
698 if (isSensitive) {
699 mSensitiveVolumeNames.push_back(aCell->GetName());
700 mSensitiveVolumeNames.push_back(bCell->GetName());
701 }
702 }
703}
704
705void Geometry::initializeScintCells()
706{
707 const TGeoMedium* medium = gGeoManager->GetMedium("FV0_Scintillator$");
708 initializeCells(sScintillatorName, sDzScintillator, medium, true);
709}
710
711void Geometry::initializePlasticCells()
712{
713 const TGeoMedium* medium = gGeoManager->GetMedium("FV0_Plastic$");
714 initializeCells(sPlasticName, sDzPlastic, medium, false);
715}
716
717void Geometry::initializePmts()
718{
719 const TGeoMedium* medium = gGeoManager->GetMedium("FV0_PMT$");
720 new TGeoVolume(createVolumeName(sPmtName).c_str(), new TGeoTube(createVolumeName(sPmtName + "Shape").c_str(), 0, sDrPmt, sDzPmt / 2), medium);
721}
722
723void Geometry::initializeFibers()
724{
725 // depth of the fiber volumes
726 const float dzFibers = sDzContainer - sDzContainerBack - sDzContainerFront - sDzScintillator - sDzPlastic - 2 * sEpsilon;
727
728 const std::string fiberName = sDetectorName + "Fibers";
729
730 const std::string fiberSepCutName = fiberName + "SepCut";
731 const std::string fiberConeCutName = fiberName + "ConeCut";
732 const std::string fiberHoleCutName = fiberName + "HoleCut";
733
734 const std::string fiberTransName = fiberName + "Trans";
735 const std::string fiberConeCutTransName = fiberConeCutName + "Trans";
736 const std::string fiberHoleCutTransName = fiberHoleCutName + "Trans";
737
738 new TGeoBBox(fiberSepCutName.c_str(), sDrSeparationScint, mRMaxFiber.back() + sEpsilon, dzFibers / 2 + sEpsilon);
739 new TGeoConeSeg(fiberConeCutName.c_str(), sDzContainerCone / 2 + sEpsilon, 0,
740 sDrMinContainerCone + sXYThicknessContainerCone + sEpsilon, 0, sDrMinContainerFront + sEpsilon, -90, 90);
741 new TGeoTube(fiberHoleCutName.c_str(), 0, mRMinScintillator.front(), dzFibers / 2 + sEpsilon);
742
743 createAndRegisterTrans(fiberTransName, sXScintillator, 0, sZFiber);
744 createAndRegisterTrans(fiberConeCutTransName, sXScintillator, 0, sZCone);
745 createAndRegisterTrans(fiberHoleCutTransName, sXScintillator + sXShiftInnerRadiusScintillator, 0, sZFiber);
746
747 for (int i = 0; i < mRMinFiber.size(); ++i) {
748 const std::string fiberShapeName = fiberName + std::to_string(i + 1);
749 new TGeoTubeSeg(fiberShapeName.c_str(), mRMinFiber[i], mRMaxFiber[i] - sEpsilon, dzFibers / 2, -90, 90);
750
751 // Composite shape
752 std::string boolFormula = "";
753 boolFormula += fiberShapeName + ":" + fiberTransName;
754 boolFormula += "-" + fiberSepCutName + ":" + fiberTransName;
755 boolFormula += "-" + fiberConeCutName + ":" + fiberConeCutTransName;
756
757 if (i == 0) {
758 // Cut out the hole in the innermost fiber volume
759 boolFormula += "-" + fiberHoleCutName + ":" + fiberHoleCutTransName;
760 }
761
762 // Remove holes for screws and rods
763 boolFormula += "-" + sScrewHolesCSName;
764 boolFormula += "-" + sRodHolesCSName;
765
766 const TGeoCompositeShape* fiberCS = new TGeoCompositeShape((fiberShapeName + "CS").c_str(), boolFormula.c_str());
767
768 new TGeoVolume(createVolumeName(sFiberName, i + 1).c_str(), fiberCS, mMediumFiberRings[i]);
769 }
770
771 // Volume for fibers in front of PMTs
772 for (int i = 0; i < sNumberOfPMTFiberVolumes; i++) {
773 new TGeoVolume(createVolumeName(sFiberName + sPmtName, i + 1).c_str(),
774 new TGeoTube(createVolumeName(sFiberName + sPmtName + "Shape", i + 1).c_str(), 0, sDrPmt / 2, sDzPmt / 2),
775 mMediumFiberPMTs[i]);
776 }
777}
778
779void Geometry::initializeScrews()
780{
781 for (int i = 0; i < sNumberOfScrewTypes; ++i) {
782 const std::string screwName = createVolumeName(sScrewName, i);
783 const TGeoShape* screwShape = createScrewShape(screwName + "Shape", i, 0, 0, 0);
784
785 // If modifying materials, make sure the appropriate initialization is done in initializeXxxMedium() methods
786 new TGeoVolume(screwName.c_str(), screwShape, mMediumScrewTypes[i]);
787 }
788}
789
790void Geometry::initializeRods()
791{
792 for (int i = 0; i < sNumberOfRodTypes; ++i) {
793 const std::string rodName = createVolumeName(sRodName, i);
794 const TGeoShape* rodShape = createRodShape(rodName + "Shape", i, -sEpsilon, -sEpsilon);
795
796 // If modifying materials, make sure the appropriate initialization is done in initializeXxxMedium() methods
797 new TGeoVolume(rodName.c_str(), rodShape, mMediumRodTypes[i]);
798 }
799}
800
801void Geometry::initializeMetalContainer()
802{
803 // The metal container is constructed starting from the backplate. The backplate is positioned first, relative to
804 // the scintillator cells. The rest of the container parts are positioned relative to the backplate.
805 //
806 // Caution: some position variables are in global coords, and some are relative to some other part of the container
807
808 // Backplate
809
810 const std::string backPlateName = "FV0_BackPlate"; // the full backplate
811 const std::string backPlateStandName = backPlateName + "Stand"; // the stand part of the backplate
812 const std::string backPlateHoleName = backPlateName + "Hole"; // the hole in the middle of the backplate
813 const std::string backPlateHoleCutName = backPlateHoleName + "Cut"; // extension of the hole
814 const std::string backPlateStandTransName = backPlateStandName + "Trans"; // shift of the backplate stand
815 const std::string backPlateHoleTransName = backPlateHoleName + "Trans"; // shift of the backplate inner radius
816
817 new TGeoTubeSeg(backPlateName.c_str(), 0, sDrMaxContainerBack, sDzContainerBack / 2, -90, 90);
818 new TGeoBBox(backPlateStandName.c_str(), sDxContainerStand / 2, (sDrMaxContainerBack + sDyContainerStand) / 2,
819 sDzContainerBack / 2);
820 new TGeoTubeSeg(backPlateHoleName.c_str(), 0, sDrContainerHole, sDzContainerBack / 2, -90, 90);
821 new TGeoBBox(backPlateHoleCutName.c_str(), -sXShiftContainerHole, sDrContainerHole, sDzContainerBack);
822
823 createAndRegisterTrans(backPlateStandTransName, sDxContainerStand / 2,
824 -(sDrMaxContainerBack + sDyContainerStand) / 2, 0);
825 createAndRegisterTrans(backPlateHoleTransName, sXShiftContainerHole, 0, 0);
826
827 // Backplate composite shape
828 std::string backPlateBoolFormula = "";
829 backPlateBoolFormula += backPlateName;
830 backPlateBoolFormula += "+" + backPlateStandName + ":" + backPlateStandTransName;
831 backPlateBoolFormula += "-" + backPlateHoleName + ":" + backPlateHoleTransName;
832 backPlateBoolFormula += "-" + backPlateHoleCutName;
833
834 const std::string backPlateCSName = backPlateName + "CS";
835 const std::string backPlateCSTransName = backPlateCSName + "Trans";
836
837 new TGeoCompositeShape(backPlateCSName.c_str(), backPlateBoolFormula.c_str());
838 createAndRegisterTrans(backPlateCSTransName, 0, 0, sZContainerBack);
839
840 // Frontplate
841
842 // the z-position o the frontplate
843 const float zPosFrontPlate = sZContainerFront;
844 // the height of the total stand overlapping with the rest of the plate
845 const float dyFrontPlateStand = sDyContainerStand + (sDrMaxContainerFront - sDrMinContainerFront) / 2;
846 // the y-position of the total stand
847 const float yPosFrontPlateStand = -sDrMaxContainerFront - sDyContainerStand + dyFrontPlateStand / 2;
848
849 const std::string frontPlateName = "FV0_FrontPlate";
850 const std::string frontPlateStandName = frontPlateName + "Stand";
851 const std::string frontPlateTransName = frontPlateName + "Trans";
852 const std::string frontPlateStandTransName = frontPlateStandName + "Trans";
853
854 new TGeoTubeSeg(frontPlateName.c_str(), sDrMinContainerFront, sDrMaxContainerFront, sDzContainerFront / 2, -90, 90);
855 new TGeoBBox(frontPlateStandName.c_str(), sDxContainerStand / 2, dyFrontPlateStand / 2, sDzContainerBack / 2);
856
857 createAndRegisterTrans(frontPlateTransName, 0, 0, zPosFrontPlate);
858 createAndRegisterTrans(frontPlateStandTransName, sDxContainerStand / 2, yPosFrontPlateStand, 0);
859
860 // Frontplate cone composite shape
861 std::string frontPlateBoolFormula = "";
862 frontPlateBoolFormula += frontPlateName;
863 frontPlateBoolFormula += "+" + frontPlateStandName + ":" + frontPlateStandTransName;
864
865 const std::string frontPlateCSName = frontPlateName + "CS";
866
867 new TGeoCompositeShape(frontPlateCSName.c_str(), frontPlateBoolFormula.c_str());
868
869 // Frontplate cone
870
871 // radial thickness of frontplate cone in the xy-plane
872 const float thicknessFrontPlateCone = sXYThicknessContainerCone;
873 // z-position of the frontplate cone relative to the frontplate
874 const float zPosCone = sDzContainerFront / 2 - sDzContainerCone / 2;
875
876 const std::string frontPlateConeName = "FV0_FrontPlateCone"; // no volume with this name
877 const std::string frontPlateConeShieldName = frontPlateConeName + "Shield"; // the "sides" of the cone
878 const std::string frontPlateConeShieldTransName = frontPlateConeShieldName + "Trans";
879
880 new TGeoConeSeg(frontPlateConeShieldName.c_str(), sDzContainerCone / 2, sDrMinContainerCone,
881 sDrMinContainerCone + thicknessFrontPlateCone, sDrMinContainerFront - thicknessFrontPlateCone,
882 sDrMinContainerFront,
883 -90, 90);
884 createAndRegisterTrans(frontPlateConeShieldTransName, 0, 0, zPosCone);
885
886 // Frontplate cone "bottom"
887
888 // z-position of the cone bottom relative to the frontplate
889 const float zPosConePlate = sDzContainerFront / 2 - sDzContainerCone + thicknessFrontPlateCone / 2;
890 // the bottom of the cone
891 const std::string frontPlateConePlateName = frontPlateConeName + "Plate";
892
893 new TGeoTubeSeg(frontPlateConePlateName.c_str(), 0, sDrMinContainerCone + thicknessFrontPlateCone,
894 thicknessFrontPlateCone / 2, -90, 90);
895
896 // Frontplate cone bottom composite shape
897 std::string frontPlateConePlateCSBoolFormula;
898 frontPlateConePlateCSBoolFormula += frontPlateConePlateName;
899 frontPlateConePlateCSBoolFormula += "-" + backPlateHoleName + ":" + backPlateHoleTransName;
900
901 const std::string frontPlateConePlateCSName = frontPlateConePlateName + "CS";
902 const std::string frontPlateConePlateCSTransName = frontPlateConePlateCSName + "Trans";
903 new TGeoCompositeShape(frontPlateConePlateCSName.c_str(), frontPlateConePlateCSBoolFormula.c_str());
904 createAndRegisterTrans(frontPlateConePlateCSTransName, 0, 0, zPosConePlate);
905
906 // Frontplate cone composite shape
907 std::string frontPlateConeCSBoolFormula = "";
908 frontPlateConeCSBoolFormula += frontPlateConeShieldName + ":" + frontPlateConeShieldTransName;
909 frontPlateConeCSBoolFormula += "+" + frontPlateConePlateCSName + ":" + frontPlateConePlateCSTransName;
910
911 const std::string frontPlateConeCSName = frontPlateConeName + "CS";
912 new TGeoCompositeShape(frontPlateConeCSName.c_str(), frontPlateConeCSBoolFormula.c_str());
913
914 // Shields
915 const float dzShieldGap = 0.7; // z-distance between the shields and the front- and backplate outer edges (in z-direction)
916 const float dzShield = sDzContainer - 2 * dzShieldGap; // depth of the shields
917
918 // Outer shield
919 const float zPosOuterShield = (sZContainerBack + sZContainerFront) / 2; // z-position of the outer shield
920
921 const std::string outerShieldName = "FV0_OuterShield";
922 const std::string outerShieldTransName = outerShieldName + "Trans";
923
924 new TGeoTubeSeg(outerShieldName.c_str(), sDrMinContainerOuterShield, sDrMaxContainerOuterShield, dzShield / 2, -90,
925 90);
926 createAndRegisterTrans(outerShieldTransName, 0, 0, zPosOuterShield);
927
928 // Inner shield
929 const float dzInnerShield = sDzContainer - sDzContainerCone - dzShieldGap; // depth of the inner shield
930 const float zPosInnerShield = sZContainerBack - sDzContainerBack / 2 + dzShieldGap + dzInnerShield / 2; // z-position of the inner shield relative to the backplate
931
932 const std::string innerShieldName = "FV0_InnerShield";
933 const std::string innerShieldCutName = innerShieldName + "Cut";
934
935 new TGeoTubeSeg(innerShieldName.c_str(), sDrMinContainerInnerShield, sDrMaxContainerInnerShield, dzInnerShield / 2, -90, 90);
936 new TGeoBBox(innerShieldCutName.c_str(), fabs(sXShiftContainerHole), sDrMaxContainerInnerShield, dzInnerShield / 2);
937
938 // Inner shield composite shape
939 std::string innerShieldCSBoolFormula;
940 innerShieldCSBoolFormula = innerShieldName;
941 innerShieldCSBoolFormula += "-" + innerShieldCutName;
942
943 const std::string innerShieldCSName = innerShieldName + "CS";
944 const std::string innerShieldCSTransName = innerShieldCSName + "Trans";
945 new TGeoCompositeShape(innerShieldCSName.c_str(), innerShieldCSBoolFormula.c_str());
946 createAndRegisterTrans(innerShieldCSTransName, sXShiftContainerHole, 0, zPosInnerShield);
947
948 // Cover
949 const float dzCover = sDzContainer; // Depth of the covers
950 const float zPosCoverConeCut = zPosFrontPlate + zPosCone; // Set the cone cut relative to the frontplate so that the exact position of the aluminium cone part can be used.
951
952 const std::string coverName = "FV0_Cover";
953 const std::string coverConeCutName = coverName + "ConeCut";
954 const std::string coverHoleCutName = coverName + "HoleCut";
955
956 new TGeoBBox(coverName.c_str(), sDxContainerCover / 2, sDrMaxContainerOuterShield, dzCover / 2);
957 new TGeoCone(coverConeCutName.c_str(), sDzContainerCone / 2, 0, sDrMinContainerCone + thicknessFrontPlateCone, 0,
958 sDrMinContainerFront);
959 new TGeoTubeSeg(coverHoleCutName.c_str(), 0, sDrMinContainerInnerShield, dzCover / 2, 0, 360);
960
961 const std::string coverTransName = coverName + "Trans";
962 const std::string coverConeCutTransName = coverConeCutName + "Trans";
963 const std::string coverHoleCutTransName = coverHoleCutName + "Trans";
964
965 createAndRegisterTrans(coverTransName, sDxContainerCover / 2, 0, zPosOuterShield);
966 createAndRegisterTrans(coverConeCutTransName, 0, 0, zPosCoverConeCut);
967 createAndRegisterTrans(coverHoleCutTransName.c_str(), sXShiftContainerHole, 0, zPosOuterShield);
968
969 // Cover composite shape
970 std::string coverCSBoolFormula = "";
971 coverCSBoolFormula += coverName + ":" + coverTransName;
972 coverCSBoolFormula += "-" + coverConeCutName + ":" + coverConeCutTransName;
973 coverCSBoolFormula += "-" + coverHoleCutName + ":" + coverHoleCutTransName;
974
975 const std::string coverCSName = coverName + "CS";
976 new TGeoCompositeShape(coverCSName.c_str(), coverCSBoolFormula.c_str());
977
978 // Stand bottom
979 const float dzStandBottom = sDzContainer - sDzContainerBack - sDzContainerFront;
980 const float dyStandBottomGap = 0.5; // This bottom part is not vertically aligned with the "front and backplate stands"
981 const float dxStandBottomHole = 9.4;
982 const float dzStandBottomHole = 20.4;
983 const float dxStandBottomHoleSpacing = 3.1;
984
985 const std::string standName = "FV0_StandBottom";
986 const std::string standHoleName = standName + "Hole";
987
988 new TGeoBBox(standName.c_str(), sDxContainerStandBottom / 2, sDyContainerStandBottom / 2, dzStandBottom / 2);
989 new TGeoBBox(standHoleName.c_str(), dxStandBottomHole / 2, sDyContainerStandBottom / 2 + sEpsilon,
990 dzStandBottomHole / 2);
991
992 const std::string standHoleTrans1Name = standHoleName + "Trans1";
993 const std::string standHoleTrans2Name = standHoleName + "Trans2";
994 const std::string standHoleTrans3Name = standHoleName + "Trans3";
995
996 createAndRegisterTrans(standHoleTrans1Name, -dxStandBottomHoleSpacing - dxStandBottomHole, 0, 0);
997 createAndRegisterTrans(standHoleTrans2Name, 0, 0, 0);
998 createAndRegisterTrans(standHoleTrans3Name, dxStandBottomHoleSpacing + dxStandBottomHole, 0, 0);
999
1000 // Stand bottom composite shape
1001 const std::string standCSName = standName + "CS";
1002
1003 std::string standBoolFormula = "";
1004 standBoolFormula += standName;
1005 standBoolFormula += "-" + standHoleName + ":" + standHoleTrans1Name;
1006 standBoolFormula += "-" + standHoleName + ":" + standHoleTrans2Name;
1007 standBoolFormula += "-" + standHoleName + ":" + standHoleTrans3Name;
1008
1009 new TGeoCompositeShape(standCSName.c_str(), standBoolFormula.c_str());
1010
1011 const std::string standCSTransName = standCSName + "Trans";
1012
1013 createAndRegisterTrans(standCSTransName.c_str(),
1014 sDxContainerStand - sDxContainerStandBottom / 2,
1015 -(sDrMaxContainerBack + sDyContainerStand) + sDyContainerStandBottom / 2 + dyStandBottomGap,
1016 sZContainerMid);
1017
1018 // Composite shape
1019 std::string boolFormula = "";
1020 boolFormula += backPlateCSName + ":" + backPlateCSTransName;
1021 boolFormula += "+" + frontPlateCSName + ":" + frontPlateTransName;
1022 boolFormula += "+" + frontPlateConeCSName + ":" + frontPlateTransName;
1023 boolFormula += "+" + outerShieldName + ":" + outerShieldTransName;
1024 boolFormula += "+" + innerShieldCSName + ":" + innerShieldCSTransName;
1025 boolFormula += "+" + coverCSName;
1026 boolFormula += "+" + standCSName + ":" + standCSTransName;
1027 boolFormula += "-" + sScrewHolesCSName; // Remove holes for screws
1028 boolFormula += "-" + sRodHolesCSName; // Remove holes for rods
1029
1030 const std::string aluContCSName = "FV0_AluContCS";
1031 const TGeoCompositeShape* aluContCS = new TGeoCompositeShape(aluContCSName.c_str(), boolFormula.c_str());
1032
1033 // Volume
1034 const std::string aluContName = createVolumeName(sContainerName);
1035 const TGeoMedium* medium = gGeoManager->GetMedium("FV0_Aluminium$");
1036 new TGeoVolume(aluContName.c_str(), aluContCS, medium);
1037}
1038
1039void Geometry::assembleSensVols(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1040{
1041 if (mEnabledComponents.at(eScintillator)) {
1042 assembleScintSectors(vFV0Right, vFV0Left);
1043 }
1044}
1045
1046void Geometry::assembleNonSensVols(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1047{
1048 if (mEnabledComponents.at(ePlastics)) {
1049 assemblePlasticSectors(vFV0Right, vFV0Left);
1050 }
1051 if (mEnabledComponents.at(ePmts)) {
1052 assemblePmts(vFV0Right, vFV0Left);
1053 }
1054 if (mEnabledComponents.at(eFibers)) {
1055 assembleFibers(vFV0Right, vFV0Left);
1056 }
1057 if (mEnabledComponents.at(eScrews)) {
1058 assembleScrews(vFV0Right, vFV0Left);
1059 }
1060 if (mEnabledComponents.at(eRods)) {
1061 assembleRods(vFV0Right, vFV0Left);
1062 }
1063 if (mEnabledComponents.at(eContainer)) {
1064 assembleMetalContainer(vFV0Right, vFV0Left);
1065 }
1066}
1067
1068void Geometry::assembleScintSectors(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1069{
1070 TGeoVolumeAssembly* sectors = buildSectorAssembly(sScintillatorName);
1071
1072 // Copy numbers used for cell identification in Geometry::getCurrentCellId()
1073 vFV0Right->AddNode(sectors, 0);
1074 vFV0Left->AddNode(sectors, 1);
1075}
1076
1077void Geometry::assemblePlasticSectors(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1078{
1079 TGeoVolumeAssembly* sectors = buildSectorAssembly(sPlasticName);
1080
1081 // Move the plastic cells next to the scintillator cells
1082 TGeoTranslation* trans = new TGeoTranslation(0, 0, sZPlastic);
1083
1084 vFV0Right->AddNode(sectors, 0, trans);
1085 vFV0Left->AddNode(sectors, 1, trans);
1086}
1087
1088void Geometry::assemblePmts(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1089{
1090 TGeoVolumeAssembly* pmts = new TGeoVolumeAssembly(createVolumeName("PMTS").c_str());
1091 TGeoVolume* pmt = gGeoManager->GetVolume(createVolumeName(sPmtName).c_str());
1092 if (!pmt) {
1093 LOG(warning) << "FV0 Geometry::assemblePmts(): PMT volume not found.";
1094 } else {
1095 for (int i = 0; i < sNumberOfPMTs; i++) {
1096 pmts->AddNode(pmt, i, new TGeoTranslation(sXPmt[i], sYPmt[i], sZPmt));
1097 }
1098 }
1099
1100 vFV0Right->AddNode(pmts, 0);
1101 vFV0Left->AddNode(pmts, 1);
1102}
1103
1104void Geometry::assembleFibers(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1105{
1106 TGeoVolumeAssembly* fibersRight = new TGeoVolumeAssembly(createVolumeName("FIBERSRIGHT").c_str());
1107 TGeoVolumeAssembly* fibersLeft = new TGeoVolumeAssembly(createVolumeName("FIBERSLEFT").c_str());
1108 TGeoVolume* fiber;
1109 TString volumeName;
1110
1111 for (int i = 0; i < mRMinFiber.size(); ++i) {
1112 volumeName = createVolumeName(sFiberName, i + 1);
1113 fiber = gGeoManager->GetVolume(volumeName);
1114 if (!fiber) {
1115 LOG(warning) << Form("FV0 geometry: Fiber volume no. %i (%s) not found!", i + 1, volumeName.Data());
1116 } else {
1117 fibersRight->AddNode(fiber, i);
1118 fibersLeft->AddNode(fiber, i);
1119 }
1120 }
1121
1122 int iPMTFiberCell = 0;
1123 for (int i = 0; i < sNumberOfPMTs; i++) {
1124 if (iPMTFiberCell == sNumberOfPMTsPerSector) {
1125 iPMTFiberCell = 0;
1126 }
1127
1128 volumeName = createVolumeName(sFiberName + sPmtName, sPMTFiberCellOrder[iPMTFiberCell]);
1129 fiber = gGeoManager->GetVolume(volumeName);
1130
1131 if (!fiber) {
1132 LOG(warning) << Form("FV0 geometry: Volume of fibers from cell %i (%s) not found!", iPMTFiberCell, volumeName.Data());
1133 } else {
1134 fibersRight->AddNode(fiber, i, new TGeoTranslation(sXPmt[i], sYPmt[i], sZPmt + sDzPmt));
1135 }
1136
1137 // The PMT fiber cell order for the left side is not flipped across the x-axis, but rotated clockwise
1138 volumeName = createVolumeName(sFiberName + sPmtName, sPMTFiberCellOrder[abs(iPMTFiberCell - sNumberOfPMTsPerSector) - 1]);
1139 fiber = gGeoManager->GetVolume(volumeName);
1140
1141 if (!fiber) {
1142 LOG(warning) << Form("FV0 geometry: Volume of fibers from cell %i (%s) not found!", iPMTFiberCell, volumeName.Data());
1143 } else {
1144 fibersLeft->AddNode(fiber, i, new TGeoTranslation(sXPmt[i], sYPmt[i], sZPmt + sDzPmt));
1145 }
1146
1147 iPMTFiberCell++;
1148 }
1149
1150 LOG(debug) << Form("FV0 geometry: total weight of fibers = %.4f kg", fibersRight->Weight(1e-5) + fibersLeft->Weight(1e-5));
1151
1152 vFV0Right->AddNode(fibersRight, 0);
1153 vFV0Left->AddNode(fibersLeft, 1);
1154}
1155
1156void Geometry::assembleScrews(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1157{
1158 TGeoVolumeAssembly* screws = new TGeoVolumeAssembly(createVolumeName("SCREWS").c_str());
1159
1160 // If modifying something here, make sure screw initialization is OK
1161 for (int i = 0; i < mScrewPos.size(); ++i) {
1162 TGeoVolume* screw = gGeoManager->GetVolume(createVolumeName(sScrewName, mScrewTypeIDs[i]).c_str());
1163 if (!screw) {
1164 LOG(warning) << "FV0 Geometry::assembleScrews(): Screw no. " << i << " not found";
1165 } else {
1166 screws->AddNode(screw, i, new TGeoTranslation(mScrewPos[i][0] + sXShiftScrews, mScrewPos[i][1], mScrewPos[i][2]));
1167 }
1168 }
1169
1170 vFV0Right->AddNode(screws, 0);
1171 vFV0Left->AddNode(screws, 1);
1172}
1173
1174void Geometry::assembleRods(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1175{
1176 TGeoVolumeAssembly* rods = new TGeoVolumeAssembly(createVolumeName("RODS").c_str());
1177
1178 // If modifying something here, make sure rod initialization is OK
1179 for (int i = 0; i < mRodPos.size(); ++i) {
1180 TGeoVolume* rod = gGeoManager->GetVolume(createVolumeName(sRodName, mRodTypeIDs[i]).c_str());
1181
1182 if (!rod) {
1183 LOG(info) << "FV0 Geometry::assembleRods(): Rod no. " << i << " not found";
1184 } else {
1185 rods->AddNode(rod, i, new TGeoTranslation(mRodPos[i][0] + sXShiftScrews, mRodPos[i][1], mRodPos[i][2]));
1186 }
1187 }
1188
1189 vFV0Right->AddNode(rods, 0);
1190 vFV0Left->AddNode(rods, 1);
1191}
1192
1193void Geometry::assembleMetalContainer(TGeoVolume* vFV0Right, TGeoVolume* vFV0Left) const
1194{
1195 TGeoVolume* container = gGeoManager->GetVolume(createVolumeName(sContainerName).c_str());
1196 if (!container) {
1197 LOG(warning) << "FV0: Could not find container volume";
1198 } else {
1199 vFV0Right->AddNode(container, 0);
1200 vFV0Left->AddNode(container, 1);
1201 }
1202}
1203
1204TGeoVolumeAssembly* Geometry::buildSectorAssembly(const std::string& cellName) const
1205{
1206 TGeoVolumeAssembly* assembly = new TGeoVolumeAssembly(createVolumeName(cellName).c_str());
1207
1208 for (int iSector = 0; iSector < mSectorTrans.size(); ++iSector) {
1209 TGeoVolumeAssembly* sector = buildSector(cellName, iSector);
1210 assembly->AddNode(sector, iSector, mSectorTrans[iSector]);
1211 }
1212
1213 return assembly;
1214}
1215
1216TGeoVolumeAssembly* Geometry::buildSector(const std::string& cellType, const int iSector) const
1217{
1218 TGeoVolumeAssembly* sector = new TGeoVolumeAssembly(createVolumeName(cellType + sSectorName, iSector).c_str());
1219
1220 for (int i = 0; i < sNumberOfCellRings; ++i) {
1221 TGeoVolume* cell = gGeoManager->GetVolume(createVolumeName(cellType + sCellName + sCellTypes[iSector], i).c_str());
1222
1223 if (!cell) {
1224 LOG(warning) << "FV0 Geometry::buildSector(): Couldn't find cell volume no. " << i;
1225 } else {
1226 sector->AddNode(cell, i, new TGeoTranslation(sXScintillator, 0, 0));
1227 }
1228 }
1229
1230 return sector;
1231}
1232
1233TGeoShape* Geometry::createScrewShape(const std::string& shapeName, const int screwTypeID, const float xEpsilon,
1234 const float yEpsilon, const float zEpsilon) const
1235{
1236 const float xyEpsilon = (fabs(xEpsilon) > fabs(yEpsilon)) ? xEpsilon : yEpsilon;
1237 const float dzMax = sDzMaxScrewTypes[screwTypeID] / 2 + zEpsilon;
1238 const float dzMin = sDzMinScrewTypes[screwTypeID] / 2 + zEpsilon;
1239
1240 const std::string thinPartName = shapeName + "Thin";
1241 const std::string thickPartName = shapeName + "Thick";
1242 const std::string thickPartTransName = thickPartName + "Trans";
1243
1244 if ((screwTypeID == 0) || (screwTypeID == 5)) { // for screw types 0 and 5 there is no thick part
1245 return new TGeoTube(shapeName.c_str(), 0, sDrMinScrewTypes[screwTypeID] + xyEpsilon, dzMax);
1246 } else {
1247 new TGeoTube(thinPartName.c_str(), 0, sDrMinScrewTypes[screwTypeID] + xyEpsilon, dzMax);
1248 new TGeoTube(thickPartName.c_str(), 0, sDrMaxScrewTypes[screwTypeID] + xyEpsilon, dzMin);
1249 createAndRegisterTrans(thickPartTransName, 0, 0, -dzMax - sZShiftScrew + sDzScintillator + sDzPlastic + dzMin);
1250 std::string boolFormula = thinPartName;
1251 boolFormula += "+" + thickPartName + ":" + thickPartTransName;
1252 return new TGeoCompositeShape(shapeName.c_str(), boolFormula.c_str());
1253 }
1254}
1255
1256TGeoShape* Geometry::createRodShape(const std::string& shapeName, const int rodTypeID, const float xEpsilon,
1257 const float yEpsilon, const float zEpsilon) const
1258{
1259 const float dxMin = sDxMinRodTypes[rodTypeID] / 2 + xEpsilon;
1260 const float dxMax = sDxMaxRodTypes[rodTypeID] / 2 + xEpsilon;
1261 const float dyMin = sDyMinRodTypes[rodTypeID] / 2 + yEpsilon;
1262 const float dyMax = sDyMaxRodTypes[rodTypeID] / 2 + yEpsilon;
1263 const float dzMax = sDzMaxRodTypes[rodTypeID] / 2 + zEpsilon;
1264 const float dzMin = sDzMinRodTypes[rodTypeID] / 2 + zEpsilon;
1265
1266 const std::string thinPartName = shapeName + "Thin";
1267 const std::string thickPartName = shapeName + "Thick";
1268 const std::string thickPartTransName = thickPartName + "Trans";
1269
1270 new TGeoBBox(thinPartName.c_str(), dxMin, dyMin, dzMax);
1271 new TGeoBBox(thickPartName.c_str(), dxMax, dyMax, dzMin);
1272 createAndRegisterTrans(thickPartTransName, dxMax - dxMin, 0,
1273 -dzMax - sZShiftRod + sDzScintillator + sDzPlastic + dzMin);
1274
1275 std::string boolFormula = thinPartName;
1276 boolFormula += "+" + thickPartName + ":" + thickPartTransName;
1277
1278 TGeoCompositeShape* rodShape = new TGeoCompositeShape(shapeName.c_str(), boolFormula.c_str());
1279 return rodShape;
1280}
1281
1282TGeoTranslation* Geometry::createAndRegisterTrans(const std::string& name, const double dx, const double dy,
1283 const double dz) const
1284{
1285 TGeoTranslation* trans = new TGeoTranslation(name.c_str(), dx, dy, dz);
1286 trans->RegisterYourself();
1287 return trans;
1288}
1289
1290TGeoRotation* Geometry::createAndRegisterRot(const std::string& name, const double phi, const double theta,
1291 const double psi) const
1292{
1293 TGeoRotation* rot = new TGeoRotation(name.c_str(), phi, theta, psi);
1294 rot->RegisterYourself();
1295 return rot;
1296}
1297
1298const std::string Geometry::createVolumeName(const std::string& volumeType, const int number) const
1299{
1300 return sDetectorName + volumeType + ((number >= 0) ? std::to_string(number) : "");
1301}
1302
1303void Geometry::initializeCellCenters()
1304{
1305 const float phi0 = 67.5 * TMath::DegToRad(); // starting phi of one of the sectors
1306 const float dphi = 45. * TMath::DegToRad(); // phi difference between neighbouring sectors
1307 const float lutSect2Phi[sNumberOfCellSectors * 2] = {phi0, phi0 - dphi, phi0 - 2 * dphi, phi0 - 3 * dphi, phi0 + dphi, phi0 + 2 * dphi, phi0 + 3 * dphi, phi0 + 4 * dphi};
1308 for (int cellId = 0; cellId < sNumberOfCells; cellId++) {
1309 float r = 0.5 * (sCellRingRadii[sCellToRing[cellId]] + sCellRingRadii[sCellToRing[cellId] + 1]);
1310 double x = sXGlobal + r * TMath::Cos(lutSect2Phi[sCellToSector[cellId]]);
1311 double y = sYGlobal + r * TMath::Sin(lutSect2Phi[sCellToSector[cellId]]);
1312
1313 Point3Dsimple* p = &mCellCenter.at(cellId);
1314 p->SetCoordinates(x, y, sZGlobal);
1315 }
1316}
1317
1318void Geometry::initializeReadoutCenters()
1319{
1320 for (int channelId = 0; channelId < sNumberOfReadoutChannels; channelId++) {
1321 Point3Dsimple* p = &mReadoutCenter.at(channelId);
1322 if (!isRing5(channelId)) {
1323 p->SetCoordinates(getCellCenter(channelId).x, getCellCenter(channelId).y, getCellCenter(channelId).z);
1324 } else {
1325 const int numberOfSectorsR5 = sNumberOfCellSectors * 4; // from both halves of the detector
1326 const float phi0 = 78.75 * TMath::DegToRad(); // starting phi of one of the sectors
1327 const float dphi = 22.5 * TMath::DegToRad(); // phi difference between neighbouring sectors
1328 const float lutReadoutSect2Phi[numberOfSectorsR5] =
1329 {phi0 - 0 * dphi, phi0 - 1 * dphi, phi0 - 2 * dphi, phi0 - 3 * dphi,
1330 phi0 - 4 * dphi, phi0 - 5 * dphi, phi0 - 6 * dphi, phi0 - 7 * dphi,
1331 phi0 + 1 * dphi, phi0 + 2 * dphi, phi0 + 3 * dphi, phi0 + 4 * dphi,
1332 phi0 + 5 * dphi, phi0 + 6 * dphi, phi0 + 7 * dphi, phi0 + 8 * dphi};
1333
1334 int iReadoutSector = channelId - ((sNumberOfCellRings - 1) * sNumberOfCellSectors * 2);
1335 float r = 0.5 * (sCellRingRadii[4] + sCellRingRadii[5]);
1336 double x = sXGlobal + r * TMath::Cos(lutReadoutSect2Phi[iReadoutSector]);
1337 double y = sYGlobal + r * TMath::Sin(lutReadoutSect2Phi[iReadoutSector]);
1338 p->SetCoordinates(x, y, sZGlobal);
1339 }
1340 }
1341}
1342
1343Geometry* Geometry::sInstance = nullptr;
1344
1345// Singleton access
1347{
1348 if (!sInstance) {
1349 LOG(info) << "FV0 geometry instance created";
1350 }
1351 sInstance = new Geometry(initType);
1352 return sInstance;
1353}
Base definition of FV0 geometry.
ClassImp(o2::fv0::Geometry)
int32_t i
std::ostringstream debug
FV0 Geometry.
Definition Geometry.h:51
void buildGeometry() const
Build the geometry.
Definition Geometry.cxx:95
Point3Dsimple & getReadoutCenter(UInt_t cellId)
Definition Geometry.cxx:130
int getCurrentCellId(const TVirtualMC *fMC) const
Definition Geometry.cxx:61
static Geometry * instance(EGeoType initType=eUninitialized)
bool enableComponent(EGeoComponent component, bool enable=true)
Definition Geometry.cxx:85
Point3Dsimple & getCellCenter(UInt_t cellId)
Definition Geometry.cxx:125
bool isRing5(UInt_t cellId)
Definition Geometry.cxx:135
EGeoComponent
Geometry components possible to be enabled/disabled. Only enabled components will be created.
Definition Geometry.h:67
void getGlobalPosition(float &x, float &y, float &z)
Utility functions to be accessed externally.
Definition Geometry.cxx:118
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean enable
Definition glcorearb.h:3991
GLboolean r
Definition glcorearb.h:1233
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
void SetCoordinates(float x, float y, float z)
Definition Geometry.h:41
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)