Project
Loading...
Searching...
No Matches
Detector.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
12#include <algorithm>
13#include <iomanip>
14#include <map>
15
16#include "TGeoManager.h"
17#include "TGeoVolume.h"
18#include "TVirtualMC.h"
19#include "TGeoPhysicalNode.h"
20
21#include "FairGeoNode.h"
22#include "FairRootManager.h"
23#include "FairVolume.h"
24
25#include "CPVBase/Geometry.h"
26#include "DataFormatsCPV/Hit.h"
30
32#include "DetectorsBase/Stack.h"
33
34#include <boost/algorithm/string/predicate.hpp>
35#include <boost/range/irange.hpp>
36
37using namespace o2::cpv;
38
40
42 : o2::base::DetImpl<Detector>("CPV", active),
43 mHits(o2::utils::createSimVector<o2::cpv::Hit>())
44{
45}
46
48 : o2::base::DetImpl<Detector>(rhs),
49 mHits(o2::utils::createSimVector<o2::cpv::Hit>())
50{
51}
52
57
59{
60 Reset();
61
62 // Define sensitive volumes
63 defineSensitiveVolumes();
64}
65
67{
68 Reset();
69}
71{
72 // Sort Hits
73 // Add duplicates if any and remove them
74
75 if (!mHits || mHits->size() == 0) {
76 return;
77 }
78
79 auto first = mHits->begin();
80 auto last = mHits->end();
81
82 std::sort(first, last);
83
84 first = mHits->begin();
85 last = mHits->end();
86
87 // this is copy of std::unique() method with addition: adding identical Hits
88 auto itr = first;
89 while (++first != last) {
90 if (*itr == *first) {
91 *itr += *first;
92 } else {
93 *(++itr) = *first;
94 }
95 }
96 ++itr;
97
98 mHits->erase(itr, mHits->end());
99
100 // printf("hits: %d \n",mHits->size()) ;
101 // int c=0;
102 // for(const Hit &h : *mHits){ if(h.GetDetectorID()<c){printf("Ht %d < %d\n",h.GetDetectorID(),c) ;} c=h.GetDetectorID() ;}
103}
105{
106 if (!o2::utils::ShmManager::Instance().isOperational()) {
107 mHits->clear();
108 }
109}
110
111void Detector::Register() { FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE); }
112
113Bool_t Detector::ProcessHits(FairVolume* v)
114{
115 // ------------------------------------------------------------------------
116 // Digitize one CPV hit:
117 // use exact 4-momentum p and position zxhit of the hit,
118 // find the pad response around this hit and
119 // put the amplitudes in the pads into array digits
120 //
121 // Author: Yuri Kharlov (after Serguei Sadovsky)
122 // 2 October 2000
123 // ported from AliRoot 2019
124 // ------------------------------------------------------------------------
125
126 // analyze only charged
127 if (fMC->TrackCharge() == 0) {
128 fMC->SetMaxStep(1.e10);
129 return false;
130 }
131
132 if (!fMC->IsTrackEntering()) { // simulate once per track
133 return false;
134 }
135
136 int moduleNumber;
137 fMC->CurrentVolOffID(2, moduleNumber);
138
139 double time = fMC->TrackTime() * 1.e+9; // time in ns?? To be consistent with PHOS/EMCAL
140
141 float xyzm[3], xyzd[3];
142 fMC->TrackPosition(xyzm[0], xyzm[1], xyzm[2]);
143
144 fMC->Gmtod(xyzm, xyzd, 1); // transform coordinate from master to daughter system
145
146 // Current momentum of the hit's track in the local ref. system
147 float pm[3], pd[3], energy = 0.;
148 fMC->TrackMomentum(pm[0], pm[1], pm[2], energy);
149 fMC->Gmtod(pm, pd, 2); // transform 3-momentum from master to daughter system
150
151 // Just a reminder on axes notation in the CPV module:
152 // axis Z goes along the beam
153 // axis X goes across the beam in the module plane
154 // axis Y is a normal to the module plane showing from the IP
155
156 auto& cpvparam = o2::cpv::CPVSimParams::Instance();
157 // Digitize the current CPV hit:
158 // find pad response
159 float hitX = xyzd[0]; // hit coordinate in daugter frame
160 float hitZ = xyzd[2]; // z-coordinate of track in daugter frame
161 float pX = pd[0];
162 float pZ = pd[2];
163 float pNorm = -pd[1];
164 float dZY = pZ / pNorm * cpvparam.mCPVGasThickness;
165 float dXY = pX / pNorm * cpvparam.mCPVGasThickness;
166 float rnor1 = 0., rnor2 = 0.;
167 gRandom->Rannor(rnor1, rnor2);
168 float eloss = cpvparam.mdEdx * (1 + cpvparam.mDetR * rnor1) *
169 TMath::Sqrt((1. + (pow(dZY, 2) + pow(dXY, 2)) / pow(cpvparam.mCPVGasThickness, 2)));
170 float zhit1 = hitZ + cpvparam.mPadSizeZ * cpvparam.mnCellZ / 2 - dZY / 2;
171 float xhit1 = hitX + cpvparam.mPadSizeX * cpvparam.mnCellX / 2 - dXY / 2;
172 float zhit2 = zhit1 + dZY;
173 float xhit2 = xhit1 + dXY;
174
175 int iwht1 = (int)(xhit1 / cpvparam.CellWr()); // wire (x) coordinate "in"
176 int iwht2 = (int)(xhit2 / cpvparam.CellWr()); // wire (x) coordinate "out"
177
178 int nIter;
179 float zxe[3][5];
180 if (iwht1 == iwht2) { // incline 1-wire hit
181 nIter = 2;
182 zxe[0][0] = (zhit1 + zhit2 - dZY * 0.57735) / 2;
183 zxe[1][0] = (iwht1 + 0.5) * cpvparam.CellWr();
184 zxe[2][0] = eloss / 2;
185 zxe[0][1] = (zhit1 + zhit2 + dZY * 0.57735) / 2;
186 zxe[1][1] = (iwht1 + 0.5) * cpvparam.CellWr();
187 zxe[2][1] = eloss / 2;
188 } else if (TMath::Abs(iwht1 - iwht2) != 1) { // incline 3-wire hit
189 nIter = 3;
190 int iwht3 = (iwht1 + iwht2) / 2;
191 float xwht1 = (iwht1 + 0.5) * cpvparam.CellWr(); // wire 1
192 float xwht2 = (iwht2 + 0.5) * cpvparam.CellWr(); // wire 2
193 float xwht3 = (iwht3 + 0.5) * cpvparam.CellWr(); // wire 3
194 float xwr13 = (xwht1 + xwht3) / 2; // center 13
195 float xwr23 = (xwht2 + xwht3) / 2; // center 23
196 float dxw1 = xhit1 - xwr13;
197 float dxw2 = xhit2 - xwr23;
198 float egm1 = TMath::Abs(dxw1) / (TMath::Abs(dxw1) + TMath::Abs(dxw2) + cpvparam.CellWr());
199 float egm2 = TMath::Abs(dxw2) / (TMath::Abs(dxw1) + TMath::Abs(dxw2) + cpvparam.CellWr());
200 float egm3 = cpvparam.CellWr() / (TMath::Abs(dxw1) + TMath::Abs(dxw2) + cpvparam.CellWr());
201 zxe[0][0] = (dXY * (xwr13 - xwht1) / dXY + zhit1 + zhit1) / 2;
202 zxe[1][0] = xwht1;
203 zxe[2][0] = eloss * egm1;
204 zxe[0][1] = (dXY * (xwr23 - xwht1) / dXY + zhit1 + zhit2) / 2;
205 zxe[1][1] = xwht2;
206 zxe[2][1] = eloss * egm2;
207 zxe[0][2] = dXY * (xwht3 - xwht1) / dXY + zhit1;
208 zxe[1][2] = xwht3;
209 zxe[2][2] = eloss * egm3;
210 } else { // incline 2-wire hit
211 nIter = 2;
212 float xwht1 = (iwht1 + 0.5) * cpvparam.CellWr();
213 float xwht2 = (iwht2 + 0.5) * cpvparam.CellWr();
214 float xwr12 = (xwht1 + xwht2) / 2;
215 float dxw1 = xhit1 - xwr12;
216 float dxw2 = xhit2 - xwr12;
217 float egm1 = TMath::Abs(dxw1) / (TMath::Abs(dxw1) + TMath::Abs(dxw2));
218 float egm2 = TMath::Abs(dxw2) / (TMath::Abs(dxw1) + TMath::Abs(dxw2));
219 zxe[0][0] = (zhit1 + zhit2 - dZY * egm1) / 2;
220 zxe[1][0] = xwht1;
221 zxe[2][0] = eloss * egm1;
222 zxe[0][1] = (zhit1 + zhit2 + dZY * egm2) / 2;
223 zxe[1][1] = xwht2;
224 zxe[2][1] = eloss * egm2;
225 }
226
227 // Finite size of ionization region
228
229 int nz3 = (cpvparam.mNgamz + 1) / 2;
230 int nx3 = (cpvparam.mNgamx + 1) / 2;
231
232 o2::data::Stack* stack = static_cast<o2::data::Stack*>(fMC->GetStack());
233 stack->addHit(GetDetId());
234 const int partID = stack->GetCurrentTrackNumber();
235
236 for (int iter = 0; iter < nIter; iter++) {
237
238 float zhit = zxe[0][iter];
239 float xhit = zxe[1][iter];
240 float qhit = zxe[2][iter];
241 float zcell = zhit / cpvparam.mPadSizeZ;
242 float xcell = xhit / cpvparam.mPadSizeX;
243 if (zcell <= 0 || xcell <= 0 ||
244 zcell >= cpvparam.mnCellZ || xcell >= cpvparam.mnCellX) {
245 return true; // beyond CPV
246 }
247 int izcell = (int)zcell;
248 int ixcell = (int)xcell;
249 float zc = zcell - izcell - 0.5;
250 float xc = xcell - ixcell - 0.5;
251 for (int iz = 0; iz < cpvparam.mNgamz; iz++) {
252 int kzg = izcell + iz - nz3;
253 if (kzg < 0 || kzg >= cpvparam.mnCellZ) {
254 continue;
255 }
256 float zg = (float)(iz - nz3) - zc;
257 for (int ix = 0; ix < cpvparam.mNgamx; ix++) {
258 int kxg = ixcell + ix - nx3;
259 if (kxg < 0 || kxg >= cpvparam.mnCellX) {
260 continue;
261 }
262 float xg = (float)(ix - nx3) - xc;
263
264 // Now calculate pad response
265 double qpad = padResponseFunction(qhit, zg, xg);
266 if (qpad < 0) {
267 continue;
268 }
269 // Fill hit with pad response ID and amplitude
270 // hist will be sorted and merged later if necessary
271 int detID = Geometry::relToAbsId(moduleNumber, kxg, kzg);
272 addHit(partID, detID, math_utils::Point3D<float>(xyzm[0], xyzm[1], xyzm[2]), time, qpad);
273 }
274 }
275 }
276 return true;
277}
278
279float Detector::padResponseFunction(float qhit, float zhit, float xhit)
280{
281 // ------------------------------------------------------------------------
282 // Calculate the amplitude in one CPV pad using the
283 // cumulative pad response function
284 // Author: Yuri Kharlov (after Serguei Sadovski)
285 // 3 October 2000
286 // ------------------------------------------------------------------------
287
288 auto& cpvparam = o2::cpv::CPVSimParams::Instance();
289 float dz = cpvparam.mPadSizeZ / 2;
290 float dx = cpvparam.mPadSizeX / 2;
291 float z = zhit * cpvparam.mPadSizeZ;
292 float x = xhit * cpvparam.mPadSizeX;
293 float amplitude = qhit *
294 (CPVCumulPadResponse(z + dz, x + dx) - CPVCumulPadResponse(z + dz, x - dx) -
295 CPVCumulPadResponse(z - dz, x + dx) + CPVCumulPadResponse(z - dz, x - dx));
296 return amplitude;
297}
298
300{
301 // ------------------------------------------------------------------------
302 // Cumulative pad response function
303 // It includes several terms from the CF decomposition in electrostatics
304 // Note: this cumulative function is wrong since omits some terms
305 // but the cell amplitude obtained with it is correct because
306 // these omitting terms cancel
307 // Author: Yuri Kharlov (after Serguei Sadovski)
308 // 3 October 2000
309 // ------------------------------------------------------------------------
310
311 auto& cpvparam = o2::cpv::CPVSimParams::Instance();
312 float r2 = x * x + y * y;
313 float xy = x * y;
314 float cumulPRF = 0;
315 for (Int_t i = 0; i <= 4; i++) {
316 float b1 = (2 * i + 1) * cpvparam.mB;
317 cumulPRF += TMath::Power(-1, i) * TMath::ATan(xy / (b1 * TMath::Sqrt(b1 * b1 + r2)));
318 }
319 cumulPRF *= cpvparam.mA / (2 * TMath::Pi());
320 return cumulPRF;
321}
322
323void Detector::addHit(int trackID, short detID, const math_utils::Point3D<float>& pos, double time, float qdep)
324{
325 LOG(debug) << "Adding hit for track " << trackID << " in a pad " << detID << " with position (" << pos.X() << ", "
326 << pos.Y() << ", " << pos.Z() << "), time" << time << ", qdep =" << qdep << std::endl;
327 mHits->emplace_back(trackID, detID, pos, time, qdep);
328 // register hit creation with MCStack
329 static_cast<o2::data::Stack*>(fMC->GetStack())->addHit(GetDetId());
330}
331
333{
334 // Create geometry description of CPV depector for Geant simulations.
335
336 using boost::algorithm::contains;
337
338 cpv::GeometryParams* geomParams = cpv::GeometryParams::GetInstance("CPVRun3Params");
339
340 if (!geomParams) {
341 LOG(error) << "ConstructGeometry: CPV Geometry class has not been set up.\n";
342 }
343
344 if (!fMC) {
345 fMC = TVirtualMC::GetMC();
346 }
347
348 // Configure geometry So far we have only one: Run3
349 {
350 mActiveModule[0] = kFALSE;
351 mActiveModule[1] = kFALSE;
352 mActiveModule[2] = kTRUE;
353 mActiveModule[3] = kTRUE;
354 mActiveModule[4] = kTRUE;
355 }
356
357 // First create necessary materials
359
360 // Create a CPV modules-containers which will be filled with the stuff later.
361 double par[3], x, y, z;
362
363 // The box containing all CPV filled with air
364 par[0] = geomParams->GetCPVBoxSize(0) / 2.0;
365 par[1] = geomParams->GetCPVBoxSize(1) / 2.0;
366 par[2] = geomParams->GetCPVBoxSize(2) / 2.0;
367 fMC->Gsvolu("CPV", "BOX ", getMediumID(ID_AIR), par, 3);
368
369 // --- Position CPV modules in ALICE setup ---
370 int idrotm[5];
371 for (int iModule = 0; iModule < 5; iModule++) {
372 if (!mActiveModule[iModule]) {
373 continue;
374 }
375 double angle[3][2] = {0};
376 geomParams->GetModuleAngle(iModule, angle);
377 Matrix(idrotm[iModule], angle[0][0], angle[0][1], angle[1][0], angle[1][1], angle[2][0], angle[2][1]);
378
379 double pos[3] = {0};
380 geomParams->GetModuleCenter(iModule, pos);
381
382 fMC->Gspos("CPV", iModule, "barrel", pos[0], pos[1] + 30., pos[2], idrotm[iModule], "ONLY");
383 }
384
385 // start filling CPV moodules
386 // Gassiplex board
387 par[0] = geomParams->GetGassiplexChipSize(0) / 2.;
388 par[1] = geomParams->GetGassiplexChipSize(1) / 2.;
389 par[2] = geomParams->GetGassiplexChipSize(2) / 2.;
390 fMC->Gsvolu("CPVG", "BOX ", getMediumID(ID_TEXTOLIT), par, 3);
391
392 // Cu+Ni foil covers Gassiplex board
393 par[1] = geomParams->GetCPVCuNiFoilThickness() / 2;
394 fMC->Gsvolu("CPVC", "BOX ", getMediumID(ID_CU), par, 3);
395 y = -(geomParams->GetGassiplexChipSize(1) / 2 - par[1]);
396 fMC->Gspos("CPVC", 1, "CPVG", 0, y, 0, 0, "ONLY");
397
398 // Position of the chip inside CPV
399 double xStep = geomParams->GetCPVActiveSize(0) / (geomParams->GetNumberOfCPVChipsPhi() + 1);
400 double zStep = geomParams->GetCPVActiveSize(1) / (geomParams->GetNumberOfCPVChipsZ() + 1);
401 int copy = 0;
402 y = geomParams->GetCPVFrameSize(1) / 2 - geomParams->GetFTPosition(0) +
403 geomParams->GetCPVTextoliteThickness() / 2 + geomParams->GetGassiplexChipSize(1) / 2 + 0.1;
404 for (int ix = 0; ix < geomParams->GetNumberOfCPVChipsPhi(); ix++) {
405 x = xStep * (ix + 1) - geomParams->GetCPVActiveSize(0) / 2;
406 for (int iz = 0; iz < geomParams->GetNumberOfCPVChipsZ(); iz++) {
407 copy++;
408 z = zStep * (iz + 1) - geomParams->GetCPVActiveSize(1) / 2;
409 fMC->Gspos("CPVG", copy, "CPV", x, y, z, 0, "ONLY");
410 }
411 }
412
413 // Foiled textolite (1 mm of textolite + 50 mkm of Cu + 6 mkm of Ni)
414 par[0] = geomParams->GetCPVActiveSize(0) / 2;
415 par[1] = geomParams->GetCPVTextoliteThickness() / 2;
416 par[2] = geomParams->GetCPVActiveSize(1) / 2;
417 fMC->Gsvolu("CPVF", "BOX ", getMediumID(ID_TEXTOLIT), par, 3);
418
419 // Argon gas volume
420 par[1] = (geomParams->GetFTPosition(2) - geomParams->GetFTPosition(1) - geomParams->GetCPVTextoliteThickness()) / 2;
421 fMC->Gsvolu("CPVAr", "BOX ", getMediumID(ID_AR), par, 3);
422
423 for (int i = 0; i < 4; i++) {
424 y = geomParams->GetCPVFrameSize(1) / 2 - geomParams->GetFTPosition(i) + geomParams->GetCPVTextoliteThickness() / 2;
425 fMC->Gspos("CPVF", i + 1, "CPV", 0, y, 0, 0, "ONLY");
426 if (i == 1) {
427 y -= (geomParams->GetFTPosition(2) - geomParams->GetFTPosition(1)) / 2;
428 fMC->Gspos("CPVAr", 1, "CPV ", 0, y, 0, 0, "ONLY");
429 }
430 }
431
432 // Dummy sensitive plane in the middle of argone gas volume
433 par[1] = 0.001;
434 fMC->Gsvolu("CPVQ", "BOX ", getMediumID(ID_AR), par, 3);
435 fMC->Gspos("CPVQ", 1, "CPVAr", 0, 0, 0, 0, "ONLY");
436
437 // Cu+Ni foil covers textolite
438 par[1] = geomParams->GetCPVCuNiFoilThickness() / 2;
439 fMC->Gsvolu("CPVP1", "BOX ", getMediumID(ID_CU), par, 3);
440 y = geomParams->GetCPVTextoliteThickness() / 2 - par[1];
441 fMC->Gspos("CPVP1", 1, "CPVF", 0, y, 0, 0, "ONLY");
442
443 // Aluminum frame around CPV
444 par[0] = geomParams->GetCPVFrameSize(0) / 2;
445 par[1] = geomParams->GetCPVFrameSize(1) / 2;
446 par[2] = geomParams->GetCPVBoxSize(2) / 2;
447 fMC->Gsvolu("CPVF1", "BOX ", getMediumID(ID_AL), par, 3);
448
449 par[0] = geomParams->GetCPVBoxSize(0) / 2 - geomParams->GetCPVFrameSize(0);
450 par[1] = geomParams->GetCPVFrameSize(1) / 2;
451 par[2] = geomParams->GetCPVFrameSize(2) / 2;
452 fMC->Gsvolu("CPVF2", "BOX ", getMediumID(ID_AL), par, 3);
453
454 // The frame's inner faces are the edges of the active plane. Deriving them from the box and
455 // frame sizes instead of from the active size left CPVF2 38 nm away from CPVF and CPVAr:
456 // algebraically the same plane, different float sums. TGeo relocates from a point pushed far
457 // past a boundary and never notices; VecGeom answers DistanceToOut = -1 and gives the volume
458 // back to its mother. Place the frame against the halves the active volumes were actually
459 // given, so the faces land on the same double.
460 const double activeHalfX = geomParams->GetCPVActiveSize(0) / 2;
461 const double activeHalfZ = geomParams->GetCPVActiveSize(1) / 2;
462 const double frameHalfX = geomParams->GetCPVFrameSize(0) / 2;
463 const double frameHalfZ = geomParams->GetCPVFrameSize(2) / 2;
464 for (int j = 0; j <= 1; j++) {
465 x = TMath::Sign(1, 2 * j - 1) * (activeHalfX + frameHalfX);
466 fMC->Gspos("CPVF1", j + 1, "CPV", x, 0, 0, 0, "ONLY");
467 z = TMath::Sign(1, 2 * j - 1) * (activeHalfZ + frameHalfZ);
468 fMC->Gspos("CPVF2", j + 1, "CPV", 0, 0, z, 0, "ONLY");
469 }
470
471 gGeoManager->CheckGeometry();
472}
473//-----------------------------------------
475{
476 // Definitions of materials to build CPV and associated tracking media.
477
478 int isxfld = 2;
479 float sxmgmx = 10.0;
481
482 // --- Air ---
483 float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
484 float zAir[4] = {6., 7., 8., 18.};
485 float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827};
486 float dAir = 1.20479E-3;
487
488 Mixture(ID_AIR, "Air", aAir, zAir, dAir, 4, wAir);
489 Medium(ID_AIR, "Air", ID_AIR, 0, isxfld, sxmgmx, 10.0, 1.0, 0.1, 0.1, 10.0, nullptr, 0);
490
491 // The Textolit which makes up the box which contains the calorimeter module -> idtmed[707]
492 float aTX[4] = {16.0, 28.09, 12.011, 1.00794};
493 float zTX[4] = {8.0, 14.0, 6.0, 1.0};
494 float wTX[4] = {292.0, 68.0, 462.0, 736.0};
495 float dTX = 1.75;
496
497 Mixture(ID_TEXTOLIT, "Textolit", aTX, zTX, dTX, -4, wTX);
498 Medium(ID_TEXTOLIT, "Textolit", ID_TEXTOLIT, 0, isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
499
500 // Copper -> idtmed[710]
501 Material(ID_CU, "Cupr", 63.546, 29, 8.96, 1.43, 14.8, nullptr, 0);
502 Medium(ID_CU, "Cupr", ID_CU, 0, isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.0001, nullptr, 0);
503
504 // The gas mixture: ArCo2 -> idtmed[715]
505 // Ar+CO2 Mixture (80% / 20%)
506 // --- The gas mixture ---
507 // Co2
508 // float aCO[2] = {12.0, 16.0} ;
509 // float zCO[2] = {6.0, 8.0} ;
510 // float wCO[2] = {1.0, 2.0} ;
511 float dCO = 0.001977; // Co2 density
512 float dAr = 0.001782; // Argon density
513
514 float arContent = 0.80; // Ar-content of the ArCO2-mixture
515 float aArCO[3] = {39.948, 12.0, 16.0};
516 float zArCO[3] = {18.0, 6.0, 8.0};
517 float wArCO[3];
518 wArCO[0] = arContent;
519 wArCO[1] = (1 - arContent) * 1;
520 wArCO[2] = (1 - arContent) * 2;
521 float dArCO = arContent * dAr + (1 - arContent) * dCO;
522 Mixture(ID_AR, "ArCo2", aArCO, zArCO, dArCO, -3, wArCO);
523 Medium(ID_AR, "ArCo2", ID_AR, 1, isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.01, nullptr, 0);
524
525 // Various Aluminium parts made of Al -> idtmed[701]
526 Material(ID_AL, "Al", 26.98, 13., 2.7, 8.9, 999., nullptr, 0);
527 Medium(ID_AL, "Alparts", ID_AL, 0, isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.001, 0.001, nullptr, 0);
528
529 // --- Stainless steel (let it be pure iron) ---
530 Material(ID_FE, "Steel", 55.845, 26, 7.87, 1.76, 0., nullptr, 0);
531 Medium(ID_FE, "Steel", ID_FE, 0, isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.0001, nullptr, 0);
532
533 // Fibergalss -> getMediumID(ID_FIBERGLASS)
534 // Medium(ID_FIBERGLASS, "Fiberglass", ID_FIBERGLASS, 0, isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, nullptr, 0);
535
536 // The scintillator of the CPV made of Polystyrene scintillator -> idtmed[700]
537 // Medium(ID_SC, "CPVscint", ID_SC, 1, isxfld, sxmgmx, 10.0, 0.1, 0.1, 0.1, 0.1, 0, 0) ;
538}
539
540//-----------------------------------------
541void Detector::defineSensitiveVolumes()
542{
543 if (fActive) {
544 TGeoVolume* vsense = gGeoManager->GetVolume("CPVQ");
545 if (vsense) {
546 AddSensitiveVolume(vsense);
547 } else {
548 LOG(error) << "CPV Sensitive volume CPVQ not found ... No hit creation!\n";
549 }
550 }
551}
552//-----------------------------------------
554{
555 //
556 // Create entries for alignable volumes associating the symbolic volume
557 // name with the corresponding volume path.
558
560
561 // Alignable modules
562 // Volume path /cave_1/CPV_<i> => symbolic name /CPV/Module<i>, <i>=1,2,3,4,5
563
564 o2::detectors::DetID::ID idCPV = o2::detectors::DetID::CPV;
565
566 TString physModulePath = "/cave_1/barrel_1/CPV_";
567
568 TString symbModuleName = "CPV/Module";
569
570 for (Int_t iModule = 0; iModule < geom->GetNModules(); iModule++) {
571
572 if (!mActiveModule[iModule]) {
573 continue;
574 }
575 TString volPath(physModulePath);
576 volPath += iModule;
577
578 TString symName(symbModuleName);
579 symName += iModule;
580
581 int modUID = o2::base::GeometryManager::getSensID(idCPV, iModule);
582
583 LOG(debug) << "--------------------------------------------"
584 << "\n";
585 LOG(debug) << "Alignable object" << iModule << "\n";
586 LOG(debug) << "volPath=" << volPath << "\n";
587 LOG(debug) << "symName=" << symName << "\n";
588 LOG(debug) << "--------------------------------------------"
589 << "\n";
590
591 LOG(debug) << "Check for alignable entry: " << symName;
592
593 if (!gGeoManager->SetAlignableEntry(symName.Data(), volPath.Data(), modUID)) {
594 LOG(error) << "Alignable entry " << symName << " NOT set";
595 }
596 LOG(debug) << "Alignable entry " << symName << " set";
597
598 // Create the Tracking to Local transformation matrix for PHOS modules
599 TGeoPNEntry* alignableEntry = gGeoManager->GetAlignableEntryByUID(modUID);
600 LOG(debug) << "Got TGeoPNEntry " << alignableEntry;
601
602 if (alignableEntry) {
603 double angle = geom->GetCPVAngle(iModule);
604 TGeoHMatrix* globMatrix = alignableEntry->GetGlobalOrig();
605
606 TGeoHMatrix* matTtoL = new TGeoHMatrix;
607 matTtoL->RotateZ(270. + angle);
608 const TGeoHMatrix& globmatrixi = globMatrix->Inverse();
609 matTtoL->MultiplyLeft(&globmatrixi);
610 alignableEntry->SetMatrix(matTtoL);
611 }
612 }
613}
ClassImp(Detector)
Definition of the GeometryManager class.
Definition of the Stack class.
std::ostringstream debug
int16_t time
Definition RawEventData.h:4
int32_t i
uint16_t pos
Definition RawData.h:3
uint32_t j
Definition RawData.h:0
uint32_t stack
Definition RawData.h:1
void Matrix(Int_t &nmat, Double_t theta1, Double_t phi1, Double_t theta2, Double_t phi2, Double_t theta3, Double_t phi3) const
Definition Detector.cxx:104
void Mixture(Int_t imat, const char *name, Float_t *a, Float_t *z, Float_t dens, Int_t nlmat, Float_t *wmat)
Definition Detector.cxx:66
void Medium(Int_t numed, const char *name, Int_t nmat, Int_t isvol, Int_t ifield, Float_t fieldm, Float_t tmaxfd, Float_t stemax, Float_t deemax, Float_t epsil, Float_t stmin, Float_t *ubuf=nullptr, Int_t nbuf=0)
Definition Detector.cxx:72
int getMediumID(int imed) const
Definition Detector.h:136
static void initFieldTrackingParams(int &mode, float &maxfield)
Definition Detector.cxx:143
void Material(Int_t imat, const char *name, Float_t a, Float_t z, Float_t dens, Float_t radl, Float_t absl, Float_t *buf=nullptr, Int_t nwbuf=0)
Definition Detector.cxx:59
std::string addNameTo(const char *ext) const
Definition Detector.h:151
static int getSensID(o2::detectors::DetID detid, int sensid)
Detector class for the CPV detector.
Definition Detector.h:41
float CPVCumulPadResponse(float x, float y)
Definition Detector.cxx:299
~Detector() override
Definition Detector.cxx:53
void addHit(int trackID, short detID, const math_utils::Point3D< float > &pos, double time, float qdep)
Definition Detector.cxx:323
Detector()=default
float padResponseFunction(float qhit, float zhit, float xhit)
Definition Detector.cxx:279
void Register() override
Definition Detector.cxx:111
void ConstructGeometry() override
Definition Detector.cxx:332
void InitializeO2Detector() final
Definition Detector.cxx:58
void addAlignableVolumes() const override
Definition Detector.cxx:553
Bool_t ProcessHits(FairVolume *v=nullptr) final
Definition Detector.cxx:113
void EndOfEvent() final
Definition Detector.cxx:66
void FinishEvent() final
Sort final hist.
Definition Detector.cxx:70
void Reset() final
Definition Detector.cxx:104
void GetModuleCenter(int module, double *pos) const
double GetCPVFrameSize(int index) const
static GeometryParams * GetInstance(const std::string_view name="CPVRun3Params")
Get singleton (create if necessary)
void GetModuleAngle(int module, double angle[3][2]) const
int GetNumberOfCPVChipsZ() const
double GetGassiplexChipSize(int index) const
double GetFTPosition(int index) const
double GetCPVTextoliteThickness() const
double GetCPVActiveSize(int index) const
double GetCPVBoxSize(int index) const
double GetCPVAngle(Int_t index) const
int GetNumberOfCPVChipsPhi() const
double GetCPVCuNiFoilThickness() const
static unsigned short relToAbsId(short moduleNumber, short iphi, short iz)
Definition Geometry.cxx:19
CPV simulation hit information.
Definition Hit.h:25
void addHit(int iDet)
Definition Stack.cxx:639
int ID
Detector identifiers: continuous, starting from 0.
Definition DetID.h:63
static ShmManager & Instance()
Definition ShmManager.h:61
GLint GLenum GLint x
Definition glcorearb.h:403
const GLdouble * v
Definition glcorearb.h:832
GLint first
Definition glcorearb.h:399
GLint y
Definition glcorearb.h:270
GLboolean * data
Definition glcorearb.h:298
GLfloat angle
Definition glcorearb.h:4071
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
void freeSimVector(std::vector< T > *ptr)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Common utility functions.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"