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