Project
Loading...
Searching...
No Matches
ITS3Layer.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
16
17#include "TGeoTube.h"
18#include "TGeoVolume.h"
19#include "TGeoCompositeShape.h"
20
23#include "ITS3Base/SpecsV2.h"
25#include "fairlogger/Logger.h"
26
27namespace o2m = o2::constants::math;
28namespace its3c = o2::its3::constants;
29
30namespace o2::its3
31{
33
34void ITS3Layer::init()
35{
36 mR = its3c::radii[mNLayer];
37 mRmin = its3c::radiiInner[mNLayer];
38 mRmax = its3c::radiiOuter[mNLayer];
39}
40
41void ITS3Layer::getMaterials(bool create)
42{
43 if (gGeoManager == nullptr) {
44 LOGP(fatal, "gGeoManager not initalized!");
45 }
46
47 mSilicon = getMaterial("IT3_SI$", create);
48 mAir = getMaterial("IT3_AIR$", create);
49 mCarbon = getMaterial("IT3_CARBON$", create);
50}
51
52TGeoMedium* ITS3Layer::getMaterial(const char* matName, bool create)
53{
54 auto mat = gGeoManager->GetMedium(matName);
55 if (mat == nullptr) {
56 if (!create) {
57 LOGP(fatal, "Cannot get medium {}", matName);
58 } else { // create dummy
59 auto matDummy = gGeoManager->GetMaterial("MAT_DUMMY$");
60 if (matDummy == nullptr) {
61 LOGP(info, "Created Dummy material");
62 matDummy = new TGeoMaterial("MAT_DUMMY$", 26.98, 13, 2.7);
63 }
64 mat = new TGeoMedium(matName, 1, matDummy);
65 LOGP(info, "Created medium {}", matName);
66 }
67 }
68 return mat;
69}
70
71void ITS3Layer::createLayer(TGeoVolume* motherVolume)
72{
73 // Create one layer of ITS3 and attach it to the motherVolume.
74 getMaterials();
75 createLayerImpl();
76 mBuilt = true;
77
78 LOGP(info, "ITS3-Layer: Created Layer {} with mR={} (minR={}, maxR={})", mNLayer, mR, mRmin, mRmax);
79 if (motherVolume == nullptr) {
80 return;
81 }
82 // Add it to motherVolume
83 LOGP(debug, " `-> Attaching to motherVolume '{}'", motherVolume->GetName());
84 auto* trans = new TGeoTranslation(0, 0, -constants::segment::lengthSensitive / 2.);
85 motherVolume->AddNode(mLayer, 0, trans);
86}
87
88void ITS3Layer::createPixelArray()
89{
90 if (mPixelArray != nullptr) {
91 return;
92 }
93 // A pixel array is pure silicon and the sensitive part of our detector.
94 // It will be segmented into a 442x156 matrix by the
95 // SuperSegmentationAlpide.
96 // Pixel Array is just a longer version of the biasing but starts in phi at
97 // biasPhi2.
98 using namespace its3c::pixelarray;
99 double pixelArrayPhi1 = constants::tile::readout::width / mR * o2m::Rad2Deg;
100 double pixelArrayPhi2 = width / mR * o2m::Rad2Deg + pixelArrayPhi1;
101 auto pixelArray = new TGeoTubeSeg(mRmin, mRmax, length / 2.,
102 pixelArrayPhi1, pixelArrayPhi2);
103 mPixelArray = new TGeoVolume(its3TGeo::getITS3PixelArrayPattern(mNLayer), pixelArray, mSilicon);
104 mPixelArray->SetLineColor(color);
105 mPixelArray->RegisterYourself();
106}
107
108void ITS3Layer::createTile()
109{
110 if (mTile != nullptr) {
111 return;
112 } else {
113 createPixelArray();
114 }
115 // This functions creates a single Tile, which is the basic building block
116 // of the chip. It consists of a pixelArray (sensitive area), biasing, power
117 // switches and readout periphery (latter three are insensitive).
118 // We construct the Tile such that the PixelArray is in the z-middle
119 using namespace constants::tile;
120 mTile = new TGeoVolumeAssembly(its3TGeo::getITS3TilePattern(mNLayer));
121 mTile->VisibleDaughters();
122
123 // The readout periphery is also on top of the pixel array but extrudes on +z a bit e.g. is wider.
124 auto zMoveReadout = new TGeoTranslation(0, 0, +powerswitches::length / 2.);
125 double readoutPhi1 = 0;
126 double readoutPhi2 = readout::width / mR * o2m::Rad2Deg;
127 auto readout = new TGeoTubeSeg(mRmin, mRmax, readout::length / 2, readoutPhi1, readoutPhi2);
128 auto readoutVol = new TGeoVolume(Form("readout%d", mNLayer), readout, mSilicon);
129 readoutVol->SetLineColor(readout::color);
130 readoutVol->RegisterYourself();
131 mTile->AddNode(readoutVol, 0, zMoveReadout);
132
133 // Pixel Array is just a longer version of the biasing but starts in phi at
134 // biasPhi2.
135 mTile->AddNode(mPixelArray, 0);
136
137 // Biasing
138 double biasPhi1 = constants::pixelarray::width / mR * o2m::Rad2Deg + readoutPhi2;
139 double biasPhi2 = biasing::width / mR * o2m::Rad2Deg + biasPhi1;
140 auto biasing = new TGeoTubeSeg(mRmin, mRmax, biasing::length / 2, biasPhi1, biasPhi2);
141 auto biasingVol = new TGeoVolume(Form("biasing%d", mNLayer), biasing, mSilicon);
142 biasingVol->SetLineColor(biasing::color);
143 biasingVol->RegisterYourself();
144 mTile->AddNode(biasingVol, 0);
145
146 // Power Switches are on the side right side of the pixel array and biasing.
147 auto zMovePowerSwitches = new TGeoTranslation(0, 0, +powerswitches::length / 2. + constants::pixelarray::length / 2.);
148 double powerPhi1 = readoutPhi2;
149 double powerPhi2 = powerswitches::width / mR * o2m::Rad2Deg + powerPhi1;
150 auto powerSwitches = new TGeoTubeSeg(mRmin, mRmax, powerswitches::length / 2, powerPhi1, powerPhi2);
151 auto powerSwitchesVol = new TGeoVolume(Form("powerswitches%d", mNLayer), powerSwitches, mSilicon);
152 powerSwitchesVol->SetLineColor(powerswitches::color);
153 powerSwitchesVol->RegisterYourself();
154 mTile->AddNode(powerSwitchesVol, 0, zMovePowerSwitches);
155}
156
157void ITS3Layer::createRSU()
158{
159 if (mRSU != nullptr) {
160 return;
161 } else {
162 createTile();
163 }
164 // A Repeated Sensor Unit (RSU) is 12 Tiles + 4 Databackbones stichted together.
165 using namespace constants::rsu;
166 mRSU = new TGeoVolumeAssembly(its3TGeo::getITS3RSUPattern(mNLayer));
167 mRSU->VisibleDaughters();
168 int nCopyRSU{0}, nCopyDB{0};
169
170 // Create the DatabackBone
171 // The Databackbone spans the whole phi of the tile.
172 double dataBackbonePhi1 = 0;
173 double dataBackbonePhi2 = databackbone::width / mR * o2m::Rad2Deg;
174 auto dataBackbone = new TGeoTubeSeg(mRmin, mRmax, databackbone::length / 2., dataBackbonePhi1, dataBackbonePhi2);
175 auto dataBackboneVol = new TGeoVolume(Form("databackbone%d", mNLayer), dataBackbone, mSilicon);
176 dataBackboneVol->SetLineColor(databackbone::color);
177 dataBackboneVol->RegisterYourself();
178
179 // Lower Left
180 auto zMoveLL1 = new TGeoTranslation(0, 0, constants::tile::length);
181 auto zMoveLL2 = new TGeoTranslation(0, 0, constants::tile::length * 2.);
182 auto zMoveLLDB = new TGeoTranslation(0, 0, -databackbone::length / 2. - constants::pixelarray::length / 2.);
183 // Lets attach the tiles to the QS.
184 mRSU->AddNode(mTile, nCopyRSU++, nullptr);
185 mRSU->AddNode(mTile, nCopyRSU++, zMoveLL1);
186 mRSU->AddNode(mTile, nCopyRSU++, zMoveLL2);
187 mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveLLDB);
188
189 // Lower Right
190 auto zMoveLR0 = new TGeoTranslation(0, 0, +length / 2.);
191 auto zMoveLR1 = new TGeoTranslation(0, 0, constants::tile::length + length / 2.);
192 auto zMoveLR2 = new TGeoTranslation(0, 0, constants::tile::length * 2. + length / 2.);
193 auto zMoveLRDB = new TGeoTranslation(0, 0, -databackbone::length / 2. + length / 2. - constants::pixelarray::length / 2.);
194 // Lets attach the tiles to the QS.
195 mRSU->AddNode(mTile, nCopyRSU++, zMoveLR0);
196 mRSU->AddNode(mTile, nCopyRSU++, zMoveLR1);
197 mRSU->AddNode(mTile, nCopyRSU++, zMoveLR2);
198 mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveLRDB);
199
200 // Rotation for top half and vertical mirroring
201 double phi = width / mR * o2m::Rad2Deg;
202 auto rot = new TGeoRotation("", 0, 0, -phi);
203 rot->ReflectY(true);
204
205 // Upper Left
206 auto zMoveUL1 = new TGeoCombiTrans(0, 0, constants::tile::length, rot);
207 auto zMoveUL2 = new TGeoCombiTrans(0, 0, constants::tile::length * 2., rot);
208 auto zMoveULDB = new TGeoCombiTrans(0, 0, -databackbone::length / 2. - constants::pixelarray::length / 2., rot);
209 // Lets attach the tiles to the QS.
210 mRSU->AddNode(mTile, nCopyRSU++, rot);
211 mRSU->AddNode(mTile, nCopyRSU++, zMoveUL1);
212 mRSU->AddNode(mTile, nCopyRSU++, zMoveUL2);
213 mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveULDB);
214
215 // Upper Right
216 auto zMoveUR0 = new TGeoCombiTrans(0, 0, +length / 2., rot);
217 auto zMoveUR1 = new TGeoCombiTrans(0, 0, constants::tile::length + length / 2., rot);
218 auto zMoveUR2 = new TGeoCombiTrans(0, 0, constants::tile::length * 2. + length / 2., rot);
219 auto zMoveURDB = new TGeoCombiTrans(0, 0, -databackbone::length / 2. + length / 2. - constants::pixelarray::length / 2., rot);
220 // Lets attach the tiles to the QS.
221 mRSU->AddNode(mTile, nCopyRSU++, zMoveUR0);
222 mRSU->AddNode(mTile, nCopyRSU++, zMoveUR1);
223 mRSU->AddNode(mTile, nCopyRSU++, zMoveUR2);
224 mRSU->AddNode(dataBackboneVol, nCopyDB++, zMoveURDB);
225}
226
227void ITS3Layer::createSegment()
228{
229 if (mSegment != nullptr) {
230 return;
231 } else {
232 createRSU();
233 }
234 // A segment is 12 RSUs + left and right end cap. We place the first rsu
235 // as z-coordinate center and attach to this. Hence, we will displace the
236 // left end-cap to the left and the right to right.
237 using namespace constants::segment;
238 mSegment = new TGeoVolumeAssembly(its3TGeo::getITS3SegmentPattern(mNLayer));
239 mSegment->VisibleDaughters();
240
241 for (size_t i{0}; i < nRSUs; ++i) {
242 auto zMove = new TGeoTranslation(0, 0, +i * constants::rsu::length + constants::rsu::databackbone::length + constants::pixelarray::length / 2.);
243 mSegment->AddNode(mRSU, i, zMove);
244 }
245
246 // LEC
247 double lecPhi1 = 0;
248 double lecPhi2 = lec::width / mR * o2m::Rad2Deg;
249 auto zMoveLEC = new TGeoTranslation(0, 0, -lec::length / 2.);
250 auto lec =
251 new TGeoTubeSeg(mRmin, mRmax, lec::length / 2., lecPhi1, lecPhi2);
252 auto lecVol = new TGeoVolume(Form("lec%d", mNLayer), lec, mSilicon);
253 lecVol->SetLineColor(lec::color);
254 lecVol->RegisterYourself();
255 mSegment->AddNode(lecVol, 0, zMoveLEC);
256
257 // REC; reuses lecPhi1,2
258 auto zMoveREC = new TGeoTranslation(0, 0, nRSUs * constants::rsu::length + rec::length / 2.);
259 auto rec =
260 new TGeoTubeSeg(mRmin, mRmax, rec::length / 2., lecPhi1, lecPhi2);
261 auto recVol = new TGeoVolume(Form("rec%d", mNLayer), rec, mSilicon);
262 recVol->SetLineColor(rec::color);
263 recVol->RegisterYourself();
264 mSegment->AddNode(recVol, 0, zMoveREC);
265}
266
267void ITS3Layer::createChip()
268{
269 if (mChip != nullptr) {
270 return;
271 } else {
272 createSegment();
273 }
274 // A HalfLayer is composed out of multiple segment stitched together along
275 // rphi.
276 mChip = new TGeoVolumeAssembly(its3TGeo::getITS3ChipPattern(mNLayer));
277 mChip->VisibleDaughters();
278
279 for (unsigned int i{0}; i < constants::nSegments[mNLayer]; ++i) {
280 double phiOffset = constants::segment::width / mR * o2m::Rad2Deg;
281 auto rot = new TGeoRotation("", 0, 0, phiOffset * i);
282 mChip->AddNode(mSegment, i, rot);
283 }
284}
285
286void ITS3Layer::createCarbonForm()
287{
288 if (mCarbonForm != nullptr) {
289 return;
290 } else {
291 createChip();
292 }
293 // TODO : Waiting for the further information from WP5(Corrado)
294 using namespace constants::carbonfoam;
295 mCarbonForm = new TGeoVolumeAssembly(its3TGeo::getITS3CarbonFormPattern(mNLayer));
296 mCarbonForm->VisibleDaughters();
297 double dRadius = -1;
298 if (mNLayer < 2) {
299 dRadius = constants::radii[mNLayer + 1] - constants::radii[mNLayer] - constants::thickness;
300 } else {
301 dRadius = 0.7; // TODO: lack of carbon foam radius for layer 2, use 0.7mm as a temporary value
302 }
303 double phiSta = edgeBetwChipAndFoam / (0.5 * constants::radii[mNLayer + 1] + constants::radii[mNLayer]) * o2m::Rad2Deg;
304 double phiEnd = (constants::nSegments[mNLayer] * constants::segment::width) / constants::radii[mNLayer] * o2m::Rad2Deg - phiSta;
305 double phiLongeronsCover = longeronsWidth / (0.5 * constants::radii[mNLayer + 1] + constants::radii[mNLayer]) * o2m::Rad2Deg;
306
307 // H-rings foam
308 auto HringC = new TGeoTubeSeg(Form("HringC%d", mNLayer), mRmax, mRmax + dRadius, HringLength / 2., phiSta, phiEnd);
309 auto HringA = new TGeoTubeSeg(Form("HringA%d", mNLayer), mRmax, mRmax + dRadius, HringLength / 2., phiSta, phiEnd);
310 auto HringCWithHoles = getHringShape(HringC);
311 auto HringAWithHoles = getHringShape(HringA);
312 auto HringCVol = new TGeoVolume(Form("hringC%d", mNLayer), HringCWithHoles, mCarbon);
313 HringCVol->SetLineColor(color);
314 auto HringAVol = new TGeoVolume(Form("hringA%d", mNLayer), HringAWithHoles, mCarbon);
315 HringAVol->SetLineColor(color);
316 auto zMoveHringC = new TGeoTranslation(0, 0, -constants::segment::lec::length + HringLength / 2.);
317 auto zMoveHringA = new TGeoTranslation(0, 0, -constants::segment::lec::length + HringLength / 2. + constants::segment::length - HringLength);
318
319 // Longerons are made by same material
320 [[maybe_unused]] auto longeronR = new TGeoTubeSeg(Form("longeronR%d", mNLayer), mRmax, mRmax + dRadius, longeronsLength / 2, phiSta, phiSta + phiLongeronsCover);
321 [[maybe_unused]] auto longeronL = new TGeoTubeSeg(Form("longeronL%d", mNLayer), mRmax, mRmax + dRadius, longeronsLength / 2, phiEnd - phiLongeronsCover, phiEnd);
322 TString nameLongerons = Form("longeronR%d + longeronL%d", mNLayer, mNLayer);
323 auto longerons = new TGeoCompositeShape(nameLongerons);
324 auto longeronsVol = new TGeoVolume(Form("longerons%d", mNLayer), longerons, mCarbon);
325 longeronsVol->SetLineColor(color);
326 auto zMoveLongerons = new TGeoTranslation(0, 0, -constants::segment::lec::length + constants::segment::length / 2.);
327
328 mCarbonForm->AddNode(HringCVol, 0, zMoveHringC);
329 mCarbonForm->AddNode(HringAVol, 0, zMoveHringA);
330 mCarbonForm->AddNode(longeronsVol, 0, zMoveLongerons);
331 mCarbonForm->AddNode(mChip, 0);
332}
333
334TGeoCompositeShape* ITS3Layer::getHringShape(TGeoTubeSeg* Hring)
335{
336 // Function to dig holes in H-rings
337 using namespace constants::carbonfoam;
338 double stepPhiHoles = (Hring->GetPhi2() - Hring->GetPhi1()) / (nHoles[mNLayer]);
339 double phiHolesSta = Hring->GetPhi1() + stepPhiHoles / 2.;
340 double radiusHring = 0.5 * (Hring->GetRmin() + Hring->GetRmax());
341 TGeoCompositeShape* HringWithHoles = nullptr;
342 TString nameAllHoles = "";
343 for (int iHoles = 0; iHoles < nHoles[mNLayer]; iHoles++) {
344 double phiHole = phiHolesSta + stepPhiHoles * iHoles;
345 TString nameHole = Form("hole_%d_%d", iHoles, mNLayer);
346 [[maybe_unused]] auto hole = new TGeoTube(nameHole, 0, radiusHoles[mNLayer], 3 * Hring->GetDz());
347 // move hole to the hring radius
348 auto zMoveHole = new TGeoTranslation(Form("zMoveHole_%d_%d", iHoles, mNLayer), radiusHring * cos(phiHole * o2m::Deg2Rad), radiusHring * sin(phiHole * o2m::Deg2Rad), 0);
349 zMoveHole->RegisterYourself();
350 nameAllHoles += Form("hole_%d_%d:zMoveHole_%d_%d + ", iHoles, mNLayer, iHoles, mNLayer);
351 }
352 nameAllHoles.Remove(nameAllHoles.Length() - 3, 3);
353 TString nameHringWithHoles = Form("%s - (%s)", Hring->GetName(), nameAllHoles.Data());
354 HringWithHoles = new TGeoCompositeShape(nameHringWithHoles);
355 return HringWithHoles;
356}
357
358void ITS3Layer::createLayerImpl()
359{
360 if (mLayer != nullptr) {
361 return;
362 } else {
363 createCarbonForm();
364 }
365 // At long last a single layer... A layer is two HalfLayers (duuhhh) but
366 // we have to take care of the equatorial gap. So both half layers will be
367 // offset slightly by rotating in phi the upper HalfLayer and negative phi
368 // the other one.
369 mLayer = new TGeoVolumeAssembly(its3TGeo::getITS3LayerPattern(mNLayer));
370 mLayer->VisibleDaughters();
371
372 // The offset is the right angle triangle of the middle radius with the
373 // transverse axis.
374 double phiOffset = std::asin(constants::equatorialGap / 2. / mR) * o2m::Rad2Deg;
375 auto rotTop = new TGeoRotation("", 0, 0, +phiOffset);
376 auto rotBot = new TGeoRotation("", 0, 0, phiOffset + 180);
377
378 mLayer->AddNode(mCarbonForm, 0, rotTop);
379 mLayer->AddNode(mCarbonForm, 1, rotBot);
380}
381
382void ITS3Layer::buildPartial(TGeoVolume* motherVolume, TGeoMatrix* mat, BuildLevel level, bool createMaterials)
383{
384 if (!mBuilt) {
385 getMaterials(createMaterials);
386 }
387 switch (level) {
389 createPixelArray();
390 motherVolume->AddNode(mPixelArray, 0, mat);
391 break;
393 createTile();
394 motherVolume->AddNode(mTile, 0, mat);
395 break;
396 case BuildLevel::kRSU:
397 createRSU();
398 motherVolume->AddNode(mRSU, 0, mat);
399 break;
401 createSegment();
402 motherVolume->AddNode(mSegment, 0, mat);
403 break;
405 createChip();
406 motherVolume->AddNode(mChip, 0, mat);
407 break;
409 createCarbonForm();
410 motherVolume->AddNode(mCarbonForm, 0, mat);
411 break;
413 [[fallthrough]];
414 default:
415 createLayerImpl();
416 motherVolume->AddNode(mLayer, 0, mat);
417 }
418 LOGP(info, "Partially built ITS3-{}-{}", mNLayer, getName(level));
419}
420
421} // namespace o2::its3
int32_t i
Definition of the ITS3Layer class.
Definition of the GeometryTGeo class.
useful math constants
std::ostringstream debug
static std::string_view getName(BuildLevel b)
Definition ITS3Layer.h:54
void createLayer(TGeoVolume *motherVolume)
Definition ITS3Layer.cxx:71
void buildPartial(TGeoVolume *motherVolume, TGeoMatrix *mat=nullptr, BuildLevel level=BuildLevel::kAll, bool createMaterials=false)
static const char * getITS3SegmentPattern(int layer)
static const char * getITS3ChipPattern()
static const char * getITS3TilePattern(int layer)
static const char * getITS3RSUPattern(int layer)
static const char * getITS3CarbonFormPattern(int layer)
static const char * getITS3PixelArrayPattern(int layer)
static const char * getITS3LayerPattern()
GLuint color
Definition glcorearb.h:1272
GLint GLsizei width
Definition glcorearb.h:270
GLuint GLsizei GLsizei * length
Definition glcorearb.h:790
constexpr float Deg2Rad
constexpr float Rad2Deg
constexpr float longeronsWidth
Definition SpecsV2.h:100
constexpr float edgeBetwChipAndFoam
Definition SpecsV2.h:103
constexpr std::array< int, 3 > nHoles
Definition SpecsV2.h:105
constexpr float length
Definition SpecsV2.h:74
constexpr unsigned int nRSUs
Definition SpecsV2.h:92
constexpr float length
Definition SpecsV2.h:62
constexpr std::array< unsigned int, nLayers > nSegments
Definition SpecsV2.h:113
constexpr std::array< float, nLayers > radiiOuter
Definition SpecsV2.h:118
constexpr float thickness
Definition SpecsV2.h:114
constexpr float equatorialGap
Definition SpecsV2.h:112
constexpr std::array< float, nLayers > radiiInner
Definition SpecsV2.h:117
constexpr std::array< float, nLayers > radii
Definition SpecsV2.h:116
GPUReconstruction * rec