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// FairRoot includes
13#include "Framework/Logger.h"
14#include "FairRootManager.h" // for FairRootManager
15#include "FairVolume.h" // for FairVolume
17#include "DetectorsBase/Stack.h"
19#include "DataFormatsZDC/Hit.h"
20
21#include "TMath.h"
22#include "TGeoManager.h" // for TGeoManager, gGeoManager
23#include "TGeoVolume.h" // for TGeoVolume, TGeoVolumeAssembly
24#include "TGeoTube.h" // for TGeoTube
25#include "TGeoCone.h" // for TGeoCone
26#include "TGeoCompositeShape.h" // for TGeoCone
27#include "TVirtualMC.h" // for gMC, TVirtualMC
28#include "TString.h" // for TString, operator+
29#include <TRandom.h>
30#include <cassert>
31#include <fstream>
33#ifdef ZDC_FASTSIM_ONNX
34#include "Utils.h" // for normal_distribution()
35#include "FastSimulations.h" // for fastsim module
36#include "Processors.h" // for fastsim module
37#endif
38
39using namespace o2::zdc;
40
42#define kRaddeg TMath::RadToDeg()
43
44//_____________________________________________________________________________
46 : o2::base::DetImpl<Detector>("ZDC", active),
47 mHits(new std::vector<o2::zdc::Hit>),
48 mXImpact(-999, -999, -999),
49 mNeutronResponseImage(Geometry::ZNDIVISION[0] * Geometry::ZNSECTORS[0] * 2,
50 Geometry::ZNDIVISION[1] * Geometry::ZNSECTORS[1] * 2,
51 Geometry::ZNAPOSITION[0] - Geometry::ZNDIMENSION[0],
52 Geometry::ZNAPOSITION[1] - Geometry::ZNDIMENSION[1],
53 Geometry::ZNDIMENSION[0] * 2,
54 Geometry::ZNDIMENSION[1] * 2),
55 mProtonResponseImage(Geometry::ZPDIVISION[0] * Geometry::ZPSECTORS[0] * 2,
56 Geometry::ZPDIVISION[1] * Geometry::ZPSECTORS[1] * 2,
57 Geometry::ZPAPOSITION[0] - Geometry::ZPDIMENSION[0],
58 Geometry::ZPAPOSITION[1] - Geometry::ZPDIMENSION[1],
59 Geometry::ZPDIMENSION[0] * 2,
60 Geometry::ZPDIMENSION[1] * 2)
61{
62 mTrackEta = 999;
63 // REsetting summed variables
64 mTotLightPMC = 0;
65 mTotLightPMQ = 0;
66 mMediumPMCid = -1; // minus for unitialized
67 mMediumPMQid = -2; // different to PMC in any case
68 resetHitIndices();
69
70#ifdef ZDC_FASTSIM_ONNX
71 // If FastSim module was disabled, log appropriate message
72 // otherwise check if all necessary parameters were passed, if so try build objects
73 auto& simparam = o2::zdc::ZDCSimParam::Instance();
74
75 if (!simparam.useZDCFastSim) {
76 LOG(info) << "FastSim module disabled";
77 } else if (simparam.useZDCFastSim && !simparam.ZDCFastSimClassifierPath.empty() && !simparam.ZDCFastSimClassifierScales.empty()) {
78 if (!mClassifierScaler) {
79 mClassifierScaler = new fastsim::processors::StandardScaler;
80 }
81 if (!mModelScalerNeutron) {
82 mModelScalerNeutron = new fastsim::processors::StandardScaler;
83 }
84 if (!mModelScalerProton) {
85 mModelScalerProton = new fastsim::processors::StandardScaler;
86 }
87 auto eonScales = o2::zdc::fastsim::loadScales(simparam.ZDCFastSimClassifierScales);
88 if (!eonScales.has_value()) {
89 LOG(error) << "Error while reading model scales from: "
90 << "'" << simparam.ZDCFastSimClassifierScales << "'";
91 LOG(error) << "FastSim module disabled.";
92 } else {
93 mClassifierScaler->setScales(eonScales->first, eonScales->second);
94 mFastSimClassifier = new o2::zdc::fastsim::ConditionalModelSimulation(simparam.ZDCFastSimClassifierPath, 1);
95
96 if (simparam.useZDCFastSim && !simparam.ZDCFastSimModelPathNeutron.empty() && !simparam.ZDCFastSimModelScalesNeutron.empty()) {
97 auto modelScalesNeutron = o2::zdc::fastsim::loadScales(simparam.ZDCFastSimModelScalesNeutron);
98
99 if (!modelScalesNeutron.has_value()) {
100 LOG(error) << "Error while reading model scales from: "
101 << "'" << simparam.ZDCFastSimModelScalesNeutron << "'";
102 LOG(error) << "FastSim module disabled";
103 } else {
104 mModelScalerNeutron->setScales(modelScalesNeutron->first, modelScalesNeutron->second);
105 mFastSimModelNeutron = new o2::zdc::fastsim::ConditionalModelSimulation(simparam.ZDCFastSimModelPathNeutron, 1);
106 LOG(info) << "FastSim neutron module enabled";
107 }
108 }
109 if (simparam.useZDCFastSim && !simparam.ZDCFastSimModelPathProton.empty() && !simparam.ZDCFastSimModelScalesProton.empty()) {
110 auto modelScalesProton = o2::zdc::fastsim::loadScales(simparam.ZDCFastSimModelScalesProton);
111
112 if (!modelScalesProton.has_value()) {
113 LOG(error) << "Error while reading model scales from: "
114 << "'" << simparam.ZDCFastSimModelScalesProton << "'";
115 LOG(error) << "FastSim module disabled";
116 } else {
117 mModelScalerProton->setScales(modelScalesProton->first, modelScalesProton->second);
118 mFastSimModelProton = new o2::zdc::fastsim::ConditionalModelSimulation(simparam.ZDCFastSimModelPathProton, 1);
119 LOG(info) << "FastSim proton module enabled";
120 }
121 }
122 }
123 }
124#endif
125}
126
127//_____________________________________________________________________________
129 : o2::base::DetImpl<Detector>(rhs),
130 mHits(new std::vector<o2::zdc::Hit>)
131{
132}
133
134//_____________________________________________________________________________
135#ifdef ZDC_FASTSIM_ONNX
137{
138 delete (mFastSimClassifier);
139 delete (mFastSimModelNeutron);
140 delete (mFastSimModelProton);
141 delete (mClassifierScaler);
142 delete (mModelScalerNeutron);
143 delete (mModelScalerProton);
144}
145#endif
146
147//_____________________________________________________________________________
148template <typename T>
149int loadLightTable(T& table, int beta, int NRADBINS, std::string filename)
150{
151 // Retrieve the light yield table
152 std::string data;
153 std::ifstream input(filename);
154 //std::cout << " ********* Reading data from light table " << filename << std::endl;
155 int radiusbin = 0;
156 int anglebin = 0;
157 int counter = 0;
158 float value;
159 if (input.is_open()) {
160 while (input >> value) {
161 counter++;
162 table[beta][anglebin][radiusbin] = value;
163 //printf(" %f ", value);
164 radiusbin++;
165 if (radiusbin % NRADBINS == 0) {
166 radiusbin = 0;
167 anglebin++;
168 //printf("\n");
169 }
170 }
171 LOG(debug) << "Read " << counter << " values from ZDC data file " << filename;
172 input.close();
173 return counter;
174 } else {
175 LOG(error) << "Could not open file " << filename;
176 return 0;
177 }
178}
179
180//_____________________________________________________________________________
182{
183 // Define the list of sensitive volumes
184 defineSensitiveVolumes();
185
186 std::string inputDir;
187 const char* aliceO2env = std::getenv("O2_ROOT");
188 if (aliceO2env) {
189 inputDir = std::string(aliceO2env);
190 }
191 inputDir += "/share/Detectors/ZDC/simulation/data/";
192 //ZN case
193 loadLightTable(mLightTableZN, 0, ZNRADIUSBINS, inputDir + "light22620362207s");
194 loadLightTable(mLightTableZN, 1, ZNRADIUSBINS, inputDir + "light22620362208s");
195 loadLightTable(mLightTableZN, 2, ZNRADIUSBINS, inputDir + "light22620362209s");
196 auto elements = loadLightTable(mLightTableZN, 3, ZNRADIUSBINS, inputDir + "light22620362210s");
197 assert(elements == ZNRADIUSBINS * ANGLEBINS);
198 // check a few values to test correctness of reading from file light22620362207s
199 /*assert(std::abs(mLightTableZN[0][ZNRADIUSBINS - 1][0] - 1.39742) < 1.E-4); // beta=0; radius = ZNRADIUSBINS - 1; anglebin = 2;
200 assert(std::abs(mLightTableZN[0][ZNRADIUSBINS - 1][1] - .45017) < 1.E-4); // beta=1; radius = ZNRADIUSBINS - 1; anglebin = 2;
201 assert(std::abs(mLightTableZN[0][0][2] - .47985) < 1.E-4); // beta=0; radius = 0; anglebin = 2;
202 assert(std::abs(mLightTableZN[0][0][11] - .01358) < 1.E-4); // beta=0; radius = 0; anglebin = 11;
203 */
204
205 //ZP case
206 loadLightTable(mLightTableZP, 0, ZPRADIUSBINS, inputDir + "light22620552207s");
207 loadLightTable(mLightTableZP, 1, ZPRADIUSBINS, inputDir + "light22620552208s");
208 loadLightTable(mLightTableZP, 2, ZPRADIUSBINS, inputDir + "light22620552209s");
209 elements = loadLightTable(mLightTableZP, 3, ZPRADIUSBINS, inputDir + "light22620552210s");
210 assert(elements == ZPRADIUSBINS * ANGLEBINS);
211}
212
213//_____________________________________________________________________________
215{
216 LOG(debug) << "Creating ZDC geometry\n";
217
219
220 createAsideBeamLine();
221 createCsideBeamLine();
222 createMagnets();
223 createDetectors();
224}
225
226//_____________________________________________________________________________
227void Detector::defineSensitiveVolumes()
228{
229 LOG(info) << "defining sensitive for ZDC";
230 auto vol = gGeoManager->GetVolume("ZNENV");
231 if (vol) {
232 AddSensitiveVolume(vol);
233 mZNENVVolID = vol->GetNumber(); // initialize id
234
235 AddSensitiveVolume(gGeoManager->GetVolume("ZNF1"));
236 AddSensitiveVolume(gGeoManager->GetVolume("ZNF2"));
237 AddSensitiveVolume(gGeoManager->GetVolume("ZNF3"));
238 AddSensitiveVolume(gGeoManager->GetVolume("ZNF4"));
239 } else {
240 LOG(fatal) << "can't find volume ZNENV";
241 }
242 vol = gGeoManager->GetVolume("ZPENV");
243 if (vol) {
244 AddSensitiveVolume(vol);
245 mZPENVVolID = vol->GetNumber(); // initialize id
246
247 AddSensitiveVolume(gGeoManager->GetVolume("ZPF1"));
248 AddSensitiveVolume(gGeoManager->GetVolume("ZPF2"));
249 AddSensitiveVolume(gGeoManager->GetVolume("ZPF3"));
250 AddSensitiveVolume(gGeoManager->GetVolume("ZPF4"));
251 } else {
252 LOG(fatal) << "can't find volume ZPENV";
253 }
254 // em calorimeter
255 vol = gGeoManager->GetVolume("ZEM ");
256 if (vol) {
257 AddSensitiveVolume(vol);
258 mZEMVolID = vol->GetNumber();
259 AddSensitiveVolume(gGeoManager->GetVolume("ZEMF"));
260 } else {
261 LOG(fatal) << "can't find volume ZEM";
262 }
263}
264
265// determines detectorID and sectorID from volume and coordinates
266void Detector::getDetIDandSecID(TString const& volname, math_utils::Vector3D<float> const& x,
267 math_utils::Vector3D<float>& xDet, int& detector, int& sector) const
268{
269 if (volname.BeginsWith("ZN")) {
270 // for the neutron calorimeter
271
272 if (x.Z() > 0) {
273 detector = ZNA;
275
276 } else if (x.Z() < 0) {
277 detector = ZNC;
279 }
280 // now determine sector/tower
281 if (xDet.X() <= 0.) {
282 if (xDet.Y() <= 0.) {
283 sector = Ch1;
284 } else {
285 sector = Ch3;
286 }
287 } else {
288 if (xDet.Y() <= 0.) {
289 sector = Ch2;
290 } else {
291 sector = Ch4;
292 }
293 }
294 return;
295
296 } else if (volname.BeginsWith("ZP")) {
297 // proton calorimeter
298 if (x.Z() > 0) {
299 detector = ZPA; // (NB -> DIFFERENT FROM AliRoot!!!)
301 } else if (x.Z() < 0) {
302 detector = ZPC; // (NB -> DIFFERENT FROM AliRoot!!!)
304 }
305
306 // determine sector/tower
307 if (xDet.X() >= Geometry::ZPDIMENSION[0]) {
308 xDet.SetX(Geometry::ZPDIMENSION[0] - 0.01);
309 } else if (xDet.X() <= -Geometry::ZPDIMENSION[0]) {
310 xDet.SetX(-Geometry::ZPDIMENSION[0] + 0.01);
311 }
312
313 float xTow = 2. * xDet.X() / (Geometry::ZPDIMENSION[0]);
314 for (int i = 1; i <= 4; i++) {
315 if (xTow >= (i - 3) && xTow < (i - 2)) {
316 sector = i;
317 break;
318 }
319 }
320 return;
321
322 } else if (volname.BeginsWith("ZE")) {
323 // electromagnetic calorimeter
324 detector = ZEM;
326 sector = (x.X() > 0.) ? Ch1 : Ch2;
327 return;
328 }
329
330 assert(false);
331}
332
333//_____________________________________________________________________________
334void Detector::resetHitIndices()
335{
336 // reinit hit buffer to null (because we make new hits for each principal track)
337 for (int det = 0; det < NUMDETS; ++det) {
338 for (int sec = 0; sec < NUMSECS; ++sec) {
339 mCurrentHitsIndices[det][sec] = -1;
340 }
341 }
342 // Summed variables are set to 0
343 mTotLightPMC = 0;
344 mTotLightPMQ = 0;
345}
346
347void Detector::flushSpatialResponse()
348{
349 if (o2::zdc::ZDCSimParam::Instance().recordSpatialResponse) {
350 auto c = mNeutronResponseImage.getPhotonsPerChannel();
351 std::fstream output("o2sim-FullSimResult", std::fstream::out | std::fstream::app);
352 output << c[0] << " " << c[1] << " " << c[2] << " " << c[3] << " " << c[4] << "\n";
353 output.close();
354
355 // only write non-trivial image pairs
356 if (mNeutronResponseImage.getPhotonSum() > 0 || mProtonResponseImage.getPhotonSum() > 0) {
357 mResponses.push_back(std::make_pair(mCurrentPrincipalParticle,
358 std::make_pair(mNeutronResponseImage, mProtonResponseImage)));
359 }
360 mNeutronResponseImage.reset();
361 mProtonResponseImage.reset();
362 }
363}
364
365// quick estimates the time of flight to reach this detector (located at z)
366// just based on primary particle properties
367// Meant for the neutron / proton detectors which sit a large z so that speed
368// is essentially the speed in z-direction.
369double estimateTimeOfFlight(TParticle const& part, double z /* needs to be in meters */)
370{
371 const auto m = part.GetMass();
372 constexpr auto SPEED_OF_LIGHT = 299792458.; // m/s
373 if (m == 0.) {
374 return z / SPEED_OF_LIGHT;
375 } else {
376 TLorentzVector lorentz; // could be made member var
377 part.Momentum(lorentz);
378 const auto gamma = lorentz.Gamma();
379 const auto speed = SPEED_OF_LIGHT * std::sqrt(1. - 1. / (gamma * gamma));
380 return z / speed; // could refine this
381 }
382}
383
384//_____________________________________________________________________________
385Bool_t Detector::ProcessHits(FairVolume* v)
386{
387 // Method called from MC stepping for the sensitive volumes
388 TString volname = fMC->CurrentVolName();
389 float x[3] = {0., 0., 0.};
390 fMC->TrackPosition(x[0], x[1], x[2]);
391
392 // determine detectorID and sectorID
393 int detector = -1;
394 int sector = -1;
396 getDetIDandSecID(volname, math_utils::Vector3D<float>(x[0], x[1], x[2]), xImp, detector, sector);
397
398 auto stack = (o2::data::Stack*)fMC->GetStack();
399 int trackn = stack->GetCurrentTrackNumber();
400
401 // find out if we are entering into the detector NEU or PRO for the first time
402 int volID, copy;
403 volID = fMC->CurrentVolID(copy);
404 //printf("\t ---> track %d in vol. %d %d (volID %d) mother %d \n",
405 //trackn, detector, sector, volID, stack->GetCurrentTrack()->GetMother(0));
406
407 // If the particle is in a ZN or ZP fiber connected to the common PMT
408 // then the assigned sector is 0 (PMC) NB-> does not work for ZEM
409 if ((fMC->CurrentMedium() == mMediumPMCid) && (detector != ZEM)) {
410 sector = 0;
411 }
412 //printf("ProcessHits: x=(%f, %f, %f) \n",x[0], x[1], x[2]);
413 //printf("\tDET %d SEC %d -> XImpact=(%f, %f, %f)\n",detector,sector, xImp.X(), xImp.Y(), xImp.Z());
414
415 if ((volID == mZNENVVolID || volID == mZPENVVolID || volID == mZEMVolID)) {
416 // there is nothing more to do here as we are not
417 // in the fiber volumes
418 return false;
419 }
420
421 float p[3] = {0., 0., 0.};
422 float trackenergy = 0.;
423 fMC->TrackMomentum(p[0], p[1], p[2], trackenergy);
424 float eDep = fMC->Edep();
425
426 int pdgCode = fMC->TrackPid();
427 float lightoutput = 0.;
428 auto currentMediumid = fMC->CurrentMedium();
429 int nphe = 0;
430 if (((currentMediumid == mMediumPMCid) || (currentMediumid == mMediumPMQid))) {
431 if (eDep) {
432 int ibeta = 0, iangle = 0, iradius = 0;
433 Bool_t isLightProduced = calculateTableIndexes(ibeta, iangle, iradius);
434 if (isLightProduced) {
435 int charge = 0;
436 if (pdgCode < 10000) {
437 charge = fMC->TrackCharge();
438 } else {
439 charge = TMath::Abs(pdgCode / 10000 - 100000);
440 }
441
442 //look into the light tables if the particle is charged
443 if (TMath::Abs(charge) > 0) {
444 if (detector == 1 || detector == 4) {
445 iradius = std::min((int)Geometry::ZNFIBREDIAMETER, iradius);
446 lightoutput = charge * charge * mLightTableZN[ibeta][iangle][iradius];
447 //printf(" \t ZNtableEntry[%d %d %d] = %1.5f -> lightoutput %f\n", ibeta, iangle, iradius, mLightTableZN[ibeta][iangle][iradius], lightoutput);
448 } else {
449 iradius = std::min((int)Geometry::ZPFIBREDIAMETER, iradius);
450 lightoutput = charge * charge * mLightTableZP[ibeta][iangle][iradius];
451 //printf(" \t ZPtableEntry[%d %d %d] = %1.5f -> lightoutput %f\n", ibeta, iangle, iradius, mLightTableZP[ibeta][iangle][iradius], lightoutput);
452 }
453 if (lightoutput > 0) {
454 nphe = gRandom->Poisson(lightoutput);
455 //printf(" \t\t-> nphe %d \n", nphe);
456 }
457 }
458 }
459 }
460 }
461
462 auto tof = 1.e09 * fMC->TrackTime(); //TOF in ns
463
464 if (o2::zdc::ZDCSimParam::Instance().recordSpatialResponse) {
465 // some diagnostic; trying to really get the pixel fired
466 if (nphe > 0) {
467 if (detector == ZNA || detector == ZNC) {
468 mNeutronResponseImage.setDetectorID(detector);
469 mNeutronResponseImage.addPhoton(x[0], x[1], nphe);
470 mNeutronResponseImage.setHitTime(tof);
471 }
472 if (detector == ZPA || detector == ZPC) {
473 mProtonResponseImage.setDetectorID(detector);
474 mProtonResponseImage.addPhoton(x[0], x[1], nphe);
475 mProtonResponseImage.setHitTime(tof);
476 }
477 }
478 }
479
480 // A new hit is created when there is nothing yet for this det + sector
481 if (mCurrentHitsIndices[detector - 1][sector] == -1) {
482 bool issecondary = trackn != stack->getCurrentPrimaryIndex();
483 //if(!issecondary) printf(" !!! primary track (index %d)\n",stack->getCurrentPrimaryIndex());
484
485 mTotLightPMC = mTotLightPMQ = 0;
486 if (currentMediumid == mMediumPMCid) {
487 mTotLightPMC = nphe;
488 } else if (currentMediumid == mMediumPMQid) {
489 mTotLightPMQ = nphe;
490 }
491
492 math_utils::Vector3D<float> pos(x[0], x[1], x[2]);
493 math_utils::Vector3D<float> mom(p[0], p[1], p[2]);
494 addHit(trackn, mLastPrincipalTrackEntered, issecondary, trackenergy, detector, sector,
495 pos, mom, tof, xImp, eDep, mTotLightPMC, mTotLightPMQ);
496 stack->addHit(GetDetId());
497 mCurrentHitsIndices[detector - 1][sector] = mHits->size() - 1;
498
499 mXImpact = xImp;
500 //printf("### NEW HIT CREATED in vol %d %d for track %d (mother: %d) \t light %1.0f %1.0f\n",
501 //detector, sector, trackn, stack->GetCurrentTrack()->GetFirstMother(), mTotLightPMC, mTotLightPMQ);
502 return true;
503
504 } else {
505 auto& curHit = (*mHits)[mCurrentHitsIndices[detector - 1][sector]];
506 // summing variables that needs to be updated (Eloss and light yield)
507 curHit.setNoNumContributingSteps(curHit.getNumContributingSteps() + 1);
508 int nPMC{0}, nPMQ{0};
509 if (currentMediumid == mMediumPMCid) {
510 mTotLightPMC += nphe;
511 nPMC = nphe;
512 } else if (currentMediumid == mMediumPMQid) {
513 mTotLightPMQ += nphe;
514 nPMQ = nphe;
515 }
516 float incenloss = curHit.GetEnergyLoss() + eDep;
517 if (nphe > 0) {
518 curHit.SetEnergyLoss(incenloss);
519 curHit.setPMCLightYield(curHit.getPMCLightYield() + nPMC);
520 curHit.setPMQLightYield(curHit.getPMQLightYield() + nPMQ);
521 //printf(" >>> Hit updated in vol %d %d for track %d (mother: %d) \t light %1.0f %1.0f \n",
522 //detector, sector, trackn, stack->GetCurrentTrack()->GetFirstMother(), curHit.getPMCLightYield(), curHit.getPMQLightYield());
523 }
524 return true;
525 }
526 return false;
527}
528
529// function to create hit structure from a SpatialResponseImage
530// idea is to use this from a fast sim generating the response
532{
533 // one image will make one hit per sector
534 math_utils::Vector3D<float> xImp(0., 0., 0.); // good value
535
536 const int Nx = image.getNx();
537 const int Ny = image.getNy();
538 const auto& pixels = image.getImageData();
539
540 // could be put inside the image class
541 auto determineSectorID = [Nx, Ny](int detector, int x, int y) {
542 if (detector == ZNA || detector == ZNC) {
543 if ((x + y) % 2 == 0) {
544 return (int)Common;
545 }
546 if (x < Nx / 2) {
547 if (y < Ny / 2) {
548 return (int)Ch1;
549 } else {
550 return (int)Ch3;
551 }
552 } else {
553 if (y >= Ny / 2) {
554 return (int)Ch4;
555 } else {
556 return (int)Ch2;
557 }
558 }
559 }
560
561 if (detector == ZPA || detector == ZPC) {
562 if ((x + y) % 2 == 0) {
563 return (int)Common;
564 }
565 auto i = (int)(4.f * x / Nx);
566 return (int)(i + 1);
567 }
568 return -1;
569 };
570
571 auto determineMediumID = [this](int detector, int x, int y) {
572 // it is a simple checkerboard pattern
573 return ((x + y) % 2 == 0) ? mMediumPMCid : mMediumPMQid;
574 };
575
576 // loop over x = columns
577 for (int x = 0; x < Nx; ++x) {
578 // loop over y = rows
579 for (int y = 0; y < Ny; ++y) {
580 // get sector
581 int sector = determineSectorID(detector, x, y);
582 // get medium PMQ and PMC
583 int currentMediumid = determineMediumID(detector, x, y);
584 // LOG(info) << " x " << x << " y " << y << " sec " << sector << " medium " << currentMediumid;
585 int nphe = pixels[x][y];
586 float tof = 0.; // needs to be in nanoseconds ---> to be filled later on (should be meta-data of image or calculated otherwise)
587 float trackenergy = 0; // energy of the primary (need to fill good value)
588 createOrAddHit(detector,
589 sector,
590 currentMediumid,
591 0 /*issecondary ---> don't know in fast sim */,
592 nphe,
593 0 /* trackn */,
594 0 /* parent */,
595 tof,
596 trackenergy,
597 xImp,
598 0. /* eDep */, 0 /* x */, 0. /* y */, 0. /* z */, 0. /* px */, 0. /* py */, 0. /* pz */);
599 } // end loop over y
600 } // end loop over x
601 return true;
602} // end function
603
604//_____________________________________________________________________________
605o2::zdc::Hit* Detector::addHit(int32_t trackID, int32_t parentID, int32_t sFlag, float primaryEnergy, int32_t detID,
607 double energyloss, int32_t nphePMC, int32_t nphePMQ)
608{
609 LOG(debug4) << "Adding hit for track " << trackID << " X (" << pos.X() << ", " << pos.Y() << ", "
610 << pos.Z() << ") P (" << mom.X() << ", " << mom.Y() << ", " << mom.Z() << ") Ekin "
611 << primaryEnergy << " lightPMC " << nphePMC << " lightPMQ " << nphePMQ << std::endl;
612 mHits->emplace_back(trackID, parentID, sFlag, primaryEnergy, detID, secID, pos, mom,
613 tof, xImpact, energyloss, nphePMC, nphePMQ);
614 return &(mHits->back());
615}
616
617//_____________________________________________________________________________
619{
620 int32_t ifield = 2;
621 float fieldm = 10.0;
623 LOG(info) << "Detector::CreateMaterials >>>>> magnetic field: type " << ifield << " max " << fieldm << "\n";
624
625 // ******** MATERIAL DEFINITION ********
626 // --- W alloy -> ZN passive material
627 float aW[3] = {183.85, 55.85, 58.71};
628 float zW[3] = {74., 26., 28.};
629 float wW[3] = {0.93, 0.03, 0.04};
630 float dW = 17.6;
631
632 // --- Brass (CuZn) -> ZP passive material
633 float aCuZn[2] = {63.546, 65.39};
634 float zCuZn[2] = {29., 30.};
635 float wCuZn[2] = {0.63, 0.37};
636 float dCuZn = 8.48;
637
638 // --- SiO2 -> fibres
639 float aq[2] = {28.0855, 15.9994};
640 float zq[2] = {14., 8.};
641 float wq[2] = {1., 2.};
642 float dq = 2.64;
643
644 // --- Lead -> ZEM passive material
645 float aPb = 207.2;
646 float zPb = 82.;
647 float dPb = 11.35;
648 float radPb = 6.37 / dPb;
649 float absPb = 199.6 / dPb;
650
651 // --- Copper -> beam pipe
652 float aCu = 63.546;
653 float zCu = 29.;
654 float dCu = 8.96;
655 float radCu = 12.86 / dCu;
656 float absCu = 137.3 / dCu;
657 // int32_t nCu = 1.10;
658
659 // --- Iron -> beam pipe
660 float aFe = 55.845;
661 float zFe = 26.;
662 float dFe = 7.874;
663 float radFe = 13.84 / dFe;
664 float absFe = 132.1 / dFe;
665
666 // --- Aluminum -> beam pipe
667 float aAl = 26.98;
668 float zAl = 13.;
669 float dAl = 2.699;
670 float radAl = 24.01 / dAl;
671 float absAl = 107.2 / dAl;
672
673 // --- Carbon -> beam pipe
674 float aCarb = 12.01;
675 float zCarb = 6.;
676 float dCarb = 2.265;
677 float radCarb = 18.8;
678 float absCarb = 49.9;
679
680 // --- Residual gas -> inside beam pipe
681 float aResGas[3] = {1.008, 12.0107, 15.9994};
682 float zResGas[3] = {1., 6., 8.};
683 float wResGas[3] = {0.28, 0.28, 0.44};
684 float dResGas = 3.2E-14;
685
686 // --- Air
687 float aAir[4] = {12.0107, 14.0067, 15.9994, 39.948};
688 float zAir[4] = {6., 7., 8., 18.};
689 float wAir[4] = {0.000124, 0.755267, 0.231781, 0.012827};
690 float dAir = 1.20479E-3;
691
692 // ******** TRACKING MEDIA PARAMETERS ********
693 int32_t notactiveMed = 0, sensMed = 1; // sensitive or not sensitive medium
694
695 // field integration 0 no field -1 user in guswim 1 Runge Kutta 2 helix 3 const field along z
696 int32_t inofld = 0; // Max. field value (no field)
697 int32_t ifld = 2; //TODO: ????CHECK!!!! secondo me va -1!!!!!
698 float nofieldm = 0.;
699
700 float maxnofld = 0.; // max field value (no field)
701 float maxfld = 45.; // max field value (with field)
702 float tmaxnofd = 0.; // max deflection angle due to magnetic field in one step
703 float tmaxfd = 0.1; // max deflection angle due to magnetic field in one step
704 float deemax = -1.; // maximum fractional energy loss in one step 0<deemax<=1
705 float epsil = 0.001; // tracking precision [cm]
706 float stemax = 1.; // max step allowed [cm] ????CHECK!!!!
707 float stmin = 0.01; // minimum step due to continuous processes [cm] (negative value: choose it automatically) ????CHECK!!!! 0.01 in aliroot
708
709 // ******** MATERIAL DEFINITION ********
710 Mixture(0, "Walloy$", aW, zW, dW, 3, wW);
711 Mixture(1, "CuZn$", aCuZn, zCuZn, dCuZn, 2, wCuZn);
712 Mixture(2, "SiO2$", aq, zq, dq, -2, wq);
713 Material(3, "Pb $", aPb, zPb, dPb, radPb, absPb);
714 Material(4, "Cu $", aCu, zCu, dCu, radCu, absCu);
715 Material(5, "Fe $", aFe, zFe, dFe, radFe, absFe);
716 Material(6, "Al $", aAl, zAl, dAl, radAl, absAl);
717 Material(7, "graphite$", aCarb, zCarb, dCarb, radCarb, absCarb);
718 Mixture(8, "residualGas$", aResGas, zResGas, dResGas, 3, wResGas);
719 Mixture(9, "Air$", aAir, zAir, dAir, 4, wAir);
720
721 // ******** MEDIUM DEFINITION ********
722 Medium(kWalloy, "Walloy$", 0, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
723 Medium(kCuZn, "CuZn$", 1, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
724 Medium(kSiO2pmc, "quartzPMC$", 2, sensMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
725 Medium(kSiO2pmq, "quartzPMQ$", 2, sensMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
726 Medium(kPb, "Lead$", 3, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
727 Medium(kCu, "Copper$", 4, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
728 Medium(kCuLumi, "CopperLowTh$", 4, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
729 Medium(kFe, "Iron$", 5, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
730 Medium(kFeLowTh, "IronLowTh$", 5, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
731 Medium(kAl, "Aluminum$", 6, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
732 Medium(kGraphite, "Graphite$", 7, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
733 Medium(kVoidNoField, "VoidNoField$", 8, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
734 Medium(kVoidwField, "VoidwField$", 8, notactiveMed, ifld, maxfld, tmaxfd, stemax, deemax, epsil, stmin);
735 Medium(kAir, "Air$", 9, notactiveMed, inofld, nofieldm, tmaxnofd, stemax, deemax, epsil, stmin);
736}
737
738//_____________________________________________________________________________
739void Detector::createAsideBeamLine()
740{
741
742 double tubpar[3] = {0., 0., 0};
743 float boxpar[3] = {0., 0., 0};
744 double tubspar[5] = {0., 0., 0., 0., 0.};
745 double conpar[15] = {0.}; // all elements will be 0
746
747 float zA = 1910.4;
748
749 conpar[0] = 0.;
750 conpar[1] = 360.;
751 conpar[2] = 2.;
752 conpar[3] = zA;
753 conpar[4] = 0.;
754 conpar[5] = 55.;
755 conpar[6] = 13500.;
756 conpar[7] = 0.;
757 conpar[8] = 55.;
758 TVirtualMC::GetMC()->Gsvolu("ZDCA", "PCON", getMediumID(kVoidNoField), conpar, 9);
759 TVirtualMC::GetMC()->Gspos("ZDCA", 1, "cave", 0., 0., 0., 0, "ONLY");
760
761 // BEAM PIPE from 19.10 m to inner triplet beginning (22.965 m)
762 tubpar[0] = 6.0 / 2.;
763 tubpar[1] = 6.4 / 2.;
764 tubpar[2] = (386.28 - 0.18) / 2.;
765 TVirtualMC::GetMC()->Gsvolu("QA01", "TUBE", getMediumID(kFe), tubpar, 3);
766 TVirtualMC::GetMC()->Gspos("QA01", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
767
768 zA += 2. * tubpar[2];
769
770 // -- FIRST SECTION OF THE BEAM PIPE (from beginning of inner triplet to beginning of D1)
771 tubpar[0] = 6.3 / 2.;
772 tubpar[1] = 6.7 / 2.;
773 tubpar[2] = 3541.8 / 2.;
774 TVirtualMC::GetMC()->Gsvolu("QA02", "TUBE", getMediumID(kFe), tubpar, 3);
775 TVirtualMC::GetMC()->Gspos("QA02", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
776
777 zA += 2. * tubpar[2];
778
779 // -- SECOND SECTION OF THE BEAM PIPE (from the beginning of D1 to the beginning of D2)
780 // FROM (MAGNETIC) BEGINNING OF D1 TO THE (MAGNETIC) END OF D1 + 126.5 cm
781 // CYLINDRICAL PIPE of diameter increasing from 6.75 cm up to 8.0 cm
782 // from magnetic end :
783 // 1) 80.1 cm still with ID = 6.75 radial beam screen
784 // 2) 2.5 cm conical section from ID = 6.75 to ID = 8.0 cm
785 // 3) 43.9 cm straight section (tube) with ID = 8.0 cm
786
787 tubpar[0] = 6.75 / 2.;
788 tubpar[1] = 7.15 / 2.;
789 tubpar[2] = (945.0 + 80.1) / 2.;
790 TVirtualMC::GetMC()->Gsvolu("QA03", "TUBE", getMediumID(kFe), tubpar, 3);
791 TVirtualMC::GetMC()->Gspos("QA03", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
792
793 zA += 2. * tubpar[2];
794
795 // Transition Cone from ID=67.5 mm to ID=80 mm
796 conpar[0] = 2.5 / 2.;
797 conpar[1] = 6.75 / 2.;
798 conpar[2] = 7.15 / 2.;
799 conpar[3] = 8.0 / 2.;
800 conpar[4] = 8.4 / 2.;
801 TVirtualMC::GetMC()->Gsvolu("QA04", "CONE", getMediumID(kFe), conpar, 5);
802 TVirtualMC::GetMC()->Gspos("QA04", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
803
804 zA += 2. * conpar[0];
805
806 tubpar[0] = 8.0 / 2.;
807 tubpar[1] = 8.4 / 2.;
808 tubpar[2] = (43.9 + 20. + 28.5 + 28.5) / 2.;
809 TVirtualMC::GetMC()->Gsvolu("QA05", "TUBE", getMediumID(kFe), tubpar, 3);
810 TVirtualMC::GetMC()->Gspos("QA05", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
811
812 zA += 2. * tubpar[2];
813
814 // Second section of VAEHI (transition cone from ID=80mm to ID=98mm)
815 conpar[0] = 4.0 / 2.;
816 conpar[1] = 8.0 / 2.;
817 conpar[2] = 8.4 / 2.;
818 conpar[3] = 9.8 / 2.;
819 conpar[4] = 10.2 / 2.;
820 TVirtualMC::GetMC()->Gsvolu("QAV1", "CONE", getMediumID(kFe), conpar, 5);
821 TVirtualMC::GetMC()->Gspos("QAV1", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
822
823 zA += 2. * conpar[0];
824
825 //Third section of VAEHI (transition cone from ID=98mm to ID=90mm)
826 conpar[0] = 1.0 / 2.;
827 conpar[1] = 9.8 / 2.;
828 conpar[2] = 10.2 / 2.;
829 conpar[3] = 9.0 / 2.;
830 conpar[4] = 9.4 / 2.;
831 TVirtualMC::GetMC()->Gsvolu("QAV2", "CONE", getMediumID(kFe), conpar, 5);
832 TVirtualMC::GetMC()->Gspos("QAV2", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
833
834 zA += 2. * conpar[0];
835
836 // Fourth section of VAEHI (tube ID=90mm)
837 tubpar[0] = 9.0 / 2.;
838 tubpar[1] = 9.4 / 2.;
839 tubpar[2] = 31.0 / 2.;
840 TVirtualMC::GetMC()->Gsvolu("QAV3", "TUBE", getMediumID(kFe), tubpar, 3);
841 TVirtualMC::GetMC()->Gspos("QAV3", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
842
843 zA += 2. * tubpar[2];
844
845 //---------------------------- TCDD beginning ----------------------------------
846 // space for the insertion of the collimator TCDD (2 m)
847 // TCDD ZONE - 1st volume
848 conpar[0] = 1.3 / 2.;
849 conpar[1] = 9.0 / 2.;
850 conpar[2] = 13.0 / 2.;
851 conpar[3] = 9.6 / 2.;
852 conpar[4] = 13.0 / 2.;
853 TVirtualMC::GetMC()->Gsvolu("Q01T", "CONE", getMediumID(kFe), conpar, 5);
854 TVirtualMC::GetMC()->Gspos("Q01T", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
855
856 zA += 2. * conpar[0];
857
858 // TCDD ZONE - 2nd volume
859 tubpar[0] = 9.6 / 2.;
860 tubpar[1] = 10.0 / 2.;
861 tubpar[2] = 1.0 / 2.;
862 TVirtualMC::GetMC()->Gsvolu("Q02T", "TUBE", getMediumID(kFe), tubpar, 3);
863 TVirtualMC::GetMC()->Gspos("Q02T", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
864
865 zA += 2. * tubpar[2];
866
867 // TCDD ZONE - third volume
868 conpar[0] = 9.04 / 2.;
869 conpar[1] = 9.6 / 2.;
870 conpar[2] = 10.0 / 2.;
871 conpar[3] = 13.8 / 2.;
872 conpar[4] = 14.2 / 2.;
873 TVirtualMC::GetMC()->Gsvolu("Q03T", "CONE", getMediumID(kFe), conpar, 5);
874 TVirtualMC::GetMC()->Gspos("Q03T", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
875
876 zA += 2. * conpar[0];
877
878 // TCDD ZONE - 4th volume
879 tubpar[0] = 13.8 / 2.;
880 tubpar[1] = 14.2 / 2.;
881 tubpar[2] = 38.6 / 2.;
882 TVirtualMC::GetMC()->Gsvolu("Q04T", "TUBE", getMediumID(kFe), tubpar, 3);
883 TVirtualMC::GetMC()->Gspos("Q04T", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
884
885 zA += 2. * tubpar[2];
886
887 // TCDD ZONE - 5th volume
888 tubpar[0] = 21.0 / 2.;
889 tubpar[1] = 21.4 / 2.;
890 tubpar[2] = 100.12 / 2.;
891 TVirtualMC::GetMC()->Gsvolu("Q05T", "TUBE", getMediumID(kFe), tubpar, 3);
892 TVirtualMC::GetMC()->Gspos("Q05T", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
893
894 zA += 2. * tubpar[2];
895
896 // TCDD ZONE - 6th volume
897 tubpar[0] = 13.8 / 2.;
898 tubpar[1] = 14.2 / 2.;
899 tubpar[2] = 38.6 / 2.;
900 TVirtualMC::GetMC()->Gsvolu("Q06T", "TUBE", getMediumID(kFe), tubpar, 3);
901 TVirtualMC::GetMC()->Gspos("Q06T", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
902
903 zA += 2. * tubpar[2];
904
905 // TCDD ZONE - 7th volume
906 conpar[0] = 11.34 / 2.;
907 conpar[1] = 13.8 / 2.;
908 conpar[2] = 14.2 / 2.;
909 conpar[3] = 18.0 / 2.;
910 conpar[4] = 18.4 / 2.;
911 TVirtualMC::GetMC()->Gsvolu("Q07T", "CONE", getMediumID(kFe), conpar, 5);
912 TVirtualMC::GetMC()->Gspos("Q07T", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
913
914 zA += 2. * conpar[0];
915
916 // Upper section : one single phi segment of a tube
917 // 5 parameters for tubs: inner radius = 0.,
918 // outer radius = 7. cm, half length = 50 cm
919 // phi1 = 0., phi2 = 180.
920 tubspar[0] = 0.0 / 2.;
921 tubspar[1] = 14.0 / 2.;
922 tubspar[2] = 100.0 / 2.;
923 tubspar[3] = 0.;
924 tubspar[4] = 180.;
925 TVirtualMC::GetMC()->Gsvolu("Q08T", "TUBS", getMediumID(kFe), tubspar, 5);
926
927 // rectangular beam pipe inside TCDD upper section (Vacuum)
928 boxpar[0] = 7.0 / 2.;
929 boxpar[1] = 2.2 / 2.;
930 boxpar[2] = 100. / 2.;
931 TVirtualMC::GetMC()->Gsvolu("Q09T", "BOX ", getMediumID(kVoidNoField), boxpar, 3);
932 // positioning vacuum box in the upper section of TCDD
933 TVirtualMC::GetMC()->Gspos("Q09T", 1, "Q08T", 0., 1.1, 0., 0, "ONLY");
934
935 // lower section : one single phi segment of a tube
936 tubspar[0] = 0.0 / 2.;
937 tubspar[1] = 14.0 / 2.;
938 tubspar[2] = 100.0 / 2.;
939 tubspar[3] = 180.;
940 tubspar[4] = 360.;
941 TVirtualMC::GetMC()->Gsvolu("Q10T", "TUBS", getMediumID(kFe), tubspar, 5);
942 // rectangular beam pipe inside TCDD lower section (Vacuum)
943 boxpar[0] = 7.0 / 2.;
944 boxpar[1] = 2.2 / 2.;
945 boxpar[2] = 100. / 2.;
946 TVirtualMC::GetMC()->Gsvolu("Q11T", "BOX ", getMediumID(kVoidNoField), boxpar, 3);
947 // positioning vacuum box in the lower section of TCDD
948 TVirtualMC::GetMC()->Gspos("Q11T", 1, "Q10T", 0., -1.1, 0., 0, "ONLY");
949
950 // positioning TCDD elements in ZDCA, (inside TCDD volume)
951 // TODO: think about making those parameters tunable/settable from outside
952 double TCDDAperturePos = 2.2;
953 double TCDDApertureNeg = 2.4;
954 TVirtualMC::GetMC()->Gspos("Q08T", 1, "ZDCA", 0., TCDDAperturePos, -100. + zA, 0, "ONLY");
955 TVirtualMC::GetMC()->Gspos("Q10T", 1, "ZDCA", 0., -TCDDApertureNeg, -100. + zA, 0, "ONLY");
956
957 // RF screen
958 boxpar[0] = 0.2 / 2.;
959 boxpar[1] = 4.0 / 2.;
960 boxpar[2] = 100. / 2.;
961 TVirtualMC::GetMC()->Gsvolu("Q12T", "BOX ", getMediumID(kFe), boxpar, 3);
962 // positioning RF screen at both sides of TCDD
963 TVirtualMC::GetMC()->Gspos("Q12T", 1, "ZDCA", tubspar[1] + boxpar[0], 0., -100. + zA, 0, "ONLY");
964 TVirtualMC::GetMC()->Gspos("Q12T", 2, "ZDCA", -tubspar[1] - boxpar[0], 0., -100. + zA, 0, "ONLY");
965 //---------------------------- TCDD end ---------------------------------------
966
967 // The following elliptical tube 180 mm x 70 mm (obtained positioning the void QA06 in QA07)
968 // represents VAMTF + first part of VCTCP (93 mm)
969
970 tubpar[0] = 18.4 / 2.;
971 tubpar[1] = 7.4 / 2.;
972 tubpar[2] = (78 + 9.3) / 2.;
973 TVirtualMC::GetMC()->Gsvolu("QA06", "ELTU", getMediumID(kFe), tubpar, 3);
974 // AliRoot: temporary replace with a scaled tube (AG) ????????????
975 /*TGeoTube *tubeQA06 = new TGeoTube(0.,tubpar[0],tubpar[2]);
976 TGeoScale *scaleQA06 = new TGeoScale(1., tubpar[1]/tubpar[0], 1.);
977 TGeoScaledShape *sshapeQA06 = new TGeoScaledShape(tubeQA06, scaleQA06);
978 new TGeoVolume("QA06", sshapeQA06, gGeoManager->GetMedium(getMediumID(kVoidNoField)));*/
979
980 tubpar[0] = 18.0 / 2.;
981 tubpar[1] = 7.0 / 2.;
982 tubpar[2] = (78 + 9.3) / 2.;
983 TVirtualMC::GetMC()->Gsvolu("QA07", "ELTU", getMediumID(kVoidNoField), tubpar, 3);
984 // temporary replace with a scaled tube (AG) ????????????
985 /*TGeoTube *tubeQA07 = new TGeoTube(0.,tubpar[0],tubpar[2]);
986 TGeoScale *scaleQA07 = new TGeoScale(1., tubpar[1]/tubpar[0], 1.);
987 TGeoScaledShape *sshapeQA07 = new TGeoScaledShape(tubeQA07, scaleQA07);
988 new TGeoVolume("QA07", sshapeQA07, gGeoManager->GetMedium(getMediumID(k10]));*/
989 TVirtualMC::GetMC()->Gspos("QA06", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
990 TVirtualMC::GetMC()->Gspos("QA07", 1, "QA06", 0., 0., 0., 0, "ONLY");
991
992 zA += 2. * tubpar[2];
993
994 // VCTCP second part: transition cone from ID=180 to ID=212.7
995 conpar[0] = 31.5 / 2.;
996 conpar[1] = 18.0 / 2.;
997 conpar[2] = 18.6 / 2.;
998 conpar[3] = 21.27 / 2.;
999 conpar[4] = 21.87 / 2.;
1000 TVirtualMC::GetMC()->Gsvolu("QA08", "CONE", getMediumID(kFe), conpar, 5);
1001 TVirtualMC::GetMC()->Gspos("QA08", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
1002
1003 zA += 2. * conpar[0];
1004
1005 //-- rotation matrices for the tilted cone after the TDI to recenter vacuum chamber
1006 int32_t irotpipe3, irotpipe4, irotpipe5;
1007 double rang3[6] = {90. - 1.8934, 0., 90., 90., 1.8934, 180.};
1008 double rang4[6] = {90. - 3.8, 0., 90., 90., 3.8, 180.};
1009 double rang5[6] = {90. + 9.8, 0., 90., 90., 9.8, 0.};
1010 TVirtualMC::GetMC()->Matrix(irotpipe3, rang3[0], rang3[1], rang3[2], rang3[3], rang3[4], rang3[5]);
1011 TVirtualMC::GetMC()->Matrix(irotpipe4, rang4[0], rang4[1], rang4[2], rang4[3], rang4[4], rang4[5]);
1012 TVirtualMC::GetMC()->Matrix(irotpipe5, rang5[0], rang5[1], rang5[2], rang5[3], rang5[4], rang5[5]);
1013
1014 // Tube ID 212.7 mm
1015 // Represents VCTCP third part (92 mm) + VCDWB (765 mm) + VMBGA (400 mm) +
1016 // VCDWE (300 mm) + VMBGA (400 mm) + TCTVB space + VAMTF space
1017 tubpar[0] = 21.27 / 2.;
1018 tubpar[1] = 21.87 / 2.;
1019 tubpar[2] = (195.7 + 148. + 78.) / 2.;
1020 TVirtualMC::GetMC()->Gsvolu("QA09", "TUBE", getMediumID(kFe), tubpar, 3);
1021 TVirtualMC::GetMC()->Gspos("QA09", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1022
1023 zA += 2. * tubpar[2];
1024
1025 // skewed transition piece (ID=212.7 mm to 332 mm) (before TDI)
1026 conpar[0] = (50.0 - 0.73 - 1.13) / 2.;
1027 conpar[1] = 21.27 / 2.;
1028 conpar[2] = 21.87 / 2.;
1029 conpar[3] = 33.2 / 2.;
1030 conpar[4] = 33.8 / 2.;
1031 TVirtualMC::GetMC()->Gsvolu("QA10", "CONE", getMediumID(kFe), conpar, 5);
1032 TVirtualMC::GetMC()->Gspos("QA10", 1, "ZDCA", -1.66, 0., conpar[0] + 0.73 + zA, irotpipe4, "ONLY");
1033
1034 zA += 2. * conpar[0] + 0.73 + 1.13;
1035
1036 // Vacuum chamber containing TDI
1037 tubpar[0] = 0.;
1038 tubpar[1] = 54.6 / 2.;
1039 tubpar[2] = 540.0 / 2.;
1040 TVirtualMC::GetMC()->Gsvolu("Q13TM", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1041 TVirtualMC::GetMC()->Gspos("Q13TM", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1042 tubpar[0] = 54.0 / 2.;
1043 tubpar[1] = 54.6 / 2.;
1044 tubpar[2] = 540.0 / 2.;
1045 TVirtualMC::GetMC()->Gsvolu("Q13T", "TUBE", getMediumID(kFe), tubpar, 3);
1046 TVirtualMC::GetMC()->Gspos("Q13T", 1, "Q13TM", 0., 0., 0., 0, "ONLY");
1047
1048 zA += 2. * tubpar[2];
1049
1050 //---------------- INSERT TDI INSIDE Q13T -----------------------------------
1051 boxpar[0] = 11.0 / 2.;
1052 boxpar[1] = 9.0 / 2.;
1053 boxpar[2] = 418.5 / 2.;
1054 double TDIAperturePos = 6.;
1055 TVirtualMC::GetMC()->Gsvolu("QTD1", "BOX ", getMediumID(kFe), boxpar, 3);
1056 TVirtualMC::GetMC()->Gspos("QTD1", 1, "Q13TM", -3.8, boxpar[1] + TDIAperturePos, 0., 0, "ONLY");
1057 boxpar[0] = 11.0 / 2.;
1058 boxpar[1] = 9.0 / 2.;
1059 boxpar[2] = 418.5 / 2.;
1060 TVirtualMC::GetMC()->Gsvolu("QTD2", "BOX ", getMediumID(kFe), boxpar, 3);
1061 double TDIApertureNeg = 6.;
1062 TVirtualMC::GetMC()->Gspos("QTD2", 1, "Q13TM", -3.8, -boxpar[1] - TDIApertureNeg, 0., 0, "ONLY");
1063 boxpar[0] = 5.1 / 2.;
1064 boxpar[1] = 0.2 / 2.;
1065 boxpar[2] = 418.5 / 2.;
1066 TVirtualMC::GetMC()->Gsvolu("QTD3", "BOX ", getMediumID(kFe), boxpar, 3);
1067 TVirtualMC::GetMC()->Gspos("QTD3", 1, "Q13TM", -3.8 + 5.5 + boxpar[0], TDIAperturePos, 0., 0, "ONLY");
1068 TVirtualMC::GetMC()->Gspos("QTD3", 2, "Q13TM", -3.8 + 5.5 + boxpar[0], -TDIApertureNeg, 0., 0, "ONLY");
1069 TVirtualMC::GetMC()->Gspos("QTD3", 3, "Q13TM", -3.8 - 5.5 - boxpar[0], TDIAperturePos, 0., 0, "ONLY");
1070 TVirtualMC::GetMC()->Gspos("QTD3", 4, "Q13TM", -3.8 - 5.5 - boxpar[0], -TDIApertureNeg, 0., 0, "ONLY");
1071 //
1072 tubspar[0] = 12.0 / 2.;
1073 tubspar[1] = 12.4 / 2.;
1074 tubspar[2] = 418.5 / 2.;
1075 tubspar[3] = 90.;
1076 tubspar[4] = 270.;
1077 TVirtualMC::GetMC()->Gsvolu("QTD4", "TUBS", getMediumID(kCu), tubspar, 5);
1078 TVirtualMC::GetMC()->Gspos("QTD4", 1, "Q13TM", -3.8 - 10.6, 0., 0., 0, "ONLY");
1079 tubspar[0] = 12.0 / 2.;
1080 tubspar[1] = 12.4 / 2.;
1081 tubspar[2] = 418.5 / 2.;
1082 tubspar[3] = -90.;
1083 tubspar[4] = 90.;
1084 TVirtualMC::GetMC()->Gsvolu("QTD5", "TUBS", getMediumID(kCu), tubspar, 5);
1085 TVirtualMC::GetMC()->Gspos("QTD5", 1, "Q13TM", -3.8 + 10.6, 0., 0., 0, "ONLY");
1086 //---------------- END DEFINING TDI INSIDE Q13T -------------------------------
1087
1088 // VCTCG skewed transition piece (ID=332 mm to 212.7 mm) (after TDI)
1089 conpar[0] = (50.0 - 2.92 - 1.89) / 2.;
1090 conpar[1] = 33.2 / 2.;
1091 conpar[2] = 33.8 / 2.;
1092 conpar[3] = 21.27 / 2.;
1093 conpar[4] = 21.87 / 2.;
1094 TVirtualMC::GetMC()->Gsvolu("QA11", "CONE", getMediumID(kFe), conpar, 5);
1095 TVirtualMC::GetMC()->Gspos("QA11", 1, "ZDCA", 4.32 - 3.8, 0., conpar[0] + 2.92 + zA, irotpipe5, "ONLY");
1096
1097 zA += 2. * conpar[0] + 2.92 + 1.89;
1098
1099 // The following tube ID 212.7 mm
1100 // represents VMBGA (400 mm) + VCDWE (300 mm) + VMBGA (400 mm) +
1101 // BTVTS (600 mm) + VMLGB (400 mm)
1102 tubpar[0] = 21.27 / 2.;
1103 tubpar[1] = 21.87 / 2.;
1104 tubpar[2] = 210.0 / 2.;
1105 TVirtualMC::GetMC()->Gsvolu("QA12", "TUBE", getMediumID(kFe), tubpar, 3);
1106 TVirtualMC::GetMC()->Gspos("QA12", 1, "ZDCA", 4., 0., tubpar[2] + zA, 0, "ONLY");
1107
1108 zA += 2. * tubpar[2];
1109
1110 // First part of VCTCC
1111 // skewed transition cone from ID=212.7 mm to ID=797 mm
1112 conpar[0] = (121.0 - 0.37 - 1.35) / 2.;
1113 conpar[1] = 21.27 / 2.;
1114 conpar[2] = 21.87 / 2.;
1115 conpar[3] = 79.7 / 2.;
1116 conpar[4] = 81.3 / 2.;
1117 TVirtualMC::GetMC()->Gsvolu("QA13", "CONE", getMediumID(kFe), conpar, 5);
1118 TVirtualMC::GetMC()->Gspos("QA13", 1, "ZDCA", 4. - 2., 0., conpar[0] + 0.37 + zA, irotpipe3, "ONLY");
1119
1120 zA += 2. * conpar[0] + 0.37 + 1.35;
1121
1122 // The following tube ID 797 mm represents the second part of VCTCC (4272 mm) +
1123 // 4 x VCDGA (4 x 4272 mm) + the first part of VCTCR (850 mm)
1124 tubpar[0] = 79.7 / 2.;
1125 tubpar[1] = 81.3 / 2.;
1126 tubpar[2] = (2221. - 136.) / 2.;
1127 TVirtualMC::GetMC()->Gsvolu("QA14", "TUBE", getMediumID(kFe), tubpar, 3);
1128 TVirtualMC::GetMC()->Gspos("QA14", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1129
1130 zA += 2. * tubpar[2];
1131
1132 // Second part of VCTCR
1133 // Transition from ID=797 mm to ID=196 mm. To simulate the thin window opened in the transition cone
1134 // we divide the transition cone in three cones:
1135 // (1) 8 mm thick (2) 3 mm thick (3) the third 8 mm thick
1136
1137 // (1) 8 mm thick
1138 conpar[0] = 9.09 / 2.; // 15 degree
1139 conpar[1] = 79.7 / 2.;
1140 conpar[2] = 81.3 / 2.; // thickness 8 mm
1141 conpar[3] = 74.82868 / 2.;
1142 conpar[4] = 76.42868 / 2.; // thickness 8 mm
1143 TVirtualMC::GetMC()->Gsvolu("QA15", "CONE", getMediumID(kFe), conpar, 5);
1144 TVirtualMC::GetMC()->Gspos("QA15", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
1145
1146 zA += 2. * conpar[0];
1147
1148 // (2) 3 mm thick
1149 conpar[0] = 96.2 / 2.; // 15 degree
1150 conpar[1] = 74.82868 / 2.;
1151 conpar[2] = 75.42868 / 2.; // thickness 3 mm
1152 conpar[3] = 23.19588 / 2.;
1153 conpar[4] = 23.79588 / 2.; // thickness 3 mm
1154 TVirtualMC::GetMC()->Gsvolu("QA16", "CONE", getMediumID(kFe), conpar, 5);
1155 TVirtualMC::GetMC()->Gspos("QA16", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
1156
1157 zA += 2. * conpar[0];
1158
1159 // (3) 8 mm thick
1160 conpar[0] = 6.71 / 2.; // 15 degree
1161 conpar[1] = 23.19588 / 2.;
1162 conpar[2] = 24.79588 / 2.; // thickness 8 mm
1163 conpar[3] = 19.6 / 2.;
1164 conpar[4] = 21.2 / 2.; // thickness 8 mm
1165 TVirtualMC::GetMC()->Gsvolu("QA17", "CONE", getMediumID(kFe), conpar, 5);
1166 TVirtualMC::GetMC()->Gspos("QA17", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
1167
1168 zA += 2. * conpar[0];
1169
1170 // Third part of VCTCR: tube (ID=196 mm)
1171 tubpar[0] = 19.6 / 2.;
1172 tubpar[1] = 21.2 / 2.;
1173 tubpar[2] = 9.55 / 2.;
1174 TVirtualMC::GetMC()->Gsvolu("QA18", "TUBE", getMediumID(kFe), tubpar, 3);
1175 TVirtualMC::GetMC()->Gspos("QA18", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1176
1177 zA += 2. * tubpar[2];
1178
1179 // Flange (ID=196 mm) (last part of VCTCR and first part of VMZAR)
1180 tubpar[0] = 19.6 / 2.;
1181 tubpar[1] = 25.3 / 2.;
1182 tubpar[2] = 4.9 / 2.;
1183 TVirtualMC::GetMC()->Gsvolu("QF01", "TUBE", getMediumID(kFe), tubpar, 3);
1184 TVirtualMC::GetMC()->Gspos("QF01", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1185
1186 zA += 2. * tubpar[2];
1187
1188 // VMZAR (5 volumes)
1189 tubpar[0] = 20.2 / 2.;
1190 tubpar[1] = 20.6 / 2.;
1191 tubpar[2] = 2.15 / 2.;
1192 TVirtualMC::GetMC()->Gsvolu("QA19", "TUBE", getMediumID(kFe), tubpar, 3);
1193 TVirtualMC::GetMC()->Gspos("QA19", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1194
1195 zA += 2. * tubpar[2];
1196
1197 conpar[0] = 6.9 / 2.;
1198 conpar[1] = 20.2 / 2.;
1199 conpar[2] = 20.6 / 2.;
1200 conpar[3] = 23.9 / 2.;
1201 conpar[4] = 24.3 / 2.;
1202 TVirtualMC::GetMC()->Gsvolu("QA20", "CONE", getMediumID(kFe), conpar, 5);
1203 TVirtualMC::GetMC()->Gspos("QA20", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
1204
1205 zA += 2. * conpar[0];
1206
1207 tubpar[0] = 23.9 / 2.;
1208 tubpar[1] = 25.5 / 2.;
1209 tubpar[2] = 17.0 / 2.;
1210 TVirtualMC::GetMC()->Gsvolu("QA21", "TUBE", getMediumID(kFe), tubpar, 3);
1211 TVirtualMC::GetMC()->Gspos("QA21", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1212
1213 zA += 2. * tubpar[2];
1214
1215 conpar[0] = 6.9 / 2.;
1216 conpar[1] = 23.9 / 2.;
1217 conpar[2] = 24.3 / 2.;
1218 conpar[3] = 20.2 / 2.;
1219 conpar[4] = 20.6 / 2.;
1220 TVirtualMC::GetMC()->Gsvolu("QA22", "CONE", getMediumID(kFe), conpar, 5);
1221 TVirtualMC::GetMC()->Gspos("QA22", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
1222
1223 zA += 2. * conpar[0];
1224
1225 tubpar[0] = 20.2 / 2.;
1226 tubpar[1] = 20.6 / 2.;
1227 tubpar[2] = 2.15 / 2.;
1228 TVirtualMC::GetMC()->Gsvolu("QA23", "TUBE", getMediumID(kFe), tubpar, 3);
1229 TVirtualMC::GetMC()->Gspos("QA23", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1230
1231 zA += 2. * tubpar[2];
1232
1233 // Flange (ID=196 mm)(last part of VMZAR and first part of VCTYD)
1234 tubpar[0] = 19.6 / 2.;
1235 tubpar[1] = 25.3 / 2.;
1236 tubpar[2] = 4.9 / 2.;
1237 TVirtualMC::GetMC()->Gsvolu("QF02", "TUBE", getMediumID(kFe), tubpar, 3);
1238 TVirtualMC::GetMC()->Gspos("QF02", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1239
1240 zA += 2. * tubpar[2];
1241
1242 // simulation of the trousers (VCTYB)
1243 tubpar[0] = 19.6 / 2.;
1244 tubpar[1] = 20.0 / 2.;
1245 tubpar[2] = 3.9 / 2.;
1246 TVirtualMC::GetMC()->Gsvolu("QA24", "TUBE", getMediumID(kFe), tubpar, 3);
1247 TVirtualMC::GetMC()->Gspos("QA24", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1248
1249 zA += 2. * tubpar[2];
1250
1251 // transition cone from ID=196. to ID=216.6
1252 conpar[0] = 32.55 / 2.;
1253 conpar[1] = 19.6 / 2.;
1254 conpar[2] = 20.0 / 2.;
1255 conpar[3] = 21.66 / 2.;
1256 conpar[4] = 22.06 / 2.;
1257 TVirtualMC::GetMC()->Gsvolu("QA25", "CONE", getMediumID(kFe), conpar, 5);
1258 TVirtualMC::GetMC()->Gspos("QA25", 1, "ZDCA", 0., 0., conpar[0] + zA, 0, "ONLY");
1259
1260 zA += 2. * conpar[0];
1261
1262 // tube
1263 tubpar[0] = 21.66 / 2.;
1264 tubpar[1] = 22.06 / 2.;
1265 tubpar[2] = 28.6 / 2.;
1266 TVirtualMC::GetMC()->Gsvolu("QA26", "TUBE", getMediumID(kFe), tubpar, 3);
1267 TVirtualMC::GetMC()->Gspos("QA26", 1, "ZDCA", 0., 0., tubpar[2] + zA, 0, "ONLY");
1268
1269 zA += 2. * tubpar[2];
1270
1271 // --------------------------------------------------------
1272 // RECOMBINATION CHAMBER
1273 // TRANSFORMATION MATRICES
1274 double dx = -3.970000;
1275 double dy = 0.000000;
1276 double dz = 0.0;
1277 // Rotation:
1278 double thx = 84.989100;
1279 double phx = 0.000000;
1280 double thy = 90.000000;
1281 double phy = 90.000000;
1282 double thz = 5.010900;
1283 double phz = 180.000000;
1284 TGeoRotation* rotMatrix1 = new TGeoRotation("", thx, phx, thy, phy, thz, phz);
1285 // Combi transformation:
1286 TGeoCombiTrans* rotMatrix2 = new TGeoCombiTrans("ZDC_c1", dx, dy, dz, rotMatrix1);
1287 rotMatrix2->RegisterYourself();
1288 // Combi transformation:
1289 // Rotation:
1290 double thx3 = 95.010900;
1291 double phx3 = 0.000000;
1292 double thy3 = 90.000000;
1293 double phy3 = 90.000000;
1294 double thz3 = 5.010900;
1295 double phz3 = 0.000000;
1296 TGeoRotation* rotMatrix3 = new TGeoRotation("", thx3, phx3, thy3, phy3, thz3, phz3);
1297 TGeoCombiTrans* rotMatrix4 = new TGeoCombiTrans("ZDC_c2", -dx, dy, dz, rotMatrix3);
1298 rotMatrix4->RegisterYourself();
1299
1300 //-- rotation matrices for the legs
1301 int32_t irotpipe1, irotpipe2;
1302 double rang1[6] = {90. - 1.0027, 0., 90., 90., 1.0027, 180.};
1303 double rang2[6] = {90. + 1.0027, 0., 90., 90., 1.0027, 0.};
1304 TVirtualMC::GetMC()->Matrix(irotpipe1, rang1[0], rang1[1], rang1[2], rang1[3], rang1[4], rang1[5]);
1305 TVirtualMC::GetMC()->Matrix(irotpipe2, rang2[0], rang2[1], rang2[2], rang2[3], rang2[4], rang2[5]);
1306
1307 // VOLUMES DEFINITION
1308 // Volume: ZDCA
1309 TGeoVolume* pZDCA = gGeoManager->GetVolume("ZDCA");
1310
1311 conpar[0] = (90.1 - 0.95 - 0.26) / 2.;
1312 conpar[1] = 0.0 / 2.;
1313 conpar[2] = 21.6 / 2.;
1314 conpar[3] = 0.0 / 2.;
1315 conpar[4] = 5.8 / 2.;
1316 new TGeoCone("QALext", conpar[0], conpar[1], conpar[2], conpar[3], conpar[4]);
1317
1318 conpar[0] = (90.1 - 0.95 - 0.26) / 2.;
1319 conpar[1] = 0.0 / 2.;
1320 conpar[2] = 21.2 / 2.;
1321 conpar[3] = 0.0 / 2.;
1322 conpar[4] = 5.4 / 2.;
1323 new TGeoCone("QALint", conpar[0], conpar[1], conpar[2], conpar[3], conpar[4]);
1324
1325 // Outer trousers
1326 TGeoCompositeShape* pOutTrousers = new TGeoCompositeShape("outTrousers", "QALext:ZDC_c1+QALext:ZDC_c2");
1327
1328 auto& matmgr = o2::base::MaterialManager::Instance();
1329
1330 // Volume: QALext
1331 TGeoVolume* pQALext = new TGeoVolume("QALext", pOutTrousers, matmgr.getTGeoMedium("ZDC", kFeLowTh));
1332 pQALext->SetLineColor(kBlue);
1333 pQALext->SetVisLeaves(kTRUE);
1334 //
1335 TGeoTranslation* tr1 = new TGeoTranslation(0., 0., (double)conpar[0] + 0.95 + zA);
1336 pZDCA->AddNode(pQALext, 1, tr1);
1337 // Inner trousers
1338 TGeoCompositeShape* pIntTrousers = new TGeoCompositeShape("intTrousers", "QALint:ZDC_c1+QALint:ZDC_c2");
1339 // Volume: QALint
1340 TGeoVolume* pQALint = new TGeoVolume("QALint", pIntTrousers, matmgr.getTGeoMedium("ZDC", kVoidNoField));
1341 pQALint->SetLineColor(kAzure);
1342 pQALint->SetVisLeaves(kTRUE);
1343 pQALext->AddNode(pQALint, 1);
1344
1345 zA += 90.1;
1346
1347 // second section : 2 tubes (ID = 54. OD = 58.)
1348 tubpar[0] = 5.4 / 2.;
1349 tubpar[1] = 5.8 / 2.;
1350 tubpar[2] = 40.0 / 2.;
1351 TVirtualMC::GetMC()->Gsvolu("QA27", "TUBE", getMediumID(kFe), tubpar, 3);
1352 TVirtualMC::GetMC()->Gspos("QA27", 1, "ZDCA", -15.8 / 2., 0., tubpar[2] + zA, 0, "ONLY");
1353 TVirtualMC::GetMC()->Gspos("QA27", 2, "ZDCA", 15.8 / 2., 0., tubpar[2] + zA, 0, "ONLY");
1354
1355 zA += 2. * tubpar[2];
1356
1357 // transition x2zdc to recombination chamber : skewed cone
1358 conpar[0] = (10. - 1.) / 2.;
1359 conpar[1] = 5.4 / 2.;
1360 conpar[2] = 5.8 / 2.;
1361 conpar[3] = 6.3 / 2.;
1362 conpar[4] = 7.0 / 2.;
1363 TVirtualMC::GetMC()->Gsvolu("QA28", "CONE", getMediumID(kFe), conpar, 5);
1364 TVirtualMC::GetMC()->Gspos("QA28", 1, "ZDCA", -7.9 - 0.175, 0., conpar[0] + 0.5 + zA, irotpipe1, "ONLY");
1365 TVirtualMC::GetMC()->Gspos("QA28", 2, "ZDCA", 7.9 + 0.175, 0., conpar[0] + 0.5 + zA, irotpipe2, "ONLY");
1366
1367 zA += 2. * conpar[0] + 1.;
1368
1369 // 2 tubes (ID = 63 mm OD=70 mm)
1370 tubpar[0] = 6.3 / 2.;
1371 tubpar[1] = 7.0 / 2.;
1372 tubpar[2] = (342.5 + 498.3) / 2.;
1373 TVirtualMC::GetMC()->Gsvolu("QA29", "TUBE", getMediumID(kFe), tubpar, 3);
1374 TVirtualMC::GetMC()->Gspos("QA29", 1, "ZDCA", -16.5 / 2., 0., tubpar[2] + zA, 0, "ONLY");
1375 TVirtualMC::GetMC()->Gspos("QA29", 2, "ZDCA", 16.5 / 2., 0., tubpar[2] + zA, 0, "ONLY");
1376 //printf("QA29 TUBE from z = %1.2f to z= %1.2f (separate pipes)\n",zA,2*tubpar[2]+zA);
1377
1378 zA += 2. * tubpar[2];
1379
1380 // -- Luminometer (Cu box) in front of ZN - side A
1381 if (mLumiLength > 0.) { // FIX IT!!!!!!!!!!!!!!!
1382 boxpar[0] = 8.0 / 2.;
1383 boxpar[1] = 8.0 / 2.;
1384 boxpar[2] = mLumiLength / 2.;
1385 TVirtualMC::GetMC()->Gsvolu("QLUA", "BOX ", getMediumID(kCuLumi), boxpar, 3);
1386 TVirtualMC::GetMC()->Gspos("QLUA", 1, "ZDCA", 0., 0., Geometry::ZNAPOSITION[1] /*fPosZNA[2]*/ - 66. - boxpar[2], 0, "ONLY");
1387 LOG(debug) << "A-side luminometer positioned in front of ZNA\n";
1388 }
1389}
1390
1391//_____________________________________________________________________________
1392void Detector::createCsideBeamLine()
1393{
1394 double tubpar[3] = {0., 0., 0};
1395 float boxpar[3] = {0., 0., 0};
1396 double tubspar[5] = {0., 0., 0., 0., 0.};
1397 double conpar[15] = {
1398 0.,
1399 };
1400
1401 float zC = 1947.2;
1402 float zCompensator = 1974.;
1403
1404 conpar[0] = 0.;
1405 conpar[1] = 360.;
1406 conpar[2] = 4.; // Num radius specifications: 4
1407 conpar[3] = -13500.;
1408 conpar[4] = 0.;
1409 conpar[5] = 55.;
1410 conpar[6] = -zCompensator;
1411 conpar[7] = 0.;
1412 conpar[8] = 55.;
1413 conpar[9] = -zCompensator;
1414 conpar[10] = 0.;
1415 conpar[11] = 6.7 / 2.;
1416 conpar[12] = -zC; // (4) Beginning of ZDCC mother volume
1417 conpar[13] = 0.;
1418 conpar[14] = 6.7 / 2.;
1419 TVirtualMC::GetMC()->Gsvolu("ZDCC", "PCON", getMediumID(kVoidNoField), conpar, 15);
1420 TVirtualMC::GetMC()->Gspos("ZDCC", 1, "cave", 0., 0., 0., 0, "ONLY");
1421
1422 // -- BEAM PIPE from compensator dipole to the beginning of D1
1423 tubpar[0] = 6.3 / 2.;
1424 tubpar[1] = 6.7 / 2.;
1425 // From beginning of ZDC volumes to beginning of D1
1426 tubpar[2] = (5838.3 - zC) / 2.;
1427 TVirtualMC::GetMC()->Gsvolu("QT01", "TUBE", getMediumID(kFe), tubpar, 3);
1428 TVirtualMC::GetMC()->Gspos("QT01", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1429
1430 zC += 2. * tubpar[2];
1431
1432 //-- BEAM PIPE from the end of D1 to the beginning of D2
1433 //-- FROM MAGNETIC BEGINNING OF D1 TO MAGNETIC END OF D1
1434 //-- Cylindrical pipe (r = 3.47) + conical flare
1435 tubpar[0] = 6.94 / 2.;
1436 tubpar[1] = 7.34 / 2.;
1437 tubpar[2] = (6909.8 - zC) / 2.;
1438 TVirtualMC::GetMC()->Gsvolu("QT02", "TUBE", getMediumID(kFe), tubpar, 3);
1439 TVirtualMC::GetMC()->Gspos("QT02", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1440
1441 zC += 2. * tubpar[2];
1442
1443 tubpar[0] = 8. / 2.;
1444 tubpar[1] = 8.6 / 2.;
1445 tubpar[2] = (6958.3 - zC) / 2.;
1446 TVirtualMC::GetMC()->Gsvolu("QT0B", "TUBE", getMediumID(kFe), tubpar, 3);
1447 TVirtualMC::GetMC()->Gspos("QT0B", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1448
1449 zC += 2. * tubpar[2];
1450
1451 tubpar[0] = 9. / 2.;
1452 tubpar[1] = 9.6 / 2.;
1453 tubpar[2] = (7022.8 - zC) / 2.;
1454 TVirtualMC::GetMC()->Gsvolu("QT03", "TUBE", getMediumID(kFe), tubpar, 3);
1455 TVirtualMC::GetMC()->Gspos("QT03", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1456
1457 zC += 2. * tubpar[2];
1458
1459 conpar[0] = 39.2 / 2.;
1460 conpar[1] = 18. / 2.;
1461 conpar[2] = 18.6 / 2.;
1462 conpar[3] = 9. / 2.;
1463 conpar[4] = 9.6 / 2.;
1464 TVirtualMC::GetMC()->Gsvolu("QC01", "CONE", getMediumID(kFe), conpar, 5);
1465 TVirtualMC::GetMC()->Gspos("QC01", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1466
1467 zC += conpar[0] * 2.;
1468
1469 // 2nd section of VCTCQ+VAMTF+TCLIA+VAMTF+1st part of VCTCP
1470 float totLength1 = 160.8 + 78. + 148. + 78. + 9.3;
1471 //
1472 tubpar[0] = 18.6 / 2.;
1473 tubpar[1] = 7.6 / 2.;
1474 tubpar[2] = totLength1 / 2.;
1475 TVirtualMC::GetMC()->Gsvolu("QE01", "ELTU", getMediumID(kFe), tubpar, 3);
1476 // in AliRoot: temporary replace with a scaled tube (AG) ??????????
1477 /*TGeoTube *tubeQE01 = new TGeoTube(0.,tubpar[0],tubpar[2]);
1478 TGeoScale *scaleQE01 = new TGeoScale(1., tubpar[1]/tubpar[0], 1.);
1479 TGeoScaledShape *sshapeQE01 = new TGeoScaledShape(tubeQE01, scaleQE01);
1480 new TGeoVolume("QE01", sshapeQE01, gGeoManager->GetMedium(getMediumID(kVoidNoField)));*/
1481
1482 tubpar[0] = 18.0 / 2.;
1483 tubpar[1] = 7.0 / 2.;
1484 tubpar[2] = totLength1 / 2.;
1485 TVirtualMC::GetMC()->Gsvolu("QE02", "ELTU", getMediumID(kVoidNoField), tubpar, 3);
1486 // in AliRoot: temporary replace with a scaled tube (AG) ??????????
1487 /*TGeoTube *tubeQE02 = new TGeoTube(0.,tubpar[0],tubpar[2]);
1488 TGeoScale *scaleQE02 = new TGeoScale(1., tubpar[1]/tubpar[0], 1.);
1489 TGeoScaledShape *sshapeQE02 = new TGeoScaledShape(tubeQE02, scaleQE02);
1490 new TGeoVolume("QE02", sshapeQE02, gGeoManager->GetMedium(getMediumID(k10]));*/
1491
1492 TVirtualMC::GetMC()->Gspos("QE01", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1493 TVirtualMC::GetMC()->Gspos("QE02", 1, "QE01", 0., 0., 0., 0, "ONLY");
1494
1495 // TCLIA collimator jaws (defined ONLY if aperture<3.5!)
1496 if (mTCLIAAPERTURE < 3.5) {
1497 boxpar[0] = 5.4 / 2.;
1498 boxpar[1] = (3.5 - mTCLIAAPERTURE - mVCollSideCCentreY - 0.7) / 2.; // FIX IT!!!!!!!!
1499 if (boxpar[1] < 0.) {
1500 boxpar[1] = 0.;
1501 }
1502 boxpar[2] = 124.4 / 2.;
1503 TVirtualMC::GetMC()->Gsvolu("QCVC", "BOX ", getMediumID(kGraphite), boxpar, 3);
1504 TVirtualMC::GetMC()->Gspos("QCVC", 1, "QE02", -boxpar[0], mTCLIAAPERTURE + mVCollSideCCentreY + boxpar[1], -totLength1 / 2. + 160.8 + 78. + 148. / 2., 0, "ONLY"); // FIX IT!!!!!!!!
1505 TVirtualMC::GetMC()->Gspos("QCVC", 2, "QE02", -boxpar[0], -mTCLIAAPERTURENEG + mVCollSideCCentreY - boxpar[1], -totLength1 / 2. + 160.8 + 78. + 148. / 2., 0, "ONLY"); // FIX IT!!!!!!!!
1506 }
1507
1508 zC += tubpar[2] * 2.;
1509
1510 // 2nd part of VCTCP
1511 conpar[0] = 31.5 / 2.;
1512 conpar[1] = 21.27 / 2.;
1513 conpar[2] = 21.87 / 2.;
1514 conpar[3] = 18.0 / 2.;
1515 conpar[4] = 18.6 / 2.;
1516 TVirtualMC::GetMC()->Gsvolu("QC02", "CONE", getMediumID(kFe), conpar, 5);
1517 TVirtualMC::GetMC()->Gspos("QC02", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1518
1519 zC += conpar[0] * 2.;
1520
1521 // 3rd section of VCTCP+VCDWC+VMLGB
1522 float totLenght2 = (8373.3 - zC);
1523 tubpar[0] = 21.2 / 2.;
1524 tubpar[1] = 21.9 / 2.;
1525 tubpar[2] = totLenght2 / 2.;
1526 TVirtualMC::GetMC()->Gsvolu("QT04", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1527 TVirtualMC::GetMC()->Gspos("QT04", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1528
1529 zC += tubpar[2] * 2.;
1530
1531 // First part of VCTCD
1532 // skewed transition cone from ID=212.7 mm to ID=797 mm
1533 conpar[0] = 121. / 2.;
1534 conpar[1] = 79.7 / 2.;
1535 conpar[2] = 81.3 / 2.;
1536 conpar[3] = 21.27 / 2.;
1537 conpar[4] = 21.87 / 2.;
1538 TVirtualMC::GetMC()->Gsvolu("QC03", "CONE", getMediumID(kVoidNoField), conpar, 5);
1539 TVirtualMC::GetMC()->Gspos("QC03", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1540
1541 zC += 2. * conpar[0];
1542
1543 // VCDGB + 1st part of VCTCH
1544 tubpar[0] = 79.7 / 2.;
1545 tubpar[1] = 81.3 / 2.;
1546 tubpar[2] = (5 * 475.2 + 97. - 136) / 2.;
1547 TVirtualMC::GetMC()->Gsvolu("QT05", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1548 TVirtualMC::GetMC()->Gspos("QT05", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1549
1550 zC += 2. * tubpar[2];
1551
1552 // 2nd part of VCTCH
1553 // Transition from ID=797 mm to ID=196 mm:
1554 // in order to simulate the thin window opened in the transition cone
1555 // we divide the transition cone in three cones:
1556 // (1) 8 mm thick (2) 3 mm thick (3) the third 8 mm thick
1557
1558 // (1) 8 mm thick
1559 conpar[0] = 9.09 / 2.; // 15 degree
1560 conpar[1] = 74.82868 / 2.;
1561 conpar[2] = 76.42868 / 2.; // thickness 8 mm
1562 conpar[3] = 79.7 / 2.;
1563 conpar[4] = 81.3 / 2.; // thickness 8 mm
1564 TVirtualMC::GetMC()->Gsvolu("QC04", "CONE", getMediumID(kVoidNoField), conpar, 5);
1565 TVirtualMC::GetMC()->Gspos("QC04", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1566
1567 zC += 2. * conpar[0];
1568
1569 // (2) 3 mm thick
1570 conpar[0] = 96.2 / 2.; // 15 degree
1571 conpar[1] = 23.19588 / 2.;
1572 conpar[2] = 23.79588 / 2.; // thickness 3 mm
1573 conpar[3] = 74.82868 / 2.;
1574 conpar[4] = 75.42868 / 2.; // thickness 3 mm
1575 TVirtualMC::GetMC()->Gsvolu("QC05", "CONE", getMediumID(kVoidNoField), conpar, 5);
1576 TVirtualMC::GetMC()->Gspos("QC05", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1577
1578 zC += 2. * conpar[0];
1579
1580 // (3) 8 mm thick
1581 conpar[0] = 6.71 / 2.; // 15 degree
1582 conpar[1] = 19.6 / 2.;
1583 conpar[2] = 21.2 / 2.; // thickness 8 mm
1584 conpar[3] = 23.19588 / 2.;
1585 conpar[4] = 24.79588 / 2.; // thickness 8 mm
1586 TVirtualMC::GetMC()->Gsvolu("QC06", "CONE", getMediumID(kVoidNoField), conpar, 5);
1587 TVirtualMC::GetMC()->Gspos("QC06", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1588
1589 zC += 2. * conpar[0];
1590
1591 // VMZAR (5 volumes)
1592 tubpar[0] = 20.2 / 2.;
1593 tubpar[1] = 20.6 / 2.;
1594 tubpar[2] = 2.15 / 2.;
1595 TVirtualMC::GetMC()->Gsvolu("QT06", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1596 TVirtualMC::GetMC()->Gspos("QT06", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1597
1598 zC += 2. * tubpar[2];
1599
1600 conpar[0] = 6.9 / 2.;
1601 conpar[1] = 23.9 / 2.;
1602 conpar[2] = 24.3 / 2.;
1603 conpar[3] = 20.2 / 2.;
1604 conpar[4] = 20.6 / 2.;
1605 TVirtualMC::GetMC()->Gsvolu("QC07", "CONE", getMediumID(kVoidNoField), conpar, 5);
1606 TVirtualMC::GetMC()->Gspos("QC07", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1607
1608 zC += 2. * conpar[0];
1609
1610 tubpar[0] = 23.9 / 2.;
1611 tubpar[1] = 25.5 / 2.;
1612 tubpar[2] = 17.0 / 2.;
1613 TVirtualMC::GetMC()->Gsvolu("QT07", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1614 TVirtualMC::GetMC()->Gspos("QT07", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1615
1616 zC += 2. * tubpar[2];
1617
1618 conpar[0] = 6.9 / 2.;
1619 conpar[1] = 20.2 / 2.;
1620 conpar[2] = 20.6 / 2.;
1621 conpar[3] = 23.9 / 2.;
1622 conpar[4] = 24.3 / 2.;
1623 TVirtualMC::GetMC()->Gsvolu("QC08", "CONE", getMediumID(kVoidNoField), conpar, 5);
1624 TVirtualMC::GetMC()->Gspos("QC08", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1625
1626 zC += 2. * conpar[0];
1627
1628 tubpar[0] = 20.2 / 2.;
1629 tubpar[1] = 20.6 / 2.;
1630 tubpar[2] = 2.15 / 2.;
1631 TVirtualMC::GetMC()->Gsvolu("QT08", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1632 TVirtualMC::GetMC()->Gspos("QT08", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1633
1634 zC += 2. * tubpar[2];
1635
1636 // Flange (ID=196 mm)(last part of VMZAR and first part of VCTYB)
1637 tubpar[0] = 19.6 / 2.;
1638 tubpar[1] = 25.3 / 2.;
1639 tubpar[2] = 4.9 / 2.;
1640 TVirtualMC::GetMC()->Gsvolu("QT09", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1641 TVirtualMC::GetMC()->Gspos("QT09", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1642
1643 zC += 2. * tubpar[2];
1644
1645 // simulation of the trousers (VCTYB)
1646 tubpar[0] = 19.6 / 2.;
1647 tubpar[1] = 20.0 / 2.;
1648 tubpar[2] = 3.9 / 2.;
1649 TVirtualMC::GetMC()->Gsvolu("QT10", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1650 TVirtualMC::GetMC()->Gspos("QT10", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1651
1652 zC += 2. * tubpar[2];
1653
1654 // transition cone from ID=196. to ID=216.6
1655 conpar[0] = 32.55 / 2.;
1656 conpar[1] = 21.66 / 2.;
1657 conpar[2] = 22.06 / 2.;
1658 conpar[3] = 19.6 / 2.;
1659 conpar[4] = 20.0 / 2.;
1660 TVirtualMC::GetMC()->Gsvolu("QC09", "CONE", getMediumID(kVoidNoField), conpar, 5);
1661 TVirtualMC::GetMC()->Gspos("QC09", 1, "ZDCC", 0., 0., -conpar[0] - zC, 0, "ONLY");
1662
1663 zC += 2. * conpar[0];
1664
1665 // tube
1666 tubpar[0] = 21.66 / 2.;
1667 tubpar[1] = 22.06 / 2.;
1668 tubpar[2] = 28.6 / 2.;
1669 TVirtualMC::GetMC()->Gsvolu("QT11", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1670 TVirtualMC::GetMC()->Gspos("QT11", 1, "ZDCC", 0., 0., -tubpar[2] - zC, 0, "ONLY");
1671
1672 zC += 2. * tubpar[2];
1673
1674 // --------------------------------------------------------
1675 // RECOMBINATION CHAMBER
1676 // TRANSFORMATION MATRICES
1677 double dx = -3.970000;
1678 double dy = 0.000000;
1679 double dz = 0.0;
1680 // Rotation:
1681 double thx = 84.989100;
1682 double phx = 180.000000;
1683 double thy = 90.000000;
1684 double phy = 90.000000;
1685 double thz = 185.010900;
1686 double phz = 0.000000;
1687 TGeoRotation* rotMatrix1c = new TGeoRotation("c", thx, phx, thy, phy, thz, phz);
1688 // Combi transformation:
1689 dx = -3.970000;
1690 dy = 0.000000;
1691 dz = 0.0;
1692 TGeoCombiTrans* rotMatrix2c = new TGeoCombiTrans("ZDCC_c1", dx, dy, dz, rotMatrix1c);
1693 rotMatrix2c->RegisterYourself();
1694 // Combi transformation:
1695 dx = 3.970000;
1696 dy = 0.000000;
1697 dz = 0.0;
1698 // Rotation:
1699 thx = 95.010900;
1700 phx = 180.000000;
1701 thy = 90.000000;
1702 phy = 90.000000;
1703 thz = 180. - 5.010900;
1704 phz = 0.000000;
1705 TGeoRotation* rotMatrix3c = new TGeoRotation("", thx, phx, thy, phy, thz, phz);
1706 TGeoCombiTrans* rotMatrix4c = new TGeoCombiTrans("ZDCC_c2", dx, dy, dz, rotMatrix3c);
1707 rotMatrix4c->RegisterYourself();
1708
1709 // VOLUMES DEFINITION
1710 // Volume: ZDCC
1711 TGeoVolume* pZDCC = gGeoManager->GetVolume("ZDCC");
1712
1713 conpar[0] = (90.1 - 0.95 - 0.26 - 0.0085) / 2.;
1714 conpar[1] = 0.0 / 2.;
1715 conpar[2] = 21.6 / 2.;
1716 conpar[3] = 0.0 / 2.;
1717 conpar[4] = 5.8 / 2.;
1718 new TGeoCone("QCLext", conpar[0], conpar[1], conpar[2], conpar[3], conpar[4]);
1719
1720 conpar[0] = (90.1 - 0.95 - 0.26 - 0.0085) / 2.;
1721 conpar[1] = 0.0 / 2.;
1722 conpar[2] = 21.2 / 2.;
1723 conpar[3] = 0.0 / 2.;
1724 conpar[4] = 5.4 / 2.;
1725 new TGeoCone("QCLint", conpar[0], conpar[1], conpar[2], conpar[3], conpar[4]);
1726
1727 // Outer trousers
1728 TGeoCompositeShape* pOutTrousersC = new TGeoCompositeShape("outTrousersC", "QCLext:ZDCC_c1+QCLext:ZDCC_c2");
1729
1730 //auto& matmgr = o2::base::MaterialManager::Instance();
1731
1732 // Volume: QCLext
1733 TGeoMedium* medZDCFeLowTh = gGeoManager->GetMedium("ZDC_IronLowTh$");
1734 TGeoVolume* pQCLext = new TGeoVolume("QCLext", pOutTrousersC, medZDCFeLowTh);
1735 pQCLext->SetLineColor(kAzure);
1736 pQCLext->SetVisLeaves(kTRUE);
1737 //
1738 TGeoTranslation* tr1c = new TGeoTranslation(0., 0., (double)-conpar[0] - 0.95 - zC);
1739 //
1740 pZDCC->AddNode(pQCLext, 1, tr1c);
1741 // Inner trousers
1742 TGeoCompositeShape* pIntTrousersC = new TGeoCompositeShape("intTrousersC", "QCLint:ZDCC_c1+QCLint:ZDCC_c2");
1743 // Volume: QCLint
1744 TGeoMedium* medZDCvoid = gGeoManager->GetMedium("ZDC_VoidNoField$");
1745 TGeoVolume* pQCLint = new TGeoVolume("QCLint", pIntTrousersC, medZDCvoid);
1746 pQCLint->SetLineColor(kBlue);
1747 pQCLint->SetVisLeaves(kTRUE);
1748 pQCLext->AddNode(pQCLint, 1);
1749
1750 zC += 90.1;
1751 double offset = 0.5;
1752 zC = zC + offset;
1753
1754 // second section : 2 tubes (ID = 54. OD = 58.)
1755 tubpar[0] = 5.4 / 2.;
1756 tubpar[1] = 5.8 / 2.;
1757 tubpar[2] = 40.0 / 2.;
1758 TVirtualMC::GetMC()->Gsvolu("QT12", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1759 TVirtualMC::GetMC()->Gspos("QT12", 1, "ZDCC", -15.8 / 2., 0., -tubpar[2] - zC, 0, "ONLY");
1760 TVirtualMC::GetMC()->Gspos("QT12", 2, "ZDCC", 15.8 / 2., 0., -tubpar[2] - zC, 0, "ONLY");
1761
1762 zC += 2. * tubpar[2];
1763
1764 //-- rotation matrices for the legs
1765 int32_t irotpipe1, irotpipe2;
1766 double rang1[6] = {90. - 1.0027, 0., 90., 90., 1.0027, 180.};
1767 double rang2[6] = {90. + 1.0027, 0., 90., 90., 1.0027, 0.};
1768 TVirtualMC::GetMC()->Matrix(irotpipe1, rang1[0], rang1[1], rang1[2], rang1[3], rang1[4], rang1[5]);
1769 TVirtualMC::GetMC()->Matrix(irotpipe2, rang2[0], rang2[1], rang2[2], rang2[3], rang2[4], rang2[5]);
1770
1771 // transition x2zdc to recombination chamber : skewed cone
1772 conpar[0] = (10. - 0.2 - offset) / 2.;
1773 conpar[1] = 6.3 / 2.;
1774 conpar[2] = 7.0 / 2.;
1775 conpar[3] = 5.4 / 2.;
1776 conpar[4] = 5.8 / 2.;
1777 TVirtualMC::GetMC()->Gsvolu("QC10", "CONE", getMediumID(kVoidNoField), conpar, 5);
1778 TVirtualMC::GetMC()->Gspos("QC10", 1, "ZDCC", -7.9 - 0.175, 0., -conpar[0] - 0.1 - zC, irotpipe1, "ONLY");
1779 TVirtualMC::GetMC()->Gspos("QC10", 2, "ZDCC", 7.9 + 0.175, 0., -conpar[0] - 0.1 - zC, irotpipe2, "ONLY");
1780
1781 zC += 2. * conpar[0] + 0.2;
1782
1783 // 2 tubes (ID = 63 mm OD=70 mm)
1784 tubpar[0] = 6.3 / 2.;
1785 tubpar[1] = 7.0 / 2.;
1786 tubpar[2] = 639.8 / 2.;
1787 TVirtualMC::GetMC()->Gsvolu("QT13", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1788 TVirtualMC::GetMC()->Gspos("QT13", 1, "ZDCC", -16.5 / 2., 0., -tubpar[2] - zC, 0, "ONLY");
1789 TVirtualMC::GetMC()->Gspos("QT13", 2, "ZDCC", 16.5 / 2., 0., -tubpar[2] - zC, 0, "ONLY");
1790
1791 zC += 2. * tubpar[2];
1792
1793 // -- Luminometer (Cu box) in front of ZN - side C
1794 if (mLumiLength > 0.) { // FIX IT!!!!!!!!!!!!!!!!!!!!!!!!
1795 boxpar[0] = 8.0 / 2.;
1796 boxpar[1] = 8.0 / 2.;
1797 boxpar[2] = mLumiLength / 2.; // FIX IT!!!!!!!!!!!!!!!!!!!!!!!!
1798 TVirtualMC::GetMC()->Gsvolu("QLUC", "BOX ", getMediumID(kCuLumi), boxpar, 3);
1799 TVirtualMC::GetMC()->Gspos("QLUC", 1, "ZDCC", 0., 0., Geometry::ZNCPOSITION[1] + 66. + boxpar[2], 0, "ONLY");
1800 LOG(debug) << "C-side luminometer positioned in front of ZNC\n";
1801 }
1802}
1803
1804//_____________________________________________________________________________
1805void Detector::createMagnets()
1806{
1807 float tubpar[3] = {0., 0., 0.};
1808 float boxpar[3] = {0., 0., 0.};
1809 // Parameters from magnet DEFINITION
1810 double zCompensatorField = 1972.5;
1811 double zITField = 2296.5;
1812 double zD1Field = 5838.3001;
1813 double zD2Field = 12167.8;
1814
1815 // ***************************************************************
1816 //SIDE C
1817 // ***************************************************************
1818 // -- COMPENSATOR DIPOLE (MBXW)
1819 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1820 tubpar[0] = 0.;
1821 tubpar[1] = 3.14;
1822 // New -> Added to accomodate AD (A. Morsch)
1823 // Updated -> The field must be 1.53 m long
1824 tubpar[2] = 153. / 2.;
1825 TVirtualMC::GetMC()->Gsvolu("MBXW", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1826 TVirtualMC::GetMC()->Gspos("MBXW", 1, "ZDCC", 0., 0., -tubpar[2] - zCompensatorField, 0, "ONLY");
1827 // -- YOKE
1828 tubpar[0] = 4.5;
1829 tubpar[1] = 55.;
1830 // Updated -> The yoke can be 1.50 m to avoid overlaps
1831 tubpar[2] = 150. / 2.;
1832 TVirtualMC::GetMC()->Gsvolu("YMBX", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1833 TVirtualMC::GetMC()->Gspos("YMBX", 1, "ZDCC", 0., 0., -tubpar[2] - zCompensatorField - 1.5, 0, "ONLY");
1834
1835 // -- INNER TRIPLET
1836 // -- DEFINE MQXL AND MQX QUADRUPOLE ELEMENT
1837 // -- MQXL
1838 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1839 tubpar[0] = 0.;
1840 tubpar[1] = 3.14;
1841 tubpar[2] = 637. / 2.;
1842 TVirtualMC::GetMC()->Gsvolu("MQXL", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1843
1844 // -- YOKE
1845 tubpar[0] = 3.5;
1846 tubpar[1] = 22.;
1847 tubpar[2] = 637. / 2.;
1848 TVirtualMC::GetMC()->Gsvolu("YMQL", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1849
1850 TVirtualMC::GetMC()->Gspos("MQXL", 1, "ZDCC", 0., 0., -tubpar[2] - zITField, 0, "ONLY");
1851 TVirtualMC::GetMC()->Gspos("YMQL", 1, "ZDCC", 0., 0., -tubpar[2] - zITField, 0, "ONLY");
1852
1853 TVirtualMC::GetMC()->Gspos("MQXL", 2, "ZDCC", 0., 0., -tubpar[2] - zITField - 2400., 0, "ONLY");
1854 TVirtualMC::GetMC()->Gspos("YMQL", 2, "ZDCC", 0., 0., -tubpar[2] - zITField - 2400., 0, "ONLY");
1855
1856 // -- MQX
1857 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1858 tubpar[0] = 0.;
1859 tubpar[1] = 3.14;
1860 tubpar[2] = 550. / 2.;
1861 TVirtualMC::GetMC()->Gsvolu("MQX ", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1862
1863 // -- YOKE
1864 tubpar[0] = 3.5;
1865 tubpar[1] = 22.;
1866 tubpar[2] = 550. / 2.;
1867 TVirtualMC::GetMC()->Gsvolu("YMQ ", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1868
1869 TVirtualMC::GetMC()->Gspos("MQX ", 1, "ZDCC", 0., 0., -tubpar[2] - zITField - 908.5, 0, "ONLY");
1870 TVirtualMC::GetMC()->Gspos("YMQ ", 1, "ZDCC", 0., 0., -tubpar[2] - zITField - 908.5, 0, "ONLY");
1871
1872 TVirtualMC::GetMC()->Gspos("MQX ", 2, "ZDCC", 0., 0., -tubpar[2] - zITField - 1558.5, 0, "ONLY");
1873 TVirtualMC::GetMC()->Gspos("YMQ ", 2, "ZDCC", 0., 0., -tubpar[2] - zITField - 1558.5, 0, "ONLY");
1874
1875 // -- SEPARATOR DIPOLE D1
1876 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1877 tubpar[0] = 0.;
1878 tubpar[1] = 3.46;
1879 tubpar[2] = 945. / 2.;
1880 TVirtualMC::GetMC()->Gsvolu("MD1 ", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1881
1882 // -- Insert horizontal Cu plates inside D1
1883 // -- (to simulate the vacuum chamber)
1884 boxpar[0] = TMath::Sqrt(tubpar[1] * tubpar[1] - (2.98 + 0.2) * (2.98 + 0.2)) - 0.05;
1885 boxpar[1] = 0.2 / 2.;
1886 boxpar[2] = 945. / 2.;
1887 TVirtualMC::GetMC()->Gsvolu("MD1V", "BOX ", getMediumID(kCu), boxpar, 3);
1888 TVirtualMC::GetMC()->Gspos("MD1V", 1, "MD1 ", 0., 2.98 + boxpar[1], 0., 0, "ONLY");
1889 TVirtualMC::GetMC()->Gspos("MD1V", 2, "MD1 ", 0., -2.98 - boxpar[1], 0., 0, "ONLY");
1890
1891 // -- YOKE
1892 tubpar[0] = 3.68;
1893 tubpar[1] = 110. / 2.;
1894 tubpar[2] = 945. / 2.;
1895 TVirtualMC::GetMC()->Gsvolu("YD1 ", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1896
1897 TVirtualMC::GetMC()->Gspos("YD1 ", 1, "ZDCC", 0., 0., -tubpar[2] - zD1Field, 0, "ONLY");
1898 TVirtualMC::GetMC()->Gspos("MD1 ", 1, "ZDCC", 0., 0., -tubpar[2] - zD1Field, 0, "ONLY");
1899
1900 // -- DIPOLE D2
1901 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1902 tubpar[0] = 0.;
1903 tubpar[1] = 7.5 / 2.;
1904 tubpar[2] = 945. / 2.;
1905 TVirtualMC::GetMC()->Gsvolu("MD2 ", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1906
1907 // -- YOKE
1908 tubpar[0] = 0.;
1909 tubpar[1] = 55.;
1910 tubpar[2] = 945. / 2.;
1911 TVirtualMC::GetMC()->Gsvolu("YD2 ", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1912 TVirtualMC::GetMC()->Gspos("YD2 ", 1, "ZDCC", 0., 0., -tubpar[2] - zD2Field, 0, "ONLY");
1913
1914 TVirtualMC::GetMC()->Gspos("MD2 ", 1, "YD2 ", -9.4, 0., 0., 0, "ONLY");
1915 TVirtualMC::GetMC()->Gspos("MD2 ", 2, "YD2 ", 9.4, 0., 0., 0, "ONLY");
1916
1917 // ***************************************************************
1918 //SIDE A
1919 // ***************************************************************
1920
1921 // COMPENSATOR DIPOLE (MCBWA) (2nd compensator)
1922 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1923 tubpar[0] = 0.;
1924 tubpar[1] = 3.;
1925 tubpar[2] = 153. / 2.;
1926 TVirtualMC::GetMC()->Gsvolu("MCBW", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1927 TVirtualMC::GetMC()->Gspos("MCBW", 1, "ZDCA", 0., 0., tubpar[2] + zCompensatorField, 0, "ONLY");
1928
1929 // -- YOKE
1930 tubpar[0] = 4.5;
1931 tubpar[1] = 55.;
1932 tubpar[2] = 153. / 2.;
1933 TVirtualMC::GetMC()->Gsvolu("YMCB", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1934 TVirtualMC::GetMC()->Gspos("YMCB", 1, "ZDCA", 0., 0., tubpar[2] + zCompensatorField, 0, "ONLY");
1935
1936 // -- INNER TRIPLET
1937 // -- DEFINE MQX1 AND MQX2 QUADRUPOLE ELEMENT
1938 // -- MQX1
1939 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1940 tubpar[0] = 0.;
1941 tubpar[1] = 3.14;
1942 tubpar[2] = 637. / 2.;
1943 TVirtualMC::GetMC()->Gsvolu("MQX1", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1944 TVirtualMC::GetMC()->Gsvolu("MQX4", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1945
1946 // -- YOKE
1947 tubpar[0] = 3.5;
1948 tubpar[1] = 22.;
1949 tubpar[2] = 637. / 2.;
1950 TVirtualMC::GetMC()->Gsvolu("YMQ1", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
1951
1952 // -- Q1
1953 TVirtualMC::GetMC()->Gspos("MQX1", 1, "ZDCA", 0., 0., tubpar[2] + zITField, 0, "ONLY");
1954 TVirtualMC::GetMC()->Gspos("YMQ1", 1, "ZDCA", 0., 0., tubpar[2] + zITField, 0, "ONLY");
1955
1956 // -- BEAM SCREEN FOR Q1
1957 tubpar[0] = 4.78 / 2.;
1958 tubpar[1] = 5.18 / 2.;
1959 tubpar[2] = 637. / 2.;
1960 TVirtualMC::GetMC()->Gsvolu("QBS1", "TUBE", getMediumID(kCu), tubpar, 3);
1961 TVirtualMC::GetMC()->Gspos("QBS1", 1, "MQX1", 0., 0., 0., 0, "ONLY");
1962 // INSERT VERTICAL PLATE INSIDE Q1
1963 boxpar[0] = 0.2 / 2.0;
1964 boxpar[1] = TMath::Sqrt(tubpar[0] * tubpar[0] - (1.9 + 0.2) * (1.9 + 0.2));
1965 boxpar[2] = 637. / 2.;
1966 TVirtualMC::GetMC()->Gsvolu("QBS2", "BOX ", getMediumID(kCu), boxpar, 3);
1967 TVirtualMC::GetMC()->Gspos("QBS2", 1, "MQX1", 1.9 + boxpar[0], 0., 0., 0, "ONLY");
1968 TVirtualMC::GetMC()->Gspos("QBS2", 2, "MQX1", -1.9 - boxpar[0], 0., 0., 0, "ONLY");
1969
1970 // -- Q3
1971 TVirtualMC::GetMC()->Gspos("MQX4", 1, "ZDCA", 0., 0., tubpar[2] + zITField + 2400., 0, "ONLY");
1972 TVirtualMC::GetMC()->Gspos("YMQ1", 2, "ZDCA", 0., 0., tubpar[2] + zITField + 2400., 0, "ONLY");
1973
1974 // -- BEAM SCREEN FOR Q3
1975 tubpar[0] = 5.79 / 2.;
1976 tubpar[1] = 6.14 / 2.;
1977 tubpar[2] = 637. / 2.;
1978 TVirtualMC::GetMC()->Gsvolu("QBS3", "TUBE", getMediumID(kCu), tubpar, 3);
1979 TVirtualMC::GetMC()->Gspos("QBS3", 1, "MQX4", 0., 0., 0., 0, "ONLY");
1980 // INSERT VERTICAL PLATE INSIDE Q3
1981 boxpar[0] = 0.2 / 2.0;
1982 boxpar[1] = TMath::Sqrt(tubpar[0] * tubpar[0] - (2.405 + 0.2) * (2.405 + 0.2));
1983 boxpar[2] = 637. / 2.;
1984 TVirtualMC::GetMC()->Gsvolu("QBS4", "BOX ", getMediumID(kCu), boxpar, 3);
1985 TVirtualMC::GetMC()->Gspos("QBS4", 1, "MQX4", 2.405 + boxpar[0], 0., 0., 0, "ONLY");
1986 TVirtualMC::GetMC()->Gspos("QBS4", 2, "MQX4", -2.405 - boxpar[0], 0., 0., 0, "ONLY");
1987
1988 // -- MQX2
1989 // -- GAP (VACUUM WITH MAGNETIC FIELD)
1990 tubpar[0] = 0.;
1991 tubpar[1] = 3.14;
1992 tubpar[2] = 550. / 2.;
1993 TVirtualMC::GetMC()->Gsvolu("MQX2", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1994 TVirtualMC::GetMC()->Gsvolu("MQX3", "TUBE", getMediumID(kVoidwField), tubpar, 3);
1995
1996 // -- YOKE
1997 tubpar[0] = 3.5;
1998 tubpar[1] = 22.;
1999 tubpar[2] = 550. / 2.;
2000 TVirtualMC::GetMC()->Gsvolu("YMQ2", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
2001
2002 // -- BEAM SCREEN FOR Q2
2003 tubpar[0] = 5.79 / 2.;
2004 tubpar[1] = 6.14 / 2.;
2005 tubpar[2] = 550. / 2.;
2006 TVirtualMC::GetMC()->Gsvolu("QBS5", "TUBE", getMediumID(kCu), tubpar, 3);
2007 // VERTICAL PLATE INSIDE Q2
2008 boxpar[0] = 0.2 / 2.0;
2009 boxpar[1] = TMath::Sqrt(tubpar[0] * tubpar[0] - (2.405 + 0.2) * (2.405 + 0.2));
2010 boxpar[2] = 550. / 2.;
2011 TVirtualMC::GetMC()->Gsvolu("QBS6", "BOX ", getMediumID(kCu), boxpar, 3);
2012
2013 // -- Q2A
2014 TVirtualMC::GetMC()->Gspos("MQX2", 1, "ZDCA", 0., 0., tubpar[2] + zITField + 908.5, 0, "ONLY");
2015 TVirtualMC::GetMC()->Gspos("QBS5", 1, "MQX2", 0., 0., 0., 0, "ONLY");
2016 TVirtualMC::GetMC()->Gspos("QBS6", 1, "MQX2", 2.405 + boxpar[0], 0., 0., 0, "ONLY");
2017 TVirtualMC::GetMC()->Gspos("QBS6", 2, "MQX2", -2.405 - boxpar[0], 0., 0., 0, "ONLY");
2018 TVirtualMC::GetMC()->Gspos("YMQ2", 1, "ZDCA", 0., 0., tubpar[2] + zITField + 908.5, 0, "ONLY");
2019
2020 // -- Q2B
2021 TVirtualMC::GetMC()->Gspos("MQX3", 1, "ZDCA", 0., 0., tubpar[2] + zITField + 1558.5, 0, "ONLY");
2022 TVirtualMC::GetMC()->Gspos("QBS5", 2, "MQX3", 0., 0., 0., 0, "ONLY");
2023 TVirtualMC::GetMC()->Gspos("QBS6", 3, "MQX3", 2.405 + boxpar[0], 0., 0., 0, "ONLY");
2024 TVirtualMC::GetMC()->Gspos("QBS6", 4, "MQX3", -2.405 - boxpar[0], 0., 0., 0, "ONLY");
2025 TVirtualMC::GetMC()->Gspos("YMQ2", 2, "ZDCA", 0., 0., tubpar[2] + zITField + 1558.5, 0, "ONLY");
2026
2027 // -- SEPARATOR DIPOLE D1
2028 // -- GAP (VACUUM WITH MAGNETIC FIELD)
2029 tubpar[0] = 0.;
2030 tubpar[1] = 6.75 / 2.; //3.375
2031 tubpar[2] = 945. / 2.;
2032 TVirtualMC::GetMC()->Gsvolu("MD1L", "TUBE", getMediumID(kVoidwField), tubpar, 3);
2033
2034 // -- The beam screen tube is provided by the beam pipe in D1 (QA03 volume)
2035 // -- Insert the beam screen horizontal Cu plates inside D1 to simulate the vacuum chamber
2036 boxpar[0] = TMath::Sqrt(tubpar[1] * tubpar[1] - (2.885 + 0.2) * (2.885 + 0.2));
2037 boxpar[1] = 0.2 / 2.;
2038 boxpar[2] = 945. / 2.;
2039 TVirtualMC::GetMC()->Gsvolu("QBS7", "BOX ", getMediumID(kCu), boxpar, 3);
2040 TVirtualMC::GetMC()->Gspos("QBS7", 1, "MD1L", 0., 2.885 + boxpar[1], 0., 0, "ONLY");
2041 TVirtualMC::GetMC()->Gspos("QBS7", 2, "MD1L", 0., -2.885 - boxpar[1], 0., 0, "ONLY");
2042
2043 // -- YOKE
2044 tubpar[0] = 3.68;
2045 tubpar[1] = 110. / 2;
2046 tubpar[2] = 945. / 2.;
2047 TVirtualMC::GetMC()->Gsvolu("YD1L", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
2048
2049 TVirtualMC::GetMC()->Gspos("YD1L", 1, "ZDCA", 0., 0., tubpar[2] + zD1Field, 0, "ONLY");
2050 TVirtualMC::GetMC()->Gspos("MD1L", 1, "ZDCA", 0., 0., tubpar[2] + zD1Field, 0, "ONLY");
2051
2052 // -- DIPOLE D2
2053 // -- GAP (VACUUM WITH MAGNETIC FIELD)
2054 tubpar[0] = 0.;
2055 tubpar[1] = 7.5 / 2.; // this has to be checked
2056 tubpar[2] = 945. / 2.;
2057 TVirtualMC::GetMC()->Gsvolu("MD2L", "TUBE", getMediumID(kVoidwField), tubpar, 3);
2058
2059 // -- YOKE
2060 tubpar[0] = 0.;
2061 tubpar[1] = 55.;
2062 tubpar[2] = 945. / 2.;
2063 TVirtualMC::GetMC()->Gsvolu("YD2L", "TUBE", getMediumID(kVoidNoField), tubpar, 3);
2064 TVirtualMC::GetMC()->Gspos("YD2L", 1, "ZDCA", 0., 0., tubpar[2] + zD2Field, 0, "ONLY");
2065
2066 TVirtualMC::GetMC()->Gspos("MD2L", 1, "YD2L", -9.4, 0., 0., 0, "ONLY");
2067 TVirtualMC::GetMC()->Gspos("MD2L", 2, "YD2L", 9.4, 0., 0., 0, "ONLY");
2068}
2069//_____________________________________________________________________________
2070void Detector::createDetectors()
2071{
2072 // Create the ZDCs
2073
2074 double znSupportBase[3] = {6.3, 4.57, 71.2}; //Basement of ZN table (thick one)
2075 double znSupportBasePos[3] = {0., -14., 21.2};
2076 double znSupportScintillH[3] = {4.32 - 0.8, 0.8, 50.}; //Scintillator container: top&bottom
2077 double znSupportScintillV[3] = {0.8, 1.955, 50.}; //Scintillator container: sides
2078 double znSupportWallsud[3] = {3.52, 1., 50.}; //Top and bottom walls
2079 double znSupportWallside[3] = {0.4, 5.52, 50.}; //Side walls
2080
2081 float dimPb[6], dimVoid[6];
2082
2083 // -------------------------------------------------------------------------------
2084 //--> Neutron calorimeter (ZN)
2085 mMediumPMCid = getMediumID(kSiO2pmc);
2086 mMediumPMQid = getMediumID(kSiO2pmq);
2087
2088 // an envelop volume for the purpose of registering particles entering the detector
2089 double eps = 0.1; // 1 mm
2090 double neu_envelopdim[3] = {Geometry::ZNDIMENSION[0] + eps, Geometry::ZNDIMENSION[1] + eps, Geometry::ZNDIMENSION[2] + eps};
2091 TVirtualMC::GetMC()->Gsvolu("ZNENV", "BOX ", getMediumID(kVoidNoField), neu_envelopdim, 3);
2092
2093 TVirtualMC::GetMC()->Gsvolu("ZNEU", "BOX ", getMediumID(kWalloy), const_cast<double*>(Geometry::ZNDIMENSION), 3); // Passive material
2094 TVirtualMC::GetMC()->Gsvolu("ZNF1", "TUBE", mMediumPMCid, const_cast<double*>(Geometry::ZNFIBRE), 3); // Active material
2095 TVirtualMC::GetMC()->Gsvolu("ZNF2", "TUBE", mMediumPMQid, const_cast<double*>(Geometry::ZNFIBRE), 3);
2096 TVirtualMC::GetMC()->Gsvolu("ZNF3", "TUBE", mMediumPMQid, const_cast<double*>(Geometry::ZNFIBRE), 3);
2097 TVirtualMC::GetMC()->Gsvolu("ZNF4", "TUBE", mMediumPMCid, const_cast<double*>(Geometry::ZNFIBRE), 3);
2098 TVirtualMC::GetMC()->Gsvolu("ZNG1", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZNGROOVES), 3); // Empty grooves
2099 TVirtualMC::GetMC()->Gsvolu("ZNG2", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZNGROOVES), 3);
2100 TVirtualMC::GetMC()->Gsvolu("ZNG3", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZNGROOVES), 3);
2101 TVirtualMC::GetMC()->Gsvolu("ZNG4", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZNGROOVES), 3);
2102
2103 // Divide ZNEU in quadrants
2104 TVirtualMC::GetMC()->Gsdvn("ZNTX", "ZNEU", Geometry::ZNSECTORS[0], 1); // x-tower
2105 TVirtualMC::GetMC()->Gsdvn("ZN1 ", "ZNTX", Geometry::ZNSECTORS[1], 2); // y-tower
2106
2107 //-- Divide ZN1 in minitowers (4 fibres per minitower)
2108 // ZNDIVISION[0]= NUMBER OF FIBERS PER TOWER ALONG X-AXIS =11,
2109 // ZNDIVISION[1]= NUMBER OF FIBERS PER TOWER ALONG Y-AXIS =11
2110 TVirtualMC::GetMC()->Gsdvn("ZNSL", "ZN1 ", Geometry::ZNDIVISION[1], 2); // Slices
2111 TVirtualMC::GetMC()->Gsdvn("ZNST", "ZNSL", Geometry::ZNDIVISION[0], 1); // Sticks
2112
2113 // --- Position the empty grooves in the sticks (4 grooves per stick)
2114 float dx = Geometry::ZNDIMENSION[0] / Geometry::ZNDIVISION[0] / 4.;
2115 float dy = Geometry::ZNDIMENSION[1] / Geometry::ZNDIVISION[1] / 4.;
2116
2117 TVirtualMC::GetMC()->Gspos("ZNG1", 1, "ZNST", 0. - dx, 0. + dy, 0., 0, "ONLY");
2118 TVirtualMC::GetMC()->Gspos("ZNG2", 1, "ZNST", 0. + dx, 0. + dy, 0., 0, "ONLY");
2119 TVirtualMC::GetMC()->Gspos("ZNG3", 1, "ZNST", 0. - dx, 0. - dy, 0., 0, "ONLY");
2120 TVirtualMC::GetMC()->Gspos("ZNG4", 1, "ZNST", 0. + dx, 0. - dy, 0., 0, "ONLY");
2121
2122 // --- Position the fibers in the grooves
2123 TVirtualMC::GetMC()->Gspos("ZNF1", 1, "ZNG1", 0., 0., 0., 0, "ONLY");
2124 TVirtualMC::GetMC()->Gspos("ZNF2", 1, "ZNG2", 0., 0., 0., 0, "ONLY");
2125 TVirtualMC::GetMC()->Gspos("ZNF3", 1, "ZNG3", 0., 0., 0., 0, "ONLY");
2126 TVirtualMC::GetMC()->Gspos("ZNF4", 1, "ZNG4", 0., 0., 0., 0, "ONLY");
2127
2128 // --- Position the neutron calorimeter in ZDC
2129 // -- Rotation of C side ZN
2130 int32_t irotznc;
2131 double rangznc[6] = {90., 180., 90., 90., 180., 0.};
2132 TVirtualMC::GetMC()->Matrix(irotznc, rangznc[0], rangznc[1], rangznc[2], rangznc[3], rangznc[4], rangznc[5]);
2133 //
2134 TVirtualMC::GetMC()->Gspos("ZNEU", 1, "ZNENV", 0., 0., 0., 0, "ONLY");
2135 TVirtualMC::GetMC()->Gspos("ZNENV", 1, "ZDCC", Geometry::ZNCPOSITION[0], Geometry::ZNCPOSITION[1], Geometry::ZNCPOSITION[2] - Geometry::ZNDIMENSION[2], irotznc, "ONLY");
2136
2137 // --- Position the neutron calorimeter on the A side
2138 TVirtualMC::GetMC()->Gspos("ZNENV", 2, "ZDCA", Geometry::ZNAPOSITION[0], Geometry::ZNAPOSITION[1], Geometry::ZNAPOSITION[2] + Geometry::ZNDIMENSION[2], 0, "ONLY");
2139
2140 // -------------------------------------------------------------------------------
2141 // -> ZN supports
2142
2143 // Basements (A and C sides)
2144 TVirtualMC::GetMC()->Gsvolu("ZNBASE", "BOX ", getMediumID(kAl), znSupportBase, 3);
2145 TVirtualMC::GetMC()->Gspos("ZNBASE", 1, "ZDCC", Geometry::ZNCPOSITION[0] + znSupportBasePos[0],
2146 Geometry::ZNCPOSITION[1] + znSupportBasePos[1], Geometry::ZNCPOSITION[2] - znSupportBase[2], 0, "ONLY");
2147 TVirtualMC::GetMC()->Gspos("ZNBASE", 2, "ZDCA", Geometry::ZNAPOSITION[0] + znSupportBasePos[0],
2148 Geometry::ZNAPOSITION[1] + znSupportBasePos[1], Geometry::ZNAPOSITION[2] + znSupportBase[2], 0, "ONLY");
2149
2150 // Box containing scintillators (C side)
2151 TVirtualMC::GetMC()->Gsvolu("ZNSCH", "BOX ", getMediumID(kAl), znSupportScintillH, 3);
2152 TVirtualMC::GetMC()->Gspos("ZNSCH", 1, "ZDCC", Geometry::ZNCPOSITION[0] + znSupportBasePos[0],
2153 Geometry::ZNCPOSITION[1] + znSupportBasePos[1] + znSupportBase[1] + znSupportScintillH[1], Geometry::ZNCPOSITION[2] - znSupportScintillH[2], 0, "ONLY");
2154 TVirtualMC::GetMC()->Gspos("ZNSCH", 2, "ZDCC", Geometry::ZNCPOSITION[0] + znSupportBasePos[0],
2155 Geometry::ZNCPOSITION[1] - Geometry::ZNDIMENSION[1] - znSupportScintillV[1] + znSupportScintillH[1], Geometry::ZNCPOSITION[2] - znSupportScintillH[2], 0, "ONLY");
2156
2157 TVirtualMC::GetMC()->Gsvolu("ZNSCV", "BOX ", getMediumID(kAl), znSupportScintillV, 3);
2158 TVirtualMC::GetMC()->Gspos("ZNSCV", 1, "ZDCC", Geometry::ZNCPOSITION[0] + znSupportBasePos[0] + znSupportScintillH[0] + znSupportScintillV[0],
2159 Geometry::ZNCPOSITION[1] + znSupportBasePos[1] + znSupportBase[1] + znSupportScintillV[1], Geometry::ZNCPOSITION[2] - znSupportScintillV[2], 0, "ONLY");
2160 TVirtualMC::GetMC()->Gspos("ZNSCV", 2, "ZDCC", Geometry::ZNCPOSITION[0] + znSupportBasePos[0] - znSupportScintillH[0] - znSupportScintillV[0],
2161 Geometry::ZNCPOSITION[1] + znSupportBasePos[1] + znSupportBase[1] + znSupportScintillV[1], Geometry::ZNCPOSITION[2] - znSupportScintillV[2], 0, "ONLY");
2162
2163 // Box containing scintillators (A side)
2164 TVirtualMC::GetMC()->Gsvolu("ZNSCH", "BOX ", getMediumID(kAl), znSupportScintillH, 3);
2165 TVirtualMC::GetMC()->Gspos("ZNSCH", 1, "ZDCA", Geometry::ZNAPOSITION[0] + znSupportBasePos[0],
2166 Geometry::ZNAPOSITION[1] + znSupportBasePos[1] + znSupportBase[1] + znSupportScintillH[1], Geometry::ZNAPOSITION[2] + znSupportScintillH[2], 0, "ONLY");
2167 TVirtualMC::GetMC()->Gspos("ZNSCH", 2, "ZDCA", Geometry::ZNAPOSITION[0] + znSupportBasePos[0],
2168 Geometry::ZNAPOSITION[1] - Geometry::ZNDIMENSION[1] - znSupportScintillV[1] + znSupportScintillH[1], Geometry::ZNAPOSITION[2] + znSupportScintillH[2], 0, "ONLY");
2169
2170 TVirtualMC::GetMC()->Gsvolu("ZNSCV", "BOX ", getMediumID(kAl), const_cast<double*>(znSupportScintillV), 3);
2171 TVirtualMC::GetMC()->Gspos("ZNSCV", 1, "ZDCA", Geometry::ZNAPOSITION[0] + znSupportBasePos[0] + znSupportScintillH[0] + znSupportScintillV[0],
2172 Geometry::ZNAPOSITION[1] + znSupportBasePos[1] + znSupportBase[1] + znSupportScintillV[1], Geometry::ZNAPOSITION[2] + znSupportScintillV[2], 0, "ONLY");
2173 TVirtualMC::GetMC()->Gspos("ZNSCV", 2, "ZDCA", Geometry::ZNAPOSITION[0] + znSupportBasePos[0] - znSupportScintillH[0] - znSupportScintillV[0],
2174 Geometry::ZNAPOSITION[1] + znSupportBasePos[1] + znSupportBase[1] + znSupportScintillV[1], Geometry::ZNAPOSITION[2] + znSupportScintillV[2], 0, "ONLY");
2175
2176 // ZNC Box (A and C sides)
2177 // Top & bottom walls
2178 TVirtualMC::GetMC()->Gsvolu("ZNBH", "BOX ", getMediumID(kAl), const_cast<double*>(znSupportWallsud), 3);
2179 TVirtualMC::GetMC()->Gspos("ZNBH", 1, "ZDCC", Geometry::ZNCPOSITION[0] + znSupportBasePos[0],
2180 Geometry::ZNCPOSITION[1] - Geometry::ZNDIMENSION[1] - znSupportWallsud[1], Geometry::ZNCPOSITION[2] - znSupportWallsud[2], 0, "ONLY");
2181 TVirtualMC::GetMC()->Gspos("ZNBH", 2, "ZDCC", Geometry::ZNCPOSITION[0] + znSupportBasePos[0],
2182 Geometry::ZNCPOSITION[1] + Geometry::ZNDIMENSION[1] + znSupportWallsud[1], Geometry::ZNCPOSITION[2] - znSupportWallsud[2], 0, "ONLY");
2183 TVirtualMC::GetMC()->Gspos("ZNBH", 3, "ZDCA", Geometry::ZNAPOSITION[0] + znSupportBasePos[0],
2184 Geometry::ZNAPOSITION[1] - Geometry::ZNDIMENSION[1] - znSupportWallsud[1], Geometry::ZNAPOSITION[2] + znSupportWallsud[2], 0, "ONLY");
2185 TVirtualMC::GetMC()->Gspos("ZNBH", 4, "ZDCA", Geometry::ZNAPOSITION[0] + znSupportBasePos[0],
2186 Geometry::ZNAPOSITION[1] + Geometry::ZNDIMENSION[1] + znSupportWallsud[1], Geometry::ZNAPOSITION[2] + znSupportWallsud[2], 0, "ONLY");
2187
2188 // Side walls
2189 TVirtualMC::GetMC()->Gsvolu("ZNBS", "BOX ", getMediumID(kAl), const_cast<double*>(znSupportWallside), 3);
2190 TVirtualMC::GetMC()->Gspos("ZNBS", 1, "ZDCC", Geometry::ZNCPOSITION[0] + Geometry::ZNDIMENSION[0] + znSupportWallside[0],
2191 Geometry::ZNCPOSITION[1], Geometry::ZNCPOSITION[2] - znSupportWallside[2], 0, "ONLY");
2192 TVirtualMC::GetMC()->Gspos("ZNBS", 2, "ZDCC", Geometry::ZNCPOSITION[0] - Geometry::ZNDIMENSION[0] - znSupportWallside[0],
2193 Geometry::ZNCPOSITION[1], Geometry::ZNCPOSITION[2] - znSupportWallsud[2], 0, "ONLY");
2194 TVirtualMC::GetMC()->Gspos("ZNBS", 3, "ZDCA", Geometry::ZNAPOSITION[0] + Geometry::ZNDIMENSION[0] + znSupportWallside[0],
2195 Geometry::ZNAPOSITION[1], Geometry::ZNAPOSITION[2] + znSupportWallside[2], 0, "ONLY");
2196 TVirtualMC::GetMC()->Gspos("ZNBS", 4, "ZDCA", Geometry::ZNAPOSITION[0] - Geometry::ZNDIMENSION[0] - znSupportWallside[0],
2197 Geometry::ZNAPOSITION[1], Geometry::ZNAPOSITION[2] + znSupportWallsud[2], 0, "ONLY");
2198
2199 // -------------------------------------------------------------------------------
2200 //--> Proton calorimeter (ZP)
2201 double zpSupportBase1[3] = {12.5, 1.4, 75.}; //Bottom basement of ZP table (thinner one)
2202 double zpSupportBase1Pos[3] = {0., -17., 0.};
2203 double zpSupportBase2[3] = {12.5, 2.5, 75.}; //Upper basement of ZP table (thicker one)
2204 double zpSupportBase2Pos[3] = {0., -9., 0.};
2205 double zpSupportBase3[3] = {1.5, 2.05, 75.}; //support table heels (piedini)
2206 double zpSupportWallBottom[3] = {11.2, 0.25, 75.}; //Bottom wall
2207 double zpSupportWallup[3] = {11.2, 1., 75.}; //Top wall
2208 //double zpSupportWallside[3] = {0.5, 7.25, 75.}; //Side walls (original)
2209 double zpSupportWallside[3] = {0.5, 6., 75.}; //Side walls (modified)
2210
2211 double pro_envelopdim[3] = {Geometry::ZPDIMENSION[0] + eps, Geometry::ZPDIMENSION[1] + eps, Geometry::ZPDIMENSION[2] + eps};
2212 TVirtualMC::GetMC()->Gsvolu("ZPENV", "BOX", getMediumID(kVoidNoField), pro_envelopdim, 3);
2213
2214 TVirtualMC::GetMC()->Gsvolu("ZPRO", "BOX ", getMediumID(kCuZn), const_cast<double*>(Geometry::ZPDIMENSION), 3); // Passive material
2215 TVirtualMC::GetMC()->Gsvolu("ZPF1", "TUBE", getMediumID(kSiO2pmc), const_cast<double*>(Geometry::ZPFIBRE), 3); // Active material
2216 TVirtualMC::GetMC()->Gsvolu("ZPF2", "TUBE", getMediumID(kSiO2pmq), const_cast<double*>(Geometry::ZPFIBRE), 3);
2217 TVirtualMC::GetMC()->Gsvolu("ZPF3", "TUBE", getMediumID(kSiO2pmq), const_cast<double*>(Geometry::ZPFIBRE), 3);
2218 TVirtualMC::GetMC()->Gsvolu("ZPF4", "TUBE", getMediumID(kSiO2pmc), const_cast<double*>(Geometry::ZPFIBRE), 3);
2219 TVirtualMC::GetMC()->Gsvolu("ZPG1", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZPGROOVES), 3); // Empty grooves
2220 TVirtualMC::GetMC()->Gsvolu("ZPG2", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZPGROOVES), 3);
2221 TVirtualMC::GetMC()->Gsvolu("ZPG3", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZPGROOVES), 3);
2222 TVirtualMC::GetMC()->Gsvolu("ZPG4", "BOX ", getMediumID(kAir), const_cast<double*>(Geometry::ZPGROOVES), 3);
2223
2224 //-- Divide ZPRO in towers
2225 TVirtualMC::GetMC()->Gsdvn("ZPTX", "ZPRO", Geometry::ZPSECTORS[0], 1); // x-tower
2226 TVirtualMC::GetMC()->Gsdvn("ZP1 ", "ZPTX", Geometry::ZPSECTORS[1], 2); // y-tower
2227
2228 //-- Divide ZP1 in minitowers (4 fiber per minitower)
2229 // ZPDIVISION[0]= NUMBER OF FIBERS ALONG X-AXIS PER MINITOWER,
2230 // ZPDIVISION[1]= NUMBER OF FIBERS ALONG Y-AXIS PER MINITOWER
2231 TVirtualMC::GetMC()->Gsdvn("ZPSL", "ZP1 ", Geometry::ZPDIVISION[1], 2); // Slices
2232 TVirtualMC::GetMC()->Gsdvn("ZPST", "ZPSL", Geometry::ZPDIVISION[0], 1); // Sticks
2233
2234 // --- Position the empty grooves in the sticks (4 grooves per stick)
2237
2238 TVirtualMC::GetMC()->Gspos("ZPG1", 1, "ZPST", 0. - dx, 0. + dy, 0., 0, "ONLY");
2239 TVirtualMC::GetMC()->Gspos("ZPG2", 1, "ZPST", 0. + dx, 0. + dy, 0., 0, "ONLY");
2240 TVirtualMC::GetMC()->Gspos("ZPG3", 1, "ZPST", 0. - dx, 0. - dy, 0., 0, "ONLY");
2241 TVirtualMC::GetMC()->Gspos("ZPG4", 1, "ZPST", 0. + dx, 0. - dy, 0., 0, "ONLY");
2242
2243 // --- Position the fibers in the grooves
2244 TVirtualMC::GetMC()->Gspos("ZPF1", 1, "ZPG1", 0., 0., 0., 0, "ONLY");
2245 TVirtualMC::GetMC()->Gspos("ZPF2", 1, "ZPG2", 0., 0., 0., 0, "ONLY");
2246 TVirtualMC::GetMC()->Gspos("ZPF3", 1, "ZPG3", 0., 0., 0., 0, "ONLY");
2247 TVirtualMC::GetMC()->Gspos("ZPF4", 1, "ZPG4", 0., 0., 0., 0, "ONLY");
2248
2249 // --- Position the proton calorimeter in ZDCC
2250 // -- Rotation of C side ZP
2251 TVirtualMC::GetMC()->Gspos("ZPRO", 1, "ZPENV", 0., 0., 0., 0, "ONLY");
2252 TVirtualMC::GetMC()->Gspos("ZPENV", 1, "ZDCC", Geometry::ZPCPOSITION[0], Geometry::ZPCPOSITION[1], Geometry::ZPCPOSITION[2] - Geometry::ZPDIMENSION[2], irotznc, "ONLY");
2253
2254 // --- Position the proton calorimeter in ZDCA
2255 TVirtualMC::GetMC()->Gspos("ZPENV", 2, "ZDCA", Geometry::ZPAPOSITION[0], Geometry::ZPAPOSITION[1], Geometry::ZPAPOSITION[2] + Geometry::ZPDIMENSION[2], 0, "ONLY");
2256
2257 // -------------------------------------------------------------------------------
2258 // -> ZP supports
2259
2260 // Bottom basements (A and C sides)
2261 TVirtualMC::GetMC()->Gsvolu("ZPBASE1", "BOX ", getMediumID(kAl), const_cast<double*>(zpSupportBase1), 3);
2262 TVirtualMC::GetMC()->Gspos("ZPBASE1", 1, "ZDCC", Geometry::ZPCPOSITION[0] + zpSupportBase1Pos[0],
2263 Geometry::ZPCPOSITION[1] + zpSupportBase1Pos[1], Geometry::ZPCPOSITION[2] - zpSupportBase1[2], 0, "ONLY");
2264 TVirtualMC::GetMC()->Gspos("ZPBASE1", 2, "ZDCA", Geometry::ZPAPOSITION[0] + zpSupportBase1Pos[0],
2265 Geometry::ZPAPOSITION[1] + zpSupportBase1Pos[1], Geometry::ZPAPOSITION[2] + zpSupportBase1[2], 0, "ONLY");
2266
2267 // Bottom foot between 2 basements (A and C sides)
2268 TVirtualMC::GetMC()->Gsvolu("ZPFOOT", "BOX ", getMediumID(kAl), const_cast<double*>(zpSupportBase3), 3);
2269 TVirtualMC::GetMC()->Gspos("ZPFOOT", 1, "ZDCC", Geometry::ZPCPOSITION[0] + zpSupportBase1Pos[0] - zpSupportBase1[0] + zpSupportBase3[0], Geometry::ZPCPOSITION[1] + zpSupportBase1Pos[1] + zpSupportBase1[1] + zpSupportBase3[1], Geometry::ZPCPOSITION[2] - zpSupportBase3[2], 0, "ONLY");
2270 TVirtualMC::GetMC()->Gspos("ZPFOOT", 2, "ZDCC", Geometry::ZPCPOSITION[0] + zpSupportBase1Pos[0] + zpSupportBase1[0] - zpSupportBase3[0], Geometry::ZPCPOSITION[1] + zpSupportBase1Pos[1] + zpSupportBase1[1] + zpSupportBase3[1], Geometry::ZPCPOSITION[2] - zpSupportBase3[2], 0, "ONLY");
2271 TVirtualMC::GetMC()->Gspos("ZPFOOT", 3, "ZDCA", Geometry::ZPAPOSITION[0] + zpSupportBase1Pos[0] - zpSupportBase1[0] + zpSupportBase3[0], Geometry::ZPAPOSITION[1] + zpSupportBase1Pos[1] + zpSupportBase1[1] + zpSupportBase3[1], Geometry::ZPAPOSITION[2] + zpSupportBase3[2], 0, "ONLY");
2272 TVirtualMC::GetMC()->Gspos("ZPFOOT", 4, "ZDCA", Geometry::ZPAPOSITION[0] + zpSupportBase1Pos[0] + zpSupportBase1[0] - zpSupportBase3[0], Geometry::ZPAPOSITION[1] + zpSupportBase1Pos[1] + zpSupportBase1[1] + zpSupportBase3[1], Geometry::ZPAPOSITION[2] + zpSupportBase3[2], 0, "ONLY");
2273
2274 // Upper basements (A and C sides)
2275 TVirtualMC::GetMC()->Gsvolu("ZPBASE2", "BOX ", getMediumID(kAl), const_cast<double*>(zpSupportBase2), 3);
2276 TVirtualMC::GetMC()->Gspos("ZPBASE2", 1, "ZDCC", Geometry::ZPCPOSITION[0] + zpSupportBase2Pos[0],
2277 Geometry::ZPCPOSITION[1] + zpSupportBase2Pos[1], Geometry::ZPCPOSITION[2] - zpSupportBase2[2], 0, "ONLY");
2278 TVirtualMC::GetMC()->Gspos("ZPBASE2", 2, "ZDCA", Geometry::ZPAPOSITION[0] + zpSupportBase2Pos[0],
2279 Geometry::ZPAPOSITION[1] + zpSupportBase2Pos[1], Geometry::ZPAPOSITION[2] + zpSupportBase2[2], 0, "ONLY");
2280
2281 // ZPC Box (A and C sides)
2282 // Bottom walls
2283 TVirtualMC::GetMC()->Gsvolu("ZPBB", "BOX ", getMediumID(kAl), const_cast<double*>(zpSupportWallBottom), 3);
2284 TVirtualMC::GetMC()->Gspos("ZPBB", 1, "ZDCC", Geometry::ZPCPOSITION[0],
2285 Geometry::ZPCPOSITION[1] - Geometry::ZPDIMENSION[1] - zpSupportWallBottom[1], Geometry::ZPCPOSITION[2] - zpSupportWallBottom[2], 0, "ONLY");
2286 TVirtualMC::GetMC()->Gspos("ZPBB", 2, "ZDCA", Geometry::ZPAPOSITION[0],
2287 Geometry::ZPAPOSITION[1] - Geometry::ZPDIMENSION[1] - zpSupportWallBottom[1], Geometry::ZPAPOSITION[2] + zpSupportWallBottom[2], 0, "ONLY");
2288
2289 // Top walls
2290 TVirtualMC::GetMC()->Gsvolu("ZPBT", "BOX ", getMediumID(kAl), const_cast<double*>(zpSupportWallup), 3);
2291 TVirtualMC::GetMC()->Gspos("ZPBT", 1, "ZDCC", Geometry::ZPCPOSITION[0],
2292 Geometry::ZPCPOSITION[1] + Geometry::ZPDIMENSION[1] + zpSupportWallup[1], Geometry::ZPCPOSITION[2] - zpSupportWallup[2], 0, "ONLY");
2293 TVirtualMC::GetMC()->Gspos("ZPBT", 2, "ZDCA", Geometry::ZPAPOSITION[0],
2294 Geometry::ZPAPOSITION[1] + Geometry::ZPDIMENSION[1] + zpSupportWallup[1], Geometry::ZPAPOSITION[2] + zpSupportWallup[2], 0, "ONLY");
2295
2296 // Side walls
2297 TVirtualMC::GetMC()->Gsvolu("ZPBS", "BOX ", getMediumID(kAl), const_cast<double*>(zpSupportWallside), 3);
2298 TVirtualMC::GetMC()->Gspos("ZPBS", 1, "ZDCC", Geometry::ZPCPOSITION[0] + Geometry::ZPDIMENSION[0] + zpSupportWallside[0], Geometry::ZPCPOSITION[1] + 0.75, Geometry::ZPCPOSITION[2] - zpSupportWallside[2], 0, "ONLY");
2299 TVirtualMC::GetMC()->Gspos("ZPBS", 2, "ZDCC", Geometry::ZPCPOSITION[0] - Geometry::ZPDIMENSION[0] - zpSupportWallside[0], Geometry::ZPCPOSITION[1] + 0.75, Geometry::ZPCPOSITION[2] - zpSupportWallside[2], 0, "ONLY");
2300 TVirtualMC::GetMC()->Gspos("ZPBS", 3, "ZDCA", Geometry::ZPAPOSITION[0] + Geometry::ZPDIMENSION[0] + zpSupportWallside[0], Geometry::ZPAPOSITION[1] + 0.75, Geometry::ZPAPOSITION[2] + zpSupportWallside[2], 0, "ONLY");
2301 TVirtualMC::GetMC()->Gspos("ZPBS", 4, "ZDCA", Geometry::ZPAPOSITION[0] - Geometry::ZPDIMENSION[0] - zpSupportWallside[0], Geometry::ZPAPOSITION[1] + 0.75, Geometry::ZPAPOSITION[2] + zpSupportWallside[2], 0, "ONLY");
2302
2303 // -------------------------------------------------------------------------------
2304 // -> EM calorimeter (ZEM)
2305 int32_t irotzem1, irotzem2;
2306 double rangzem1[6] = {0., 0., 90., 90., -90., 0.};
2307 double rangzem2[6] = {180., 0., 90., 45. + 90., 90., 45.};
2308 TVirtualMC::GetMC()->Matrix(irotzem1, rangzem1[0], rangzem1[1], rangzem1[2], rangzem1[3], rangzem1[4], rangzem1[5]);
2309 TVirtualMC::GetMC()->Matrix(irotzem2, rangzem2[0], rangzem2[1], rangzem2[2], rangzem2[3], rangzem2[4], rangzem2[5]);
2310
2311 double zemLength = Geometry::ZEMDIMENSION[0];
2312 double zemTranLength = zemLength / 20.;
2313 double zemPbSlice[6] = {0.15 * TMath::Sqrt(2), 3.5, 3.5, 45., 0., 0.};
2314 double zemVoidLayer[6] = {(zemTranLength - 2. * zemPbSlice[0]) / 2., 3.5, 3.5, 45., 0., 0.};
2315 // Platform and support structures
2316 double zemSupportTable[3] = {55. / 2., 1.5 / 2., 110. / 2.};
2317 double zemSupportBox[6] = {10.5 / 2., 100. / 2., 95. / 2., 0.25 / 2., 2. / 2., 2. / 2.};
2318 double zemSupport1[3] = {15. / 2, 3. / 2., 95. / 2.}; //support table
2319 double zemSupport2[3] = {2. / 2, 5. / 2., 95. / 2.}; //support table heels (piedini)
2320 double zemSupport3[3] = {3.5, 2. / 2., zemLength}; //screens around ZEM
2321 double zemSupport4[6] = {20. / 2., 3.5, 1.5 / 2., 45., 0., 0.}; //detector box walls (side)
2322 double zemWallH[3] = {10.5 / 2., /*bthickness[1]*/ 1., 95. / 2.}; //box walls
2323 double zemWallVfwd[3] = {10.5 / 2., (100. - 2.) / 2., 0.2};
2324 double zemWallVbkw[3] = {10.5 / 2., (100. - 2.) / 2., 2. / 2.};
2325 double zemWallVside[3] = {0.25 / 2., (100. - 2.) / 2., (95. - 2.) / 2.};
2326
2327 TVirtualMC::GetMC()->Gsvolu("ZEM ", "PARA", getMediumID(kVoidNoField), const_cast<double*>(Geometry::ZEMDIMENSION), 6);
2328 TVirtualMC::GetMC()->Gsvolu("ZEMF", "TUBE", getMediumID(kSiO2pmc), const_cast<double*>(Geometry::ZEMFIBRE), 3); // Active material
2329 TVirtualMC::GetMC()->Gsdvn("ZETR", "ZEM ", Geometry::ZEMDIVISION[2], 1); // Tranches
2330
2331 TVirtualMC::GetMC()->Gsvolu("ZEL0", "PARA", getMediumID(kPb), const_cast<double*>(zemPbSlice), 6); // Lead slices
2332 TVirtualMC::GetMC()->Gsvolu("ZEL1", "PARA", getMediumID(kPb), const_cast<double*>(zemPbSlice), 6);
2333 TVirtualMC::GetMC()->Gsvolu("ZEL2", "PARA", getMediumID(kPb), const_cast<double*>(zemPbSlice), 6);
2334
2335 // --- Position the lead slices in the tranche
2336 TVirtualMC::GetMC()->Gspos("ZEL0", 1, "ZETR", -zemTranLength + zemPbSlice[0], 0., 0., 0, "ONLY");
2337 TVirtualMC::GetMC()->Gspos("ZEL1", 1, "ZETR", zemPbSlice[0], 0., 0., 0, "ONLY");
2338
2339 // --- Vacuum zone (to be filled with fibres)
2340 TVirtualMC::GetMC()->Gsvolu("ZEV0", "PARA", getMediumID(kVoidNoField), const_cast<double*>(zemVoidLayer), 6);
2341 TVirtualMC::GetMC()->Gsvolu("ZEV1", "PARA", getMediumID(kVoidNoField), const_cast<double*>(zemVoidLayer), 6);
2342
2343 // --- Divide the vacuum slice into sticks along x axis
2344 TVirtualMC::GetMC()->Gsdvn("ZES0", "ZEV0", Geometry::ZEMDIVISION[0], 3);
2345 TVirtualMC::GetMC()->Gsdvn("ZES1", "ZEV1", Geometry::ZEMDIVISION[0], 3);
2346
2347 // --- Positioning the fibers into the sticks
2348 TVirtualMC::GetMC()->Gspos("ZEMF", 1, "ZES0", 0., 0., 0., irotzem2, "ONLY");
2349 TVirtualMC::GetMC()->Gspos("ZEMF", 1, "ZES1", 0., 0., 0., irotzem2, "ONLY");
2350
2351 // --- Positioning the vacuum slice into the tranche
2352 //float displFib = fDimZEM[1]/fDivZEM[0];
2353 TVirtualMC::GetMC()->Gspos("ZEV0", 1, "ZETR", -zemVoidLayer[0], 0., 0., 0, "ONLY");
2354 TVirtualMC::GetMC()->Gspos("ZEV1", 1, "ZETR", -zemVoidLayer[0] + zemTranLength, 0., 0., 0, "ONLY");
2355
2356 // --- Positioning the ZEM into the ZDC - rotation for 90 degrees
2357 // NB -> ZEM is positioned in cave volume
2358 const float z0 = 1313.3475; // center of caveRB24 mother volume
2359 TVirtualMC::GetMC()->Gspos("ZEM ", 1, "caveRB24", -Geometry::ZEMPOSITION[0], Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + Geometry::ZEMDIMENSION[0] - z0, irotzem1, "ONLY");
2360
2361 // Second EM ZDC (same side w.r.t. IP, just on the other side w.r.t. beam pipe)
2362 TVirtualMC::GetMC()->Gspos("ZEM ", 2, "caveRB24", Geometry::ZEMPOSITION[0], Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + Geometry::ZEMDIMENSION[0] - z0, irotzem1, "ONLY");
2363
2364 // --- Adding last slice at the end of the EM calorimeter
2365 float zLastSlice = Geometry::ZEMPOSITION[2] + zemPbSlice[0] + 2 * Geometry::ZEMDIMENSION[0];
2366 TVirtualMC::GetMC()->Gspos("ZEL2", 1, "caveRB24", Geometry::ZEMPOSITION[0], Geometry::ZEMPOSITION[1], zLastSlice - z0, irotzem1, "ONLY");
2367
2368 // -------------------------------------------------------------------------------
2369 // -> ZEM supports
2370
2371 // Platform and supports
2372 float ybox = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2. * 2. * zemSupportBox[3 + 1] + zemSupportBox[1];
2373 float zSupport = Geometry::ZEMPOSITION[2] - 3.5; //to take into account the titlted front face
2374 float zbox = zSupport + zemSupportBox[2];
2375
2376 // Bridge
2377 TVirtualMC::GetMC()->Gsvolu("ZESH", "BOX ", getMediumID(kAl), const_cast<double*>(zemSupport1), 3);
2378 float ybridge = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2. * 2. * zemSupportBox[3 + 1] - 5. - zemSupport1[1];
2379 TVirtualMC::GetMC()->Gspos("ZESH", 1, "caveRB24", Geometry::ZEMPOSITION[0], ybridge, zbox - z0, 0, "ONLY");
2380 TVirtualMC::GetMC()->Gspos("ZESH", 2, "caveRB24", -Geometry::ZEMPOSITION[0], ybridge, zbox - z0, 0, "ONLY");
2381 //
2382 TVirtualMC::GetMC()->Gsvolu("ZESV", "BOX ", getMediumID(kAl), const_cast<double*>(zemSupport2), 3);
2383 TVirtualMC::GetMC()->Gspos("ZESV", 1, "caveRB24", Geometry::ZEMPOSITION[0] - zemSupportBox[0] + zemSupport2[0], ybox - zemSupportBox[1] - zemSupport2[1], zbox - z0, 0, "ONLY");
2384 TVirtualMC::GetMC()->Gspos("ZESV", 2, "caveRB24", Geometry::ZEMPOSITION[0] + zemSupportBox[0] - zemSupport2[0], ybox - zemSupportBox[1] - zemSupport2[1], zbox - z0, 0, "ONLY");
2385 TVirtualMC::GetMC()->Gspos("ZESV", 3, "caveRB24", -(Geometry::ZEMPOSITION[0] - zemSupportBox[0] + zemSupport2[0]), ybox - zemSupportBox[1] - zemSupport2[1], zbox - z0, 0, "ONLY");
2386 TVirtualMC::GetMC()->Gspos("ZESV", 4, "caveRB24", -(Geometry::ZEMPOSITION[0] + zemSupportBox[0] - zemSupport2[0]), ybox - zemSupportBox[1] - zemSupport2[1], zbox - z0, 0, "ONLY");
2387
2388 // Table
2389 TVirtualMC::GetMC()->Gsvolu("ZETA", "BOX ", getMediumID(kAl), const_cast<double*>(zemSupportTable), 3);
2390 float ytable = ybridge - zemSupport1[1] - zemSupportTable[1];
2391 TVirtualMC::GetMC()->Gspos("ZETA", 1, "caveRB24", 0.0, ytable, zbox - z0, 0, "ONLY");
2392 TVirtualMC::GetMC()->Gspos("ZETA", 2, "caveRB24", 0.0, ytable - 13. + 2. * zemSupportTable[1], zbox - z0, 0, "ONLY");
2393
2394 //Screens around ZEM
2395 TVirtualMC::GetMC()->Gsvolu("ZEFL", "BOX ", getMediumID(kAl), const_cast<double*>(zemSupport3), 3);
2396 TVirtualMC::GetMC()->Gspos("ZEFL", 1, "caveRB24", Geometry::ZEMPOSITION[0], -Geometry::ZEMDIMENSION[1] - zemSupport3[1], zSupport + zemSupport3[2] - z0, 0, "ONLY");
2397 TVirtualMC::GetMC()->Gspos("ZEFL", 2, "caveRB24", -Geometry::ZEMPOSITION[0], -Geometry::ZEMDIMENSION[1] - zemSupport3[1], zSupport + zemSupport3[2] - z0, 0, "ONLY");
2398
2399 TVirtualMC::GetMC()->Gsvolu("ZELA", "PARA", getMediumID(kAl), const_cast<double*>(zemSupport4), 6);
2400 TVirtualMC::GetMC()->Gspos("ZELA", 1, "caveRB24", Geometry::ZEMPOSITION[0] - Geometry::ZEMDIMENSION[2] - zemSupport4[2], Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + zemSupport4[0] - z0, irotzem1, "ONLY");
2401 TVirtualMC::GetMC()->Gspos("ZELA", 2, "caveRB24", Geometry::ZEMPOSITION[0] + Geometry::ZEMDIMENSION[2] + zemSupport4[2], Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + zemSupport4[0] - z0, irotzem1, "ONLY");
2402 TVirtualMC::GetMC()->Gspos("ZELA", 3, "caveRB24", -(Geometry::ZEMPOSITION[0] - Geometry::ZEMDIMENSION[2] - zemSupport4[2]), Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + zemSupport4[0] - z0, irotzem1, "ONLY");
2403 TVirtualMC::GetMC()->Gspos("ZELA", 4, "caveRB24", -(Geometry::ZEMPOSITION[0] + Geometry::ZEMDIMENSION[2] + zemSupport4[2]), Geometry::ZEMPOSITION[1], Geometry::ZEMPOSITION[2] + zemSupport4[0] - z0, irotzem1, "ONLY");
2404
2405 // Containers for ZEM calorimeters
2406 TVirtualMC::GetMC()->Gsvolu("ZEW1", "BOX ", getMediumID(kAl), const_cast<double*>(zemWallH), 3);
2407 TVirtualMC::GetMC()->Gsvolu("ZEW2", "BOX ", getMediumID(kAl), const_cast<double*>(zemWallVfwd), 3);
2408 TVirtualMC::GetMC()->Gsvolu("ZEW3", "BOX ", getMediumID(kAl), const_cast<double*>(zemWallVbkw), 3);
2409 TVirtualMC::GetMC()->Gsvolu("ZEW4", "BOX ", getMediumID(kFe), const_cast<double*>(zemWallVside), 3);
2410 //
2411 float yh1 = Geometry::ZEMPOSITION[1] - Geometry::ZEMDIMENSION[1] - 2 * zemSupport3[1] - zemWallH[1];
2412 float zh1 = zSupport + zemWallH[2];
2413 TVirtualMC::GetMC()->Gspos("ZEW1", 1, "caveRB24", Geometry::ZEMPOSITION[0], yh1, zh1 - z0, 0, "ONLY");
2414 TVirtualMC::GetMC()->Gspos("ZEW1", 2, "caveRB24", Geometry::ZEMPOSITION[0], yh1 + 2 * zemSupportBox[1], zh1 - z0, 0, "ONLY");
2415 TVirtualMC::GetMC()->Gspos("ZEW1", 3, "caveRB24", -Geometry::ZEMPOSITION[0], yh1, zh1 - z0, 0, "ONLY");
2416 TVirtualMC::GetMC()->Gspos("ZEW1", 4, "caveRB24", -Geometry::ZEMPOSITION[0], yh1 + 2 * zemSupportBox[1], zh1 - z0, 0, "ONLY");
2417 //
2418 TVirtualMC::GetMC()->Gspos("ZEW2", 1, "caveRB24", Geometry::ZEMPOSITION[0], yh1 + zemSupportBox[1], zSupport - zemWallVfwd[2] - z0, 0, "ONLY");
2419 TVirtualMC::GetMC()->Gspos("ZEW3", 1, "caveRB24", Geometry::ZEMPOSITION[0], yh1 + zemSupportBox[1], zSupport + 2 * zemWallH[2] - z0, 0, "ONLY");
2420 TVirtualMC::GetMC()->Gspos("ZEW2", 2, "caveRB24", -Geometry::ZEMPOSITION[0], yh1 + zemSupportBox[1], zSupport - zemWallVfwd[2] - z0, 0, "ONLY");
2421 TVirtualMC::GetMC()->Gspos("ZEW3", 2, "caveRB24", -Geometry::ZEMPOSITION[0], yh1 + zemSupportBox[1], zSupport + 2 * zemWallH[2] - z0, 0, "ONLY");
2422 //
2423 float xl1 = Geometry::ZEMPOSITION[0] - Geometry::ZEMDIMENSION[2] - 2. * zemSupport4[2] - zemWallVside[0];
2424 float xl2 = Geometry::ZEMPOSITION[0] + Geometry::ZEMDIMENSION[2] + 2. * zemSupport4[2] + zemWallVside[0];
2425 TVirtualMC::GetMC()->Gspos("ZEW4", 1, "caveRB24", xl1, yh1 + zemSupportBox[1], zh1 - z0, 0, "ONLY");
2426 TVirtualMC::GetMC()->Gspos("ZEW4", 2, "caveRB24", xl2, yh1 + zemSupportBox[1], zh1 - z0, 0, "ONLY");
2427 TVirtualMC::GetMC()->Gspos("ZEW4", 3, "caveRB24", -xl1, yh1 + zemSupportBox[1], zh1 - z0, 0, "ONLY");
2428 TVirtualMC::GetMC()->Gspos("ZEW4", 4, "caveRB24", -xl2, yh1 + zemSupportBox[1], zh1 - z0, 0, "ONLY");
2429}
2430
2431//_____________________________________________________________________________
2432Bool_t Detector::calculateTableIndexes(int& ibeta, int& iangle, int& iradius)
2433{
2434 double x[3] = {0., 0., 0.}, xDet[3] = {0., 0., 0.}, p[3] = {0., 0., 0.}, energy = 0.;
2435 fMC->TrackPosition(x[0], x[1], x[2]);
2436 fMC->TrackMomentum(p[0], p[1], p[2], energy);
2437
2438 //particle velocity
2439 float ptot = TMath::Sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
2440 float beta = 0.;
2441 if (energy > 0.) {
2442 beta = ptot / energy;
2443 }
2444 if (beta >= 0.67) {
2445 if (beta <= 0.75) {
2446 ibeta = 0;
2447 } else if (beta > 0.75 && beta <= 0.85) {
2448 ibeta = 1;
2449 } else if (beta > 0.85 && beta <= 0.95) {
2450 ibeta = 2;
2451 } else if (beta > 0.95) {
2452 ibeta = 3;
2453 }
2454 } else {
2455 return kFALSE;
2456 }
2457 //track angle wrt fibre axis (||LHC axis)
2458 double umom[3] = {0., 0., 0.}, udet[3] = {0., 0., 0.};
2459 umom[0] = p[0] / ptot;
2460 umom[1] = p[1] / ptot;
2461 umom[2] = p[2] / ptot;
2462 fMC->Gmtod(umom, udet, 2);
2463 double angleRad = TMath::ACos(udet[2]);
2464 double angleDeg = angleRad * kRaddeg;
2465 if (angleDeg < 110.) {
2466 iangle = int(0.5 + angleDeg / 2.);
2467 } else {
2468 return kFALSE;
2469 }
2470 //radius from fibre axis
2471 fMC->Gmtod(x, xDet, 1);
2472 float radius = 0.;
2473 if (TMath::Abs(udet[0]) > 0) {
2474 float dcoeff = udet[1] / udet[0];
2475 radius = TMath::Abs((xDet[1] - dcoeff * xDet[0]) / TMath::Sqrt(dcoeff * dcoeff + 1.));
2476 } else {
2477 radius = TMath::Abs(udet[0]);
2478 }
2479 iradius = int(radius * 1000. + 1.);
2480 //printf("\t beta %f angle %f radius %f\n",beta, angleDeg, radius);
2481 return kTRUE;
2482}
2483
2484//_____________________________________________________________________________
2486{
2487 Reset();
2488}
2489
2490//_____________________________________________________________________________
2492{
2493 // after each primary we should definitely reset
2494 mLastPrincipalTrackEntered = -1;
2495 flushSpatialResponse();
2496
2497#ifdef ZDC_FASTSIM_ONNX
2498 // dump to file only if debugZDCFastSim is set to true
2499 auto& simparam = o2::zdc::ZDCSimParam::Instance();
2500 if (simparam.debugZDCFastSim && simparam.useZDCFastSim && mFastSimModelNeutron != nullptr && mFastSimModelProton != nullptr && mFastSimClassifier != nullptr) {
2501 std::fstream output("o2sim-FastSimResult", std::fstream::out | std::fstream::app);
2502 if (!output.is_open()) {
2503 LOG(error) << "Could not open file.";
2504 } else {
2505
2506 for (auto& result : mFastSimResults) {
2507 output << result[0] << ", " << result[1] << ", " << result[2] << ", " << result[3] << ", " << result[4];
2508 output << std::endl;
2509 }
2510 mFastSimResults.clear();
2511 }
2512 output.close();
2513 }
2514#endif
2515}
2516
2518{
2519 // set current principal track
2520 auto stack = (o2::data::Stack*)fMC->GetStack();
2521
2522 mLastPrincipalTrackEntered = stack->GetCurrentTrackNumber();
2523 resetHitIndices();
2524
2525 mCurrentPrincipalParticle = *stack->GetCurrentTrack();
2526
2527#ifdef ZDC_FASTSIM_ONNX
2528 auto& simparam = o2::zdc::ZDCSimParam::Instance();
2529 using std::vector;
2530 if (simparam.useZDCFastSim && (mFastSimModelNeutron != nullptr || mFastSimModelProton != nullptr) && mFastSimClassifier != nullptr) {
2531 const std::vector<float> rawInput = {static_cast<float>(mCurrentPrincipalParticle.Energy()),
2532 static_cast<float>(mCurrentPrincipalParticle.Vx()),
2533 static_cast<float>(mCurrentPrincipalParticle.Vy()),
2534 static_cast<float>(mCurrentPrincipalParticle.Vz()),
2535 static_cast<float>(mCurrentPrincipalParticle.Px()),
2536 static_cast<float>(mCurrentPrincipalParticle.Py()),
2537 static_cast<float>(mCurrentPrincipalParticle.Pz()),
2538 static_cast<float>(mCurrentPrincipalParticle.GetMass() * 1000.0),
2539 static_cast<float>(mCurrentPrincipalParticle.GetPDG()->Charge())};
2540
2541 auto scaledClassParticle = mClassifierScaler->scale(rawInput);
2542 if (!scaledClassParticle.has_value()) {
2543 LOG(error) << "FastSimModule: error occurred on scaling";
2544 } else {
2545 vector<vector<float>> classifierInput = {std::move(*scaledClassParticle)};
2546 mFastSimClassifier->setInput(classifierInput);
2547 mFastSimClassifier->run();
2548
2549 // this classifies if particle will leave a trace at all in one of the calos ---> TODO: better do it separately for ZN + ZP?
2550 if (fastsim::processors::readClassifier(mFastSimClassifier->getResult()[0], 1)[0]) {
2551 // let's do the neutron (ZN) part
2552 if (mModelScalerNeutron && mFastSimModelNeutron) {
2553 LOG(info) << "Generating fast hits for ZN";
2554 auto scaledModelParticleNeutron = mModelScalerNeutron->scale(rawInput);
2555 if (!scaledModelParticleNeutron.has_value()) {
2556 LOG(error) << "FastSimModule: error occurred on scaling";
2557 } else {
2558 vector<vector<float>> modelInputNeutron = {fastsim::normal_distribution(0.0, 1.0, 10), std::move(*scaledModelParticleNeutron)};
2559 mFastSimModelNeutron->setInput(modelInputNeutron);
2560 mFastSimModelNeutron->run();
2561 if (simparam.debugZDCFastSim) {
2562 mFastSimResults.push_back(fastsim::processors::calculateChannels(mFastSimModelNeutron->getResult()[0], 1)[0]);
2563 }
2564 // produce hits from fast sim result
2565 bool forward = mCurrentPrincipalParticle.Pz() > 0.;
2566 FastSimToHits(mFastSimModelNeutron->getResult()[0], mCurrentPrincipalParticle, forward ? ZNA : ZNC);
2567 }
2568 }
2569 // let's do the proton (ZP) part
2570 if (mModelScalerProton && mFastSimModelProton) {
2571 LOG(info) << "Generating fast hits for ZP";
2572 auto scaledModelParticleProton = mModelScalerProton->scale(rawInput);
2573 if (!scaledModelParticleProton.has_value()) {
2574 LOG(error) << "FastSimModule: error occurred on scaling";
2575 } else {
2576 vector<vector<float>> modelInputProton = {fastsim::normal_distribution(0.0, 1.0, 10), std::move(*scaledModelParticleProton)};
2577 mFastSimModelProton->setInput(modelInputProton);
2578 mFastSimModelProton->run();
2579 // produce hits from fast sim result
2580 bool forward = mCurrentPrincipalParticle.Pz() > 0.;
2581 FastSimToHits(mFastSimModelProton->getResult()[0], mCurrentPrincipalParticle, forward ? ZPA : ZPC);
2582 }
2583 } // end proton treatment
2584 }
2585 }
2586 }
2587#endif
2588}
2589
2590//_____________________________________________________________________________
2591void Detector::Register()
2592{
2593 // This will create a branch in the output tree called Hit, setting the last
2594 // parameter to kFALSE means that this collection will not be written to the file,
2595 // it will exist only during the simulation
2596
2597 if (FairRootManager::Instance()) {
2598 FairRootManager::Instance()->RegisterAny(addNameTo("Hit").data(), mHits, kTRUE);
2599
2600 if (o2::zdc::ZDCSimParam::Instance().recordSpatialResponse) {
2601 FairRootManager::Instance()->RegisterAny(addNameTo("ResponseImage").data(), mResponsesPtr, kTRUE);
2602 }
2603 }
2604}
2605
2606//_____________________________________________________________________________
2607void Detector::Reset()
2608{
2609 if (!o2::utils::ShmManager::Instance().isOperational()) {
2610 mHits->clear();
2611 }
2612 mResponses.clear();
2613 mLastPrincipalTrackEntered = -1;
2614 resetHitIndices();
2615}
2616
2617//_____________________________________________________________________________
2618// The code of this function is taken from createHitsFromImage
2619// The changes were made to directly convert FastSim output to Hits
2620// TParticle can be used to fill additional data required by Hits
2621#ifdef ZDC_FASTSIM_ONNX
2622bool Detector::FastSimToHits(const Ort::Value& response, const TParticle& particle, int detector)
2623{
2624 math_utils::Vector3D<float> xImp(0., 0., 0.); // good value
2625
2626 // determines dimensions of the detector and binds it
2627 auto [Nx, Ny] = determineDetectorSize(detector);
2628 // if invalid detector was provided return false
2629 if (Nx == -1 || Ny == -1) {
2630 return false;
2631 }
2632
2633 // gets model output as const float*
2634 auto pixels = response.GetTensorData<float>();
2635
2636 auto determineSectorID = [&Nx = Nx, &Ny = Ny](int detector, int x, int y) {
2637 if (detector == ZNA || detector == ZNC) {
2638 if ((x + y) % 2 == 0) {
2639 return (int)Common;
2640 }
2641 if (x < Nx / 2) {
2642 if (y < Ny / 2) {
2643 return (int)Ch1;
2644 } else {
2645 return (int)Ch3;
2646 }
2647 } else {
2648 if (y >= Ny / 2) {
2649 return (int)Ch4;
2650 } else {
2651 return (int)Ch2;
2652 }
2653 }
2654 }
2655
2656 if (detector == ZPA || detector == ZPC) {
2657 if ((x + y) % 2 == 0) {
2658 return (int)Common;
2659 }
2660 auto i = (int)(4.f * x / Nx);
2661 return (int)(i + 1);
2662 }
2663 return -1;
2664 };
2665
2666 auto determineMediumID = [this](int detector, int x, int y) {
2667 // it is a simple checkerboard pattern
2668 return ((x + y) % 2 == 0) ? mMediumPMCid : mMediumPMQid;
2669 };
2670
2671 auto z_pos = 0.;
2672 if (detector == ZPA) {
2674 } else if (detector == ZPC) {
2676 } else if (detector == ZNA) {
2678 } else if (detector == ZNC) {
2680 } else {
2681 // should not happen --> we don't have fastsim for other detectors
2682 LOG(fatal) << "Unsupported detector in ZDC fast sim";
2683 }
2684 z_pos /= 1.e02; //z_pos in m
2685
2686 const float tof = 1.e09 * estimateTimeOfFlight(particle, std::abs(z_pos)); //TOF in ns
2687
2688 // loop over x = columns
2689 for (int x = 0; x < Nx; ++x) {
2690 // loop over y = rows
2691 for (int y = 0; y < Ny; ++y) {
2692 // get sector
2693 int sector = determineSectorID(detector, x, y);
2694 // get medium PMQ and PMC
2695 int currentMediumid = determineMediumID(detector, x, y);
2696 // LOG(info) << " x " << x << " y " << y << " sec " << sector << " medium " << currentMediumid;
2697 // Model output needs to be converted with exp(x)-1 function to be valid
2698 int nphe = (int)std::expm1(pixels[Nx * y + x]);
2699
2700 if (nphe > 0) {
2701 float trackenergy = 0; // energy of the primary (need to fill good value)
2702 createOrAddHit(detector,
2703 sector,
2704 currentMediumid,
2705 0 /*issecondary ---> don't know in fast sim */,
2706 nphe,
2707 0 /* trackn */,
2708 0 /* parent */,
2709 tof,
2710 trackenergy,
2711 xImp,
2712 0. /* eDep */, 0 /* x */, 0. /* y */, 0. /* z */, 0. /* px */, 0. /* py */, 0. /* pz */);
2713 }
2714 } // end loop over y
2715 } // end loop over x
2716 return true;
2717}
2718#endif
Definition of the ZDC Hit class.
Definition of the Stack class.
int16_t charge
Definition RawEventData.h:5
#define kRaddeg
int32_t i
void output(const std::map< std::string, ChannelStat > &channels)
Definition rawdump.cxx:197
uint16_t pos
Definition RawData.h:3
uint32_t c
Definition RawData.h:2
uint32_t stack
Definition RawData.h:1
std::ostringstream debug
int loadLightTable(T &table, int beta, int NRADBINS, std::string filename)
Definition Detector.cxx:149
double estimateTimeOfFlight(TParticle const &part, double z)
Definition Detector.cxx:369
ClassImp(o2::zdc::Detector)
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:135
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:150
static MaterialManager & Instance()
static ShmManager & Instance()
Definition ShmManager.h:61
o2::zdc::Hit * addHit(int32_t trackID, int32_t parentID, int32_t sFlag, float primaryEnergy, int32_t detID, int32_t secID, math_utils::Vector3D< float > pos, math_utils::Vector3D< float > mom, float tof, math_utils::Vector3D< float > xImpact, double energyloss, int32_t nphePMC, int32_t nphePMQ)
Definition Detector.cxx:605
void BeginPrimary() final
void ConstructGeometry() final
Definition Detector.cxx:323
void Register() override
Definition Detector.cxx:301
Detector(Bool_t active=true)
Definition Detector.cxx:65
void InitializeO2Detector() final
Definition Detector.cxx:181
void FinishPrimary() final
~Detector() override=default
Bool_t ProcessHits(FairVolume *v=nullptr) final
Definition Detector.cxx:385
void EndOfEvent() final
Definition Detector.cxx:292
bool createHitsFromImage(SpatialPhotonResponse const &image, int detector)
Definition Detector.cxx:531
void Reset() final
Definition Detector.cxx:315
static constexpr double ZNAPOSITION[3]
Definition Geometry.h:33
static constexpr double ZPFIBRE[3]
Definition Geometry.h:37
static constexpr double ZEMFIBRE[3]
Definition Geometry.h:47
static constexpr double ZNFIBRE[3]
Definition Geometry.h:28
static constexpr double ZPAPOSITION[3]
Definition Geometry.h:42
static constexpr double ZEMPOSITION[3]
Definition Geometry.h:51
static constexpr double ZNDIVISION[2]
Definition Geometry.h:30
static constexpr double ZPSECTORS[2]
Definition Geometry.h:38
static constexpr double ZPGROOVES[3]
Definition Geometry.h:40
static constexpr double ZPFIBREDIAMETER
Definition Geometry.h:43
static constexpr double ZNFIBREDIAMETER
Definition Geometry.h:34
static constexpr double ZEMDIVISION[3]
Definition Geometry.h:48
static constexpr double ZPCPOSITION[3]
Definition Geometry.h:41
static constexpr double ZNDIMENSION[3]
Definition Geometry.h:27
static constexpr double ZNGROOVES[3]
Definition Geometry.h:31
static constexpr double ZNSECTORS[2]
Definition Geometry.h:29
static constexpr double ZPDIVISION[2]
Definition Geometry.h:39
static constexpr double ZEMDIMENSION[6]
Definition Geometry.h:46
static constexpr double ZPDIMENSION[3]
Definition Geometry.h:36
static constexpr double ZNCPOSITION[3]
Definition Geometry.h:32
void addPhoton(double x, double y, int nphotons)
std::array< int, 5 > getPhotonsPerChannel() const
Derived class implementing interface for specific types of models.
GLeglImageOES image
Definition glcorearb.h:4021
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
GLuint64EXT * result
Definition glcorearb.h:5662
const GLdouble * v
Definition glcorearb.h:832
GLint y
Definition glcorearb.h:270
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLboolean * data
Definition glcorearb.h:298
GLintptr offset
Definition glcorearb.h:660
GLint GLint GLsizei GLint GLenum GLenum const void * pixels
Definition glcorearb.h:275
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
GLuint counter
Definition glcorearb.h:3987
D const SVectorGPU< T, D > & rhs
Definition SMatrixGPU.h:191
std::vector< T, o2::pmr::polymorphic_allocator< T > > vector
struct o2::upgrades_utils::@463 zdc
structure to keep FT0 information
std::vector< int > readClassifier(const Ort::Value &value, size_t batchSize)
Reads predicted class as int.
std::vector< std::array< long, 5 > > calculateChannels(const Ort::Value &value, size_t batchSize)
Calculate 5 channels values from 44x44 float array (for every batch)
std::vector< float > normal_distribution(double mean, double stddev, size_t size)
Generates a vector of numbers with a given normal distribution and length.
Definition Utils.cxx:19
std::optional< std::pair< std::vector< float >, std::vector< float > > > loadScales(const std::string &path)
loads and parse model scales from file at path
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
std::string filename()
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"