Project
Loading...
Searching...
No Matches
Station2Geometry.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 "Materials.h"
18#include "Station2Geometry.h"
19
20#include <TGeoManager.h>
21#include <TGeoMedium.h>
22#include <TGeoShape.h>
23#include <TGeoPgon.h>
24#include <TGeoVolume.h>
25
26#include <iostream>
27#include <string>
28#include <array>
29
30namespace o2
31{
32namespace mch
33{
34
36
37// chamber z position
38const double kChamberZPos[2] = {-676.4, -695.4};
39
40// quadrant z position w.r.t the chamber center
41const double kQuadrantZPos = 3.9;
42
43// thickness
44const double kGasHalfThickness = 0.25;
45const double kCathodeHalfThickness = 0.005 / 2; // effective copper thickness in the PCB (to be checked !)
46const double kPCBHalfThickness = 0.04 / 2;
48const double kRohaHalfThickness = 2.5 / 2;
49const double kMEBHalfThickness = 0.04 / 2;
50const double kEERBHalfThickness = 0.04 / 2; // effective electronic readout board (seems to be a very big value, should be the same than for station 1, to be investigated)
51
52// polygon shape parameters
53const double kStartAngle = 0.;
54const double kStopAngle = 90.;
55const int kNPlanes = 2;
56const int kNEdges = 5;
57
59const int kNSegments = 3;
60
61const double kSegmentRadius[2] = {23.1, 117.6};
62
63// box segment dimensions
64const double kBoxSegHalfLength[kNSegments] = {95.5 / 2, 0., 0.5};
65const double kBoxSegHalfHeight[kNSegments] = {0.6, 0., 95.5 / 2};
66
68const int kNFrames = 8;
69const double kFrameHalfLength[kNFrames] = {101. / 2, 2., 0., 0.5, 2.7 / 2, 0.5, 0., 2.5 / 2};
70const double kFrameHalfHeight[kNFrames] = {2.5 / 2, 0.6, 0., 2., 101. / 2, 2.5 / 2, 0., 0.6};
71
72const double kRibHalfLength[kNFrames] = {
74 kFrameHalfLength[1] - 0.5,
75 0.,
77 0.8 / 2,
79 0.,
80 kFrameHalfLength[7] - 0.5};
81const double kRibHalfHeight[kNFrames] = {
82 0.3,
84 0.,
85 kFrameHalfHeight[3] - 0.5,
87 1.5 / 2,
88 0.,
90
91const double kFrame3Radius[2] = {kSegmentRadius[1], 121.6};
92const double kRib3Radius[2] = {kSegmentRadius[1], 120.6};
93
94const double kFrame7Radius[2] = {20.6, kSegmentRadius[0]};
95const double kRib7Radius[2] = {21.6, kSegmentRadius[0]};
96
97const double kEpoxyHalfThickness = 2.;
98const double kRibHalfThickness = 0.5;
99
100//______________________________________________________________________________
101TGeoVolume* createSegment(int i)
102{
103
107
108 const char* segmentName = Form("Segment %d", i);
109 auto segment = new TGeoVolumeAssembly(segmentName);
110
111 const int kNLayers = 6;
112
113 const std::string kLayerName[kNLayers] = {"gas", "cathode", "insulator", "rohacell", "MEB", "EERB"};
116
117 // volume dimensions
118 double halfLength = kBoxSegHalfLength[i], halfHeight = kBoxSegHalfHeight[i], halfThickness = kLayerHalfThickness[0];
119
120 double z = 0.; // increment this variable when adding a new layer
121
122 switch (i) {
123 case 1: // polygon
124
125 // parameters
126 double par[10];
127 par[0] = kStartAngle; // initial angle
128 par[1] = kStopAngle; // increment in angle starting from initial angle
129 par[2] = kNEdges; // number of edges
130 par[3] = kNPlanes; // number of planes
131 par[4] = -halfThickness; // z-position of the first plane
132 par[5] = kSegmentRadius[0]; // inner radius first plane
133 par[6] = kSegmentRadius[1]; // outer radius first plane
134 par[7] = halfThickness; // z-position of the second plane
135 par[8] = par[5]; // inner radius of second plane
136 par[9] = par[6]; // outer radius of second plane
137
138 // create and place the layers in the segment
139
140 segment->AddNode(new TGeoVolume(Form("%s %s", segmentName, kLayerName[0].data()), new TGeoPgon(par), kLayerMedium[0]), 1);
141
142 z = halfThickness;
143
144 for (int j = 1; j < kNLayers; j++) {
145
146 halfThickness = kLayerHalfThickness[j];
147
148 par[4] = -halfThickness;
149 par[7] = halfThickness;
150 auto layer = new TGeoVolume(Form("Segment %d %s", i, kLayerName[j].data()), new TGeoPgon(par), kLayerMedium[j]);
151
152 z += halfThickness;
153 segment->AddNode(layer, 1, new TGeoTranslation(0., 0., z));
154 segment->AddNode(layer, 2, new TGeoTranslation(0., 0., -z));
155 z += halfThickness;
156
157 } // end of the layer loop
158 break;
159
160 default: //box
161 // create and place the layers in the segment
162
163 // start with gas
164 halfThickness = kLayerHalfThickness[0];
165
166 segment->AddNode(gGeoManager->MakeBox(Form("%s %s", segmentName, kLayerName[0].data()), kLayerMedium[0], halfLength, halfHeight, halfThickness), 1);
167
168 z = halfThickness;
169
170 for (int j = 1; j < kNLayers; j++) {
171
172 halfThickness = kLayerHalfThickness[j];
173
174 auto layer = gGeoManager->MakeBox(Form("%s %s", segmentName, kLayerName[j].data()), kLayerMedium[j], halfLength, halfHeight, halfThickness);
175
176 z += halfThickness;
177 segment->AddNode(layer, 1, new TGeoTranslation(0., 0., z));
178 segment->AddNode(layer, 2, new TGeoTranslation(0., 0., -z));
179 z += halfThickness;
180
181 } // end of the layer loop
182
183 break;
184 } // end of the switch
185
186 return segment;
187}
188
189//______________________________________________________________________________
191{
192
193 // materials
194 const auto kFrameMed = assertMedium(Medium::Epoxy); // to be changed ? PEEK GF-30 in CERN-THESIS-2008-170
195 const auto kRibMed = assertMedium(Medium::Rohacell); // to be changed ? PEEK GF-30 in CERN-THESIS-2008-170
196
197 // rib position on the frame
198 const double kRibXPos[kNFrames] = {
199 0.,
200 -kFrameHalfLength[1] + kRibHalfLength[1], // left edge
201 0.,
202 0.,
203 kFrameHalfLength[4] - kRibHalfLength[4], // right edge
204 0.,
205 0.,
206 kFrameHalfLength[7] - kRibHalfLength[7] // right edge
207 };
208
209 const double kRibYPos[kNFrames] = {
210 kFrameHalfHeight[0] - kRibHalfHeight[0], // upper edge
211 0.,
212 0.,
213 -kFrameHalfHeight[3] + kRibHalfHeight[3], // lower edge
214 0.,
215 kFrameHalfHeight[5] - kRibHalfHeight[5], // upper edge
216 0.,
217 0.};
218
219 // useful variables
220 double halfThickness = 0., z = 0.;
221
222 for (int i = 1; i <= kNFrames; i++) {
223
224 // in this loop, we only create box frames
225 if (i == 3 || i == 7) {
226 continue; // go to next frame
227 }
228
229 // create the frame
230 auto frame = new TGeoVolumeAssembly(Form("Frame %d", i));
231
232 // create the epoxy
233 halfThickness = kEpoxyHalfThickness;
234 frame->AddNode(gGeoManager->MakeBox(Form("Epoxy %d", i), kFrameMed, kFrameHalfLength[i - 1], kFrameHalfHeight[i - 1], halfThickness), 1);
235 z = halfThickness;
236
237 // create the rib
238 halfThickness = kRibHalfThickness;
239 auto rib = gGeoManager->MakeBox(Form("Rib %d", i), kRibMed, kRibHalfLength[i - 1], kRibHalfHeight[i - 1], halfThickness);
240
241 z += halfThickness;
242 frame->AddNode(rib, 1, new TGeoTranslation(kRibXPos[i - 1], kRibYPos[i - 1], z));
243 frame->AddNode(rib, 2, new TGeoTranslation(kRibXPos[i - 1], kRibYPos[i - 1], -z));
244 }
245
247
248 // parameters
249 double par[10];
250 par[0] = kStartAngle;
251 par[1] = kStopAngle;
252 par[2] = kNEdges;
253 par[3] = kNPlanes;
254
255 // Frame 3
256 auto frame3 = new TGeoVolumeAssembly("Frame 3");
257
258 // epoxy layer
259 halfThickness = kEpoxyHalfThickness;
260 z = 0.;
261
262 par[4] = -halfThickness;
263 par[5] = kFrame3Radius[0];
264 par[6] = kFrame3Radius[1];
265 par[7] = halfThickness;
266 par[8] = par[5];
267 par[9] = par[6];
268
269 frame3->AddNode(new TGeoVolume("Epoxy 3", new TGeoPgon(par), kFrameMed), 1);
270 z += halfThickness;
271
272 // rib
273 halfThickness = kRibHalfThickness;
274 par[4] = -halfThickness;
275 par[5] = kRib3Radius[0];
276 par[6] = kRib3Radius[1];
277 par[7] = halfThickness;
278 par[8] = par[5];
279 par[9] = par[6];
280
281 auto rib3 = new TGeoVolume("Rib 3", new TGeoPgon(par), kRibMed);
282
283 z += halfThickness;
284 frame3->AddNode(rib3, 1, new TGeoTranslation(0., 0., z));
285 frame3->AddNode(rib3, 2, new TGeoTranslation(0., 0., -z));
286
287 // Frame 7
288 auto frame7 = new TGeoVolumeAssembly("Frame 7");
289
290 // epoxy layer
291 halfThickness = kEpoxyHalfThickness;
292 z = 0.;
293
294 par[4] = -halfThickness;
295 par[5] = kFrame7Radius[0];
296 par[6] = kFrame7Radius[1];
297 par[7] = halfThickness;
298 par[8] = par[5];
299 par[9] = par[6];
300 frame3->AddNode(new TGeoVolume("Epoxy 7", new TGeoPgon(par), kFrameMed), 1);
301 z += halfThickness;
302
303 // rib
304 halfThickness = kRibHalfThickness;
305 par[4] = -halfThickness;
306 par[5] = kRib7Radius[0];
307 par[6] = kRib7Radius[1];
308 par[7] = halfThickness;
309 par[8] = par[5];
310 par[9] = par[6];
311
312 auto rib7 = new TGeoVolume("Rib 7", new TGeoPgon(par), kRibMed);
313
314 z += halfThickness;
315 frame7->AddNode(rib7, 1, new TGeoTranslation(0., 0., z));
316 frame7->AddNode(rib7, 2, new TGeoTranslation(0., 0., -z));
317}
318
319//______________________________________________________________________________
320TGeoVolume* createQuadrant()
321{
322
324 auto quadrant = new TGeoVolumeAssembly("Station 2 quadrant");
325
326 // create and place the segments in the quadrant
327 const double kSegXPos[kNSegments] = {kSegmentRadius[0] + kBoxSegHalfLength[0], 0., -kBoxSegHalfLength[2]};
328 const double kSegYPos[kNSegments] = {-kBoxSegHalfHeight[0], 0., kSegmentRadius[0] + kBoxSegHalfHeight[2]};
329
330 for (int i = 0; i < kNSegments; i++) {
331 quadrant->AddNode(createSegment(i), 0, new TGeoTranslation(kSegXPos[i], kSegYPos[i], 0.));
332 }
333
334 // create and place the frames in the quadrant
335 createFrames();
336
337 // positions
338 const double kFrameXPos[kNFrames] = {
339 kSegXPos[0], // frame n°1 aligned with the segment 0
340 kSegXPos[0] + kBoxSegHalfLength[0] + kFrameHalfLength[2 - 1], // frame n°2 at the right of the segment 0
341 0.,
342 kSegXPos[2], // frame n°4 aligned with the segment 2
343 kSegXPos[2] - kBoxSegHalfLength[2] - kFrameHalfLength[5 - 1], // frame n°5 at the left of the segment 2
344 kSegXPos[2], // frame n°6 aligned with the segment 2
345 0.,
346 kSegXPos[0] - kBoxSegHalfLength[0] - kFrameHalfLength[8 - 1], // frame n°8 at the left of the segment 0
347 };
348
349 const double kFrameYPos[kNFrames] = {
350 kSegYPos[0] - kBoxSegHalfHeight[0] - kFrameHalfHeight[1 - 1], // frame n°1 below the segment 0
351 kSegYPos[0], // frame n°2 aligned with the segment 0
352 0.,
353 kSegYPos[2] + kBoxSegHalfHeight[2] + kFrameHalfHeight[4 - 1], // frame n°4 above the segment 2
354 kSegYPos[2], // frame n°5 aligned with the segment 2
355 kSegYPos[2] - kBoxSegHalfHeight[2] - kFrameHalfHeight[6 - 1], // frame n°6 below the segment 2
356 0.,
357 kSegYPos[0], // frame n°8 aligned with the segment 0
358 };
359
360 for (int i = 1; i <= kNFrames; i++) {
361 quadrant->AddNode(gGeoManager->GetVolume(Form("Frame %d", i)), 1,
362 new TGeoTranslation(kFrameXPos[i - 1], kFrameYPos[i - 1], 0.));
363 }
364
365 return quadrant;
366}
367
368//______________________________________________________________________________
369void createStation2Geometry(TGeoVolume& topVolume)
370{
372
373 // create a quadrant
374 auto quadrant = createQuadrant();
375
376 const int kNQuad = 4;
377
378 // rotation matrices to place the quadrants in the half-chambers
379 auto rot0 = new TGeoRotation();
380 auto rot1 = new TGeoRotation("reflXZ", 90., 180., 90., 90., 180., 0.);
381 auto rot2 = new TGeoRotation("reflXY", 90., 180., 90., 270., 0., 0.);
382 auto rot3 = new TGeoRotation("reflYZ", 90., 0., 90., -90., 180., 0.);
383 std::array<TGeoRotation*, kNQuad> rot = {rot0, rot1, rot2, rot3};
384
385 // build the two chambers
386 double z = kQuadrantZPos;
387 int detElemID = 0;
388 const int kFirstChamberNumber = 3;
389
390 for (int ich = kFirstChamberNumber; ich < kFirstChamberNumber + 2; ich++) {
391
392 // create two half-chambers
393 auto in = new TGeoVolumeAssembly(Form("SC0%dI", ich));
394 auto out = new TGeoVolumeAssembly(Form("SC0%dO", ich));
395
396 // place the quadrants in the half-chambers
397 for (int i = 0; i < kNQuad; i++) {
398 // alternate the z position
399 z *= -1.;
400
401 // compute the detection element ID
402 detElemID = 100 * ich + i;
403
404 if (i == 0 || i == 3) {
405 in->AddNode(quadrant, detElemID, new TGeoCombiTrans(0., 0., z, rot[i]));
406 } else {
407 out->AddNode(quadrant, detElemID, new TGeoCombiTrans(0., 0., z, rot[i]));
408 }
409 }
410
411 // place the half-chambers in the top volume
412 topVolume.AddNode(in, 2 * (ich - 1), new TGeoTranslation(0., 0., kChamberZPos[ich - kFirstChamberNumber]));
413 topVolume.AddNode(out, 2 * ich - 1, new TGeoTranslation(0., 0., kChamberZPos[ich - kFirstChamberNumber]));
414
415 } // end of the chamber loop
416}
417
418//______________________________________________________________________________
419std::vector<TGeoVolume*> getStation2SensitiveVolumes()
420{
422
423 std::vector<TGeoVolume*> sensitiveVolumeNames;
424 for (int i = 0; i < kNSegments; i++) {
425
426 auto vol = gGeoManager->GetVolume(Form("Segment %d gas", i));
427
428 if (!vol) {
429 throw std::runtime_error(Form("could not get expected volume : Segment %d gas", i));
430 } else {
431 sensitiveVolumeNames.push_back(vol);
432 }
433 }
434
435 return sensitiveVolumeNames;
436}
437
438} // namespace mch
439} // namespace o2
int32_t i
Implementation of the MID materials definitions.
uint32_t j
Definition RawData.h:0
Implementation of the station 2 geometry.
GLuint segment
Definition glcorearb.h:4945
GLboolean * data
Definition glcorearb.h:298
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
const double kRib7Radius[2]
const double kFrameHalfHeight[kNFrames]
const int kNEdges
const int kNFrames
Frames.
void createFrames()
const double kGasHalfThickness
const double kRibHalfHeight[kNFrames]
const double kPCBHalfThickness
void createStation2Geometry(TGeoVolume &topVolume)
TGeoMedium * assertMedium(int imed)
const double kMEBHalfThickness
const double kFrame7Radius[2]
const double kBoxSegHalfLength[kNSegments]
std::vector< TGeoVolume * > getStation2SensitiveVolumes()
const double kStartAngle
const double kInsuHalfThickness
const int kNPlanes
TGeoVolume * createQuadrant()
const double kStopAngle
const double kRibHalfLength[kNFrames]
const double kEpoxyHalfThickness
const double kFrame3Radius[2]
const double kFrameHalfLength[kNFrames]
const double kBoxSegHalfHeight[kNSegments]
const double kRibHalfThickness
const float kChamberZPos[2]
Constants.
@ Rohacell
Definition Materials.h:33
const double kSegmentRadius[2]
const double kRohaHalfThickness
TGeoVolume * createSegment(int i)
const double kCathodeHalfThickness
const double kEERBHalfThickness
const int kNSegments
Segments.
const float kQuadrantZPos
const double kRib3Radius[2]
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...