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