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