CbmRoot
Loading...
Searching...
No Matches
CbmTransport.cxx
Go to the documentation of this file.
1/* Copyright (C) 2019-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Volker Friese, Florian Uhlig [committer] */
4
9
10#include "CbmTransport.h"
11
12#include "CbmBeamProfile.h"
13#include "CbmEventGenerator.h"
14#include "CbmFieldMap.h"
15#include "CbmFieldPar.h"
16#include "CbmFileUtils.h"
17#include "CbmGeant3Settings.h"
18#include "CbmGeant4Settings.h"
19#include "CbmPlutoGenerator.h"
20#include "CbmSetup.h"
21#include "CbmStack.h"
22#include "CbmTarget.h"
23#include "CbmUnigenGenerator.h"
24
25#include <FairMonitor.h>
26#include <FairParRootFileIo.h>
27#include <FairRootFileSink.h>
28#include <FairRunSim.h>
29#include <FairRuntimeDb.h>
30#include <FairSystemInfo.h>
31#include <FairUrqmdGenerator.h>
32#include <Logger.h>
33
34#include <TDatabasePDG.h>
35#include <TG4RunConfiguration.h>
36#include <TGeant3.h>
37#include <TGeant3TGeo.h>
38#include <TGeant4.h>
39#include <TGeoManager.h>
40#include <TPythia6Decayer.h>
41#include <TROOT.h>
42#include <TRandom.h>
43#include <TStopwatch.h>
44#include <TString.h>
45#include <TSystem.h>
46#include <TVector3.h>
47#include <TVirtualMC.h>
48
49#include <boost/filesystem.hpp>
50
51#include <array>
52#include <cassert>
53#include <climits>
54#include <iostream>
55#include <sstream>
56#include <string>
57
58using std::stringstream;
59
60
61// ----- Constructor ----------------------------------------------------
63 : TNamed("CbmTransport", "Transport Run")
64 , fSetup(CbmSetup::Instance())
65 , fField(nullptr)
66 , fTarget()
69 , fRun(new FairRunSim())
70 , fOutFileName()
71 , fParFileName()
72 , fGeoFileName()
73 , fGenerators()
74 , fRealTimeInit(0.)
75 , fRealTimeRun(0.)
76 , fCpuTime(0.)
79 , fGenerateRunInfo(kFALSE)
80 , fStoreTrajectories(kFALSE)
81{
82 // TODO: I do not like instantiating FairRunSim from this constructor;
83 // It should be done in Run(). However, the presence of a FairRunSim
84 // is required by CbmUnigenGenerator. Not a good construction; should
85 // be done better.
86
87 // Initialisation of the TDatabasePDG. This is done here because in the
88 // course of the run, new particles may be added. The method
89 // ReadPDGTable, however, is not executed from the constructor, but only
90 // from GetParticle(), if the particle list is not empty.
91 // So, if one adds particles before the first call to GetParticle(),
92 // the particle table is never loaded.
93 // TDatabasePDG is a singleton, but there is no way to check whether
94 // it has already read the particle table file, nor to see if there are
95 // any contents, nor to clean the particle list. A truly remarkable
96 // implementation.
97 auto pdgdb = TDatabasePDG::Instance();
98 pdgdb->ReadPDGTable();
99
100 // By default, vertex smearing along the beam is activated
101 fEventGen->SmearVertexZ(kTRUE);
102 fRun->SetGenerator(fEventGen); // has to be available for some generators
103}
104// --------------------------------------------------------------------------
105
106
107// ----- Destructor -----------------------------------------------------
109// --------------------------------------------------------------------------
110
111
112// ----- Add a file-based input -----------------------------------------
113void CbmTransport::AddInput(const char* fileName, ECbmGenerator genType)
114{
115
116 FairGenerator* generator = NULL;
117
118 if (genType == kUrqmd) {
119 if (gSystem->AccessPathName(fileName)) {
120 LOG(fatal) << GetName() << ": Input file " << fileName << " not found!";
121 return;
122 }
123 }
124 else {
125 if (!Cbm::File::IsRootFile(fileName)) {
126 LOG(fatal) << GetName() << ": Input file " << fileName << " not found!";
127 return;
128 }
129 }
130
131 switch (genType) {
132 case kUnigen: generator = new CbmUnigenGenerator(TString(fileName)); break;
133 case kUrqmd: generator = new FairUrqmdGenerator(fileName); break;
134 case kPluto: generator = new CbmPlutoGenerator(fileName); break;
135 }
136
137 assert(generator);
138 fEventGen->AddGenerator(generator);
139}
140// --------------------------------------------------------------------------
141
142
143// ----- Add a generator-based input ------------------------------------
144void CbmTransport::AddInput(FairGenerator* generator)
145{
146 assert(generator);
147 fEventGen->AddGenerator(generator);
148}
149// --------------------------------------------------------------------------
150
151
152// ----- Configure the TVirtualMC ---------------------------------------
154{
155
156 std::cout << std::endl;
157 LOG(info) << GetName() << ": Configuring VMC...";
158 TVirtualMC* vmc = nullptr;
159
160 if (fEngine == kGeant3) {
161 TString* gModel = fRun->GetGeoModel();
162 if (strncmp(gModel->Data(), "TGeo", 4) == 0) {
163 LOG(info) << GetName() << ": Create TGeant3TGeo";
164 vmc = new TGeant3TGeo("C++ Interface to Geant3 with TGeo");
165 } //? Geant3 with TGeo
166 else {
167 LOG(info) << GetName() << ": Create TGeant3";
168 vmc = new TGeant3("C++ Interface to Geant3");
169 } //? Native Geant3
170 if (!fGeant3Settings) {
172 }
173 fGeant3Settings->Init(vmc);
174 } //? Geant3
175
176 else if (fEngine == kGeant4) {
177 LOG(info) << GetName() << ": Create TGeant4";
178 if (!fGeant4Settings) {
180 }
181 std::array<std::string, 3> runConfigSettings = fGeant4Settings->GetG4RunConfig();
182 TG4RunConfiguration* runConfig =
183 new TG4RunConfiguration(runConfigSettings[0], runConfigSettings[1], runConfigSettings[2]);
184 vmc = new TGeant4("TGeant4", "C++ Interface to Geant4", runConfig);
185 fGeant4Settings->Init(vmc);
186 } //? Geant4
187
188 else
189 LOG(fatal) << GetName() << ": unknown transport engine!";
190
191 // Create stack
192 std::unique_ptr<CbmStack> stack(new CbmStack());
193 stack->SetFilter(fStackFilter);
194 if (vmc) vmc->SetStack(stack.release());
195}
196// --------------------------------------------------------------------------
197
198
199// ----- Force creation of event vertex at a given z position -----------
200void CbmTransport::ForceVertexAtZ(Double_t zVertex)
201{
202 assert(fEventGen);
203 fEventGen->ForceVertexAtZ(zVertex);
204}
205// --------------------------------------------------------------------------
206
207
208// ----- Force creation of event vertex in the target -------------------
210{
211 assert(fEventGen);
212 fEventGen->ForceVertexInTarget(choice);
213}
214// --------------------------------------------------------------------------
215
216
217// ----- Force user-defined single-mode decays --------------------------
219{
220
221 assert(gMC);
222 auto pdgdb = TDatabasePDG::Instance();
223
224 // --- Setting user decays does not work with TGeant4
225 if ((!fDecayModes.empty()) && fEngine == kGeant4)
226 LOG(fatal) << GetName() << ": Forcing decay modes is not possible with TGeant4!";
227
228 for (auto& decay : fDecayModes) {
229
230 Int_t pdg = decay.first;
231 UInt_t nDaughters = decay.second.size();
232 stringstream log;
233 log << GetName() << ": Force decay " << pdgdb->GetParticle(pdg)->GetName() << " -> ";
234
235 // First check whether VMC knows the particle. Not all particles
236 // in TDatabasePDG are necessarily defined in VMC.
237 // This check is there because the call to TVirtualMC::SetUserDecay
238 // has no return value signifying success. If the particle is not
239 // found, just an error message is printed, which most likely
240 // goes unnoticed by the user.
241 // The access to ParticleMCTpye seems to me the only way to check.
242 // No method like Bool_t CheckParticle(Int_t) is there, which any
243 // sensible programmer would have put.
244 if (gMC->ParticleMCType(pdg) == kPTUndefined) { // At least TGeant3 delivers that
245 LOG(info) << log.str();
246 LOG(fatal) << GetName() << ": PDG " << pdg << " not in VMC!";
247 continue;
248 }
249
250 // For up to three daughters, the native decayer is used
251 if (nDaughters <= 3) {
252 Float_t branch[6] = {100., 0., 0., 0., 0., 0.}; // branching ratios
253 Int_t mode[6][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; // decay modes
254 for (UInt_t iDaughter = 0; iDaughter < nDaughters; iDaughter++) {
255 mode[0][iDaughter] = decay.second[iDaughter];
256 log << pdgdb->GetParticle(decay.second[iDaughter])->GetName() << " ";
257 }
258 Bool_t success = gMC->SetDecayMode(pdg, branch, mode);
259 if (!success) {
260 LOG(info) << log.str();
261 LOG(fatal) << GetName() << ": Setting decay mode failed!";
262 }
263 log << ", using native decayer.";
264 } //? not more than three daughters
265
266 // For more than three daughters, we must use TPythia6 as external decayer
267 else {
268 auto p6decayer = TPythia6Decayer::Instance();
269 Int_t daughterPdg[nDaughters];
270 Int_t multiplicity[nDaughters];
271 for (UInt_t iDaughter = 0; iDaughter < nDaughters; iDaughter++) {
272 daughterPdg[iDaughter] = decay.second[iDaughter];
273 multiplicity[iDaughter] = 1;
274 log << pdgdb->GetParticle(decay.second[iDaughter])->GetName() << " ";
275 } //# daughters
276 p6decayer->ForceParticleDecay(pdg, daughterPdg, multiplicity, nDaughters);
277 // We have to tell the VMC to use the Pythia decayer for this particle
278 gMC->SetUserDecay(pdg);
279 } //? more than three daughters
280
281 LOG(info) << log.str();
282 } //# user-defined decay modes
283}
284// --------------------------------------------------------------------------
285
286// ----- Initialisation of event generator ------------------------------
288{
289
290 // --- Set the target properties to the event generator
291 fEventGen->SetTarget(fTarget);
292
293 // --- Log output
294 std::cout << std::endl;
295 LOG(info) << "----- Settings for event generator";
296 fEventGen->Print();
297 LOG(info) << "----- End settings for event generator";
298 std::cout << std::endl;
299
300 // --- If a target is specified, check its consistency with the beam
301 // --- profile. The average beam must hit the target surface.
302 if (fTarget) {
303 if (!fEventGen->GetBeamProfile().CheckWithTarget(*fTarget)) {
304 LOG(fatal) << GetName() << ": Beam profile is not consistent with target!";
305 } //? Target not consistent with beam
306 } //? Target specified
307}
308// --------------------------------------------------------------------------
309
310
311// ----- Set the source the setup will be loaded from -------------------
312void CbmTransport::SetSetupSource(ECbmSetupSource setupSource) { fSetup->SetSetupSource(setupSource); }
313// --------------------------------------------------------------------------
314
315
316// ----- Load a standard setup ------------------------------------------
317void CbmTransport::LoadSetup(const char* setupName) { fSetup->LoadSetup(setupName); }
318// --------------------------------------------------------------------------
319
320
321// ----- Register ions to the TDatabsePDG -------------------------------
323{
324
325 // TODO: Better would be loading the additional particles from a text file.
326 // TDatabasePDG reads the particle definitions from pdg_table.txt
327 // (in $SIMPATH/share/root/etc). The method TDatabase::ReadPDGTable()
328 // is triggered on first call to TDatabasePDG::GetParticle(Int_t), if the
329 // database is still empty.
330 // We could call TDatabasePDG::ReadPDGTable(name_of_cbm_file) after the
331 // first initialisation of the database; the there defined particles would
332 // be added on top of the existing ones.
333
334 // Particle database and variables
335 TDatabasePDG* pdgdb = TDatabasePDG::Instance();
336 const char* name = "";
337 Int_t code = 0;
338 Double_t mass = 0.;
339 Bool_t stable = kTRUE;
340 Double_t charge = 0.;
341
342 // --- deuteron and anti-deuteron
343 name = "d+";
344 code = 1000010020;
345 mass = 1.876124;
346 stable = kTRUE;
347 charge = 1.;
348 pdgdb->AddParticle(name, name, mass, stable, 0., charge, "Ion", code);
349 pdgdb->AddAntiParticle("d-", -1 * code);
350
351 // --- tritium and anti-tritium
352 name = "t+";
353 code = 1000010030;
354 mass = 2.809432;
355 stable = kTRUE;
356 charge = 1.;
357 pdgdb->AddParticle(name, name, mass, stable, 0., charge, "Ion", code);
358 pdgdb->AddAntiParticle("t-", -1 * code);
359
360 // --- Helium_3 and its anti-nucleus
361 name = "He3+";
362 code = 1000020030;
363 mass = 2.809413;
364 stable = kTRUE;
365 charge = 2.;
366 pdgdb->AddParticle(name, name, mass, stable, 0., charge, "Ion", code);
367 pdgdb->AddAntiParticle("He3-", -1 * code);
368
369 // --- Helium_4 and its anti-nucleus
370 name = "He4+";
371 code = 1000020040;
372 mass = 3.7284;
373 stable = kTRUE;
374 charge = 2.;
375 pdgdb->AddParticle(name, name, mass, stable, 0., charge, "Ion", code);
376 pdgdb->AddAntiParticle("He4-", -1 * code);
377}
378// --------------------------------------------------------------------------
379
380
381// ----- Register radiation length --------------------------------------
383{
384 assert(fRun);
385 fRun->SetRadLenRegister(choice);
386 LOG(info) << GetName() << ": Radiation length register is enabled";
387}
388// --------------------------------------------------------------------------
389
390
391// ----- Create and register the setup modules --------------------------
392void CbmTransport::RegisterSetup() { fSetup->RegisterSetup(); }
393// --------------------------------------------------------------------------
394
395
396// ----- Set correct decay modes for pi0 and eta ------------------------
397void CbmTransport::PiAndEtaDecay(TVirtualMC* vmc)
398{
399
400 assert(vmc);
401 LOG(info) << GetName() << ": Set decay modes for pi0, eta, Hypernuclei and Open Charm";
402
403 if (fEngine == kGeant4) {
404 std::cout << std::endl << std::endl;
405 LOG(warn) << "***********************************";
406 LOG(warn) << "***********************************";
407 LOG(warn) << GetName() << ": User decay modes cannot be set with TGeant4!";
408 LOG(warn) << GetName() << ": Built-in decay modes for pi0 and eta will be used!";
409 LOG(warn) << "***********************************";
410 LOG(warn) << "***********************************";
411 std::cout << std::endl << std::endl;
412 return;
413 }
414 Double_t lifetime = 1.85e-10; // lifetime 3HL
415 Double_t mass = 2.99339;
416 Int_t PDG = 3004;
417 Double_t charge = 1.;
418
419 TVirtualMC::GetMC()->DefineParticle(PDG, "H3L", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
420 1, kFALSE);
421
422 Int_t mode[6][3];
423 Float_t bratio[6];
424
425 for (Int_t kz = 0; kz < 6; kz++) {
426 bratio[kz] = 0.;
427 mode[kz][0] = 0;
428 mode[kz][1] = 0;
429 mode[kz][2] = 0;
430 }
431 bratio[0] = 100.;
432 mode[0][0] = 1000020030; //3He
433 mode[0][1] = -211; //pi-
434
435 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
436
437 lifetime = 2.632e-10; // lifetime NL
438 mass = 2.046;
439 PDG = 3003;
440 charge = 0.;
441
442 TVirtualMC::GetMC()->DefineParticle(PDG, "LambdaN", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1,
443 0, 0, 1, kFALSE);
444
445
446 for (Int_t kz = 0; kz < 6; kz++) {
447 bratio[kz] = 0.;
448 mode[kz][0] = 0;
449 mode[kz][1] = 0;
450 mode[kz][2] = 0;
451 }
452 bratio[0] = 100.;
453 mode[0][0] = 1000010020; //d
454 mode[0][1] = -211; //pi-
455
456 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
457 lifetime = 1.80e-10; // lifetime 4HL
458 mass = 3.92975;
459 PDG = 3005;
460 charge = 1.;
461
462 TVirtualMC::GetMC()->DefineParticle(PDG, "H4L", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
463 1, kFALSE);
464
465
466 for (Int_t kz = 0; kz < 6; kz++) {
467 bratio[kz] = 0.;
468 mode[kz][0] = 0;
469 mode[kz][1] = 0;
470 mode[kz][2] = 0;
471 }
472 bratio[0] = 100.;
473 mode[0][0] = 1000020040; //4He
474 mode[0][1] = -211; //pi-
475
476 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
477
478 lifetime = 1.50e-10; // lifetime 4HeL
479 mass = 3.93070;
480 PDG = 3006;
481 charge = 2.;
482
483 TVirtualMC::GetMC()->DefineParticle(PDG, "He4L", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0,
484 0, 1, kFALSE);
485
486 for (Int_t kz = 0; kz < 6; kz++) {
487 bratio[kz] = 0.;
488 mode[kz][0] = 0;
489 mode[kz][1] = 0;
490 mode[kz][2] = 0;
491 }
492 bratio[0] = 100.;
493 mode[0][0] = 1000020030; //3He
494 mode[0][1] = 2212; //proton
495 mode[0][2] = -211; //pi-
496
497 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
498
499 lifetime = 1.85e-10; // lifetime 3HL->d p pi
500 mass = 2.99339;
501 PDG = 3012;
502 charge = 1.;
503 TVirtualMC::GetMC()->DefineParticle(PDG, "H3L_{dppi}", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1,
504 1, 0, 0, 1, kFALSE);
505
506 for (Int_t kz = 0; kz < 6; kz++) {
507 bratio[kz] = 0.;
508 mode[kz][0] = 0;
509 mode[kz][1] = 0;
510 mode[kz][2] = 0;
511 }
512 bratio[0] = 100.;
513 mode[0][0] = 1000010020; //d
514 mode[0][1] = 2212; //proton
515 mode[0][2] = -211; //pi-
516 // mode[0][0] = 3003; //LambdaN
517 // mode[0][1] = 2212; //proton
518
519 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
520
521 lifetime = 2.632e-10; // lifetime 5HeL->4He p pi
522 mass = 4.8393;
523 PDG = 3007;
524 charge = 2.;
525 TVirtualMC::GetMC()->DefineParticle(PDG, "He5L", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0,
526 0, 1, kFALSE);
527
528 for (Int_t kz = 0; kz < 6; kz++) {
529 bratio[kz] = 0.;
530 mode[kz][0] = 0;
531 mode[kz][1] = 0;
532 mode[kz][2] = 0;
533 }
534 bratio[0] = 100.;
535 mode[0][0] = 1000020040; //4He
536 mode[0][1] = 2212; //proton
537 mode[0][2] = -211; //pi-
538
539 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
540
541 lifetime = 2.632e-10; // lifetime 4HLL_2body
542 mass = 4.10791;
543 PDG = 3008;
544 charge = 1.;
545 TVirtualMC::GetMC()->DefineParticle(PDG, "H4LL_{He4Lpi-}", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0,
546 1, 1, 0, 0, 1, kFALSE);
547
548 for (Int_t kz = 0; kz < 6; kz++) {
549 bratio[kz] = 0.;
550 mode[kz][0] = 0;
551 mode[kz][1] = 0;
552 mode[kz][2] = 0;
553 }
554 bratio[0] = 100.;
555 mode[0][0] = 3006; //4HeL
556 mode[0][1] = -211; //pi-
557
558 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
559
560 lifetime = 2.632e-10; // lifetime 4HLL_3body
561 mass = 4.10791;
562 PDG = 3009;
563 charge = 1.;
564 TVirtualMC::GetMC()->DefineParticle(PDG, "H4LL_{H3Lppi-}", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0,
565 1, 1, 0, 0, 1, kFALSE);
566
567 for (Int_t kz = 0; kz < 6; kz++) {
568 bratio[kz] = 0.;
569 mode[kz][0] = 0;
570 mode[kz][1] = 0;
571 mode[kz][2] = 0;
572 }
573 bratio[0] = 100.;
574 mode[0][0] = 3004; //3HL
575 mode[0][1] = 2212; //p
576 mode[0][2] = -211; //pi-
577
578 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
579
580
581 lifetime = 2.632e-10; // lifetime 5HLL
582 mass = 5.04748;
583 PDG = 3010;
584 charge = 1.;
585 TVirtualMC::GetMC()->DefineParticle(PDG, "H5LL_{He5Lpi-}", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0,
586 1, 1, 0, 0, 1, kFALSE);
587
588 for (Int_t kz = 0; kz < 6; kz++) {
589 bratio[kz] = 0.;
590 mode[kz][0] = 0;
591 mode[kz][1] = 0;
592 mode[kz][2] = 0;
593 }
594 bratio[0] = 100.;
595 mode[0][0] = 3007; //5HeL
596 mode[0][1] = -211; //pi-
597
598 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
599
600
601 lifetime = 2.632e-10; // lifetime 6HeLL
602 mass = 5.98575;
603 PDG = 3011;
604 charge = 2.;
605 TVirtualMC::GetMC()->DefineParticle(PDG, "He6LL", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0,
606 0, 1, kFALSE);
607
608 for (Int_t kz = 0; kz < 6; kz++) {
609 bratio[kz] = 0.;
610 mode[kz][0] = 0;
611 mode[kz][1] = 0;
612 mode[kz][2] = 0;
613 }
614 bratio[0] = 100.;
615 mode[0][0] = 3007; //5HeL
616 mode[0][1] = 2212; //proton
617 mode[0][2] = -211; //pi-
618
619 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
620 // charm **********************************************************************************************************************
621 lifetime = 4.1e-13; // lifetime D0 -> K- pi
622 mass = 1.86486;
623 PDG = 421;
624 charge = 0.;
625 TVirtualMC::GetMC()->DefineParticle(PDG, "D0", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
626 1, kFALSE);
627
628 for (Int_t kz = 0; kz < 6; kz++) {
629 bratio[kz] = 0.;
630 mode[kz][0] = 0;
631 mode[kz][1] = 0;
632 mode[kz][2] = 0;
633 }
634 bratio[0] = 100.;
635 mode[0][0] = -321; //K-
636 mode[0][1] = 211; //pi+
637
638 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
639
640 lifetime = 4.1e-13; // lifetime D0b -> K+ pi-
641 mass = 1.86486;
642 PDG = -421;
643 charge = 0.;
644 TVirtualMC::GetMC()->DefineParticle(PDG, "D0b", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
645 1, kFALSE);
646
647 for (Int_t kz = 0; kz < 6; kz++) {
648 bratio[kz] = 0.;
649 mode[kz][0] = 0;
650 mode[kz][1] = 0;
651 mode[kz][2] = 0;
652 }
653 bratio[0] = 100.;
654 mode[0][0] = 321; //K+
655 mode[0][1] = -211; //pi-
656
657 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
658
659 lifetime = 2.0e-13; // lifetime Lc -> p K- pi+
660 mass = 2.28646;
661 PDG = 4122;
662 charge = 1.;
663 TVirtualMC::GetMC()->DefineParticle(PDG, "Lc", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
664 1, kFALSE);
665
666 for (Int_t kz = 0; kz < 6; kz++) {
667 bratio[kz] = 0.;
668 mode[kz][0] = 0;
669 mode[kz][1] = 0;
670 mode[kz][2] = 0;
671 }
672 bratio[0] = 100.;
673 mode[0][0] = 2212; //p
674 mode[0][1] = -321; //K-
675 mode[0][2] = 211; //pi+
676
677 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
678
679 lifetime = 1.04e-12; // lifetime D+ -> K- pi pi
680 mass = 1.86962;
681 PDG = 411;
682 charge = 1.;
683 TVirtualMC::GetMC()->DefineParticle(PDG, "D+", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
684 1, kFALSE);
685
686 for (Int_t kz = 0; kz < 6; kz++) {
687 bratio[kz] = 0.;
688 mode[kz][0] = 0;
689 mode[kz][1] = 0;
690 mode[kz][2] = 0;
691 }
692 bratio[0] = 100.;
693 mode[0][0] = -321; //K-
694 mode[0][1] = 211; //pi+
695 mode[0][2] = 211; //pi+
696
697 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
698
699 lifetime = 1.04e-12; // lifetime D- -> K pi- pi-
700 mass = 1.86962;
701 PDG = -411;
702 charge = 1.;
703 TVirtualMC::GetMC()->DefineParticle(PDG, "D-", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
704 1, kFALSE);
705
706 for (Int_t kz = 0; kz < 6; kz++) {
707 bratio[kz] = 0.;
708 mode[kz][0] = 0;
709 mode[kz][1] = 0;
710 mode[kz][2] = 0;
711 }
712 bratio[0] = 100.;
713 mode[0][0] = 321; //K+
714 mode[0][1] = -211; //pi-
715 mode[0][2] = -211; //pi-
716
717 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
718
719
720 lifetime = 5.0e-13; // lifetime Ds+ -> K- K+ pi+
721 mass = 1.96850;
722 PDG = 431;
723 charge = 1.;
724 TVirtualMC::GetMC()->DefineParticle(PDG, "Ds+", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
725 1, kFALSE);
726
727 for (Int_t kz = 0; kz < 6; kz++) {
728 bratio[kz] = 0.;
729 mode[kz][0] = 0;
730 mode[kz][1] = 0;
731 mode[kz][2] = 0;
732 }
733 bratio[0] = 100.;
734 mode[0][0] = -321; //K-
735 mode[0][1] = 321; //K+
736 mode[0][2] = 211; //pi+
737
738 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
739
740 lifetime = 5.0e-13; // lifetime Ds- -> K- K+ pi-
741 mass = 1.96850;
742 PDG = -431;
743 charge = 1.;
744 TVirtualMC::GetMC()->DefineParticle(PDG, "Ds-", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0, 0,
745 1, kFALSE);
746
747 for (Int_t kz = 0; kz < 6; kz++) {
748 bratio[kz] = 0.;
749 mode[kz][0] = 0;
750 mode[kz][1] = 0;
751 mode[kz][2] = 0;
752 }
753 bratio[0] = 100.;
754 mode[0][0] = -321; //K-
755 mode[0][1] = 321; //K+
756 mode[0][2] = -211; //pi-
757
758 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
759
760 // end charm **********************************************************************************************************************
761
762
763 lifetime = 1.55e-22; // lifetime 5HeD->4He K pi- pi-
764 mass = 5.5809994;
765 PDG = 4006;
766 charge = 1.;
767 TVirtualMC::GetMC()->DefineParticle(PDG, "He5D", kPTHadron, mass, charge, lifetime, "hadron", 0.0, 1, 1, 0, 1, 1, 0,
768 0, 1, kFALSE);
769
770 for (Int_t kz = 0; kz < 6; kz++) {
771 bratio[kz] = 0.;
772 mode[kz][0] = 0;
773 mode[kz][1] = 0;
774 mode[kz][2] = 0;
775 }
776 bratio[0] = 100.;
777 mode[0][0] = 1000020040; //4He
778 mode[0][1] = -411; //D-
779
780 TVirtualMC::GetMC()->SetDecayMode(PDG, bratio, mode);
781
782
783 TGeant3* gMC3 = static_cast<TGeant3*>(vmc);
784 assert(vmc);
785
786 // Decay modes for eta mesons (PDG 2016)
787 Int_t modeEta[6]; // decay modes
788 Float_t brEta[6]; // branching ratios in %
789
790 // --- eta -> gamma gamma
791 modeEta[0] = 101;
792 brEta[0] = 39.41;
793
794 // --- eta -> pi0 pi0 pi0
795 modeEta[1] = 70707;
796 brEta[1] = 32.68;
797
798 // --- eta -> pi+ pi- pi0
799 modeEta[2] = 80907;
800 brEta[2] = 22.92;
801
802 // --- eta -> pi+ pi- gamma
803 modeEta[3] = 80901;
804 brEta[3] = 4.22;
805
806 // --- eta -> e+ e- gamma
807 modeEta[4] = 30201;
808 brEta[4] = 0.69;
809
810 // --- eta -> pi0 gamma gamma
811 modeEta[5] = 10107;
812 brEta[5] = 2.56e-2;
813
814 // --- Set the eta decays
815 gMC3->Gsdk(17, brEta, modeEta);
816
817 // --- Decay modes for pi0
818 Int_t modePi[6]; // decay modes
819 Float_t brPi[6]; // branching ratios in %
820
821 // --- pi0 -> gamma gamma
822 modePi[0] = 101;
823 brPi[0] = 98.823;
824
825 // --- pi0 -> e+ e- gamma
826 modePi[1] = 30201;
827 brPi[1] = 1.174;
828
829 // --- No other channels for pi0
830 for (Int_t iMode = 2; iMode < 6; iMode++) {
831 modePi[iMode] = 0;
832 brPi[iMode] = 0.;
833 }
834
835 // --- Set the pi0 decays
836 gMC3->Gsdk(7, brPi, modePi);
837}
838// --------------------------------------------------------------------------
839
840
841// ----- Execute transport run ------------------------------------------
843{
844
845 // Get the minimum number of events from all file based generators
846 // Set the number of events to process to this minimum number of events
847 Int_t numAvailEvents{0};
848 Int_t numMinAvailEvents{INT_MAX};
849 TObjArray* genList = fEventGen->GetListOfGenerators();
850 for (Int_t i = 0; i < genList->GetEntries(); i++) {
851 CbmUnigenGenerator* gen = dynamic_cast<CbmUnigenGenerator*>(genList->At(i));
852 if (gen) {
853 numAvailEvents = gen->GetNumAvailableEvents();
854 if (nEvents > numAvailEvents) {
855 if (numAvailEvents < numMinAvailEvents) {
856 numMinAvailEvents = numAvailEvents;
857 }
858 }
859 }
860 CbmPlutoGenerator* pgen = dynamic_cast<CbmPlutoGenerator*>(genList->At(i));
861 if (pgen) {
862 numAvailEvents = pgen->GetNumAvailableEvents();
863 if (nEvents > numAvailEvents) {
864 if (numAvailEvents < numMinAvailEvents) {
865 numMinAvailEvents = numAvailEvents;
866 }
867 }
868 }
869 }
870 if (nEvents > numMinAvailEvents) {
871 LOG(warning) << "";
872 LOG(warning) << "The number of requested events (" << nEvents << ") is larger than the number of available events ("
873 << numMinAvailEvents << ")";
874 LOG(warning) << "Set the number of events to process to " << numMinAvailEvents;
875 LOG(warning) << "";
876 nEvents = numMinAvailEvents;
877 }
878
879 // --- Timer
880 TStopwatch timer;
881
882 // --- Set the global random seed
883 gRandom->SetSeed(fRandomSeed);
884
885 // --- Check presence of required requisites
886 if (fOutFileName.IsNull()) LOG(fatal) << GetName() << ": No output file specified!";
887 if (fParFileName.IsNull()) LOG(fatal) << GetName() << ": No parameter file specified!";
888 std::cout << std::endl << std::endl;
889
890
891 // --- Add some required particles to the TDatabasePDG
892 RegisterIons();
893
894
895 // --- Set transport engine
896 const char* engineName = "";
897 switch (fEngine) {
898 case kGeant3: engineName = "TGeant3"; break;
899 case kGeant4: engineName = "TGeant4"; break;
900 default: {
901 LOG(warn) << GetName() << ": Unknown transport engine ";
902 engineName = "TGeant3";
903 break;
904 }
905 } //? engine
906 LOG(info) << GetName() << ": Using engine " << engineName;
907 fRun->SetName(engineName);
908
909
910 // --- Create file sink using output file name
911 // TODO: remove release after switching to FairRoot v18.8
912 // fRun->SetSink(std::make_unique<FairRootFileSink>(fOutFileName));
913 fRun->SetSink(std::make_unique<FairRootFileSink>(fOutFileName).release());
914
915 // --- Create and register the setup modules, field and media with FairRoot
917
918 // --- Create and register the target
919 if (fTarget) {
920 LOG(info) << fTarget->ToString();
921 fRun->AddModule(fTarget.get());
922 }
923 else
924 LOG(warn) << GetName() << ": No target defined!";
925
926
927 // --- Create the magnetic field
928 LOG(info) << GetName() << ": Register magnetic field";
929 LOG(info) << fField;
930 if (!fField) fField = fSetup->CreateFieldMap();
931 fField->Print("");
932 fRun->SetField(fField);
933
934
935 // --- Initialise the event generator
937
938 // --- Trigger generation of run info
939 fRun->SetGenerateRunInfo(fGenerateRunInfo);
940
941
942 // --- Trigger storage of trajectories, if chosen
943 fRun->SetStoreTraj(fStoreTrajectories);
944
945
946 // --- Set VMC configuration
947 std::function<void()> f = std::bind(&CbmTransport::ConfigureVMC, this);
948 fRun->SetSimSetup(f);
949
950
951 // --- Set event filter task
952 fRun->AddTask(fEventFilter.get());
953
954
955 // --- Initialise run
956 fRun->Init();
957
958
959 // --- Force user-defined decays. This has to happen after FairRunSim::Init()
960 // because otherwise there seem to be no particles in GEANT.
962
963
964 // --- Set correct decay modes for pi0 and eta
965 // --- This is needed only when using Geant3
966 if (fEngine == kGeant3) PiAndEtaDecay(gMC);
967
968
969 // --- Runtime database
970 FairRuntimeDb* rtdb = fRun->GetRuntimeDb();
971 CbmFieldPar* fieldPar = static_cast<CbmFieldPar*>(rtdb->getContainer("CbmFieldPar"));
972 fieldPar->SetParameters(fField);
973 fieldPar->setChanged();
974 FairParRootFileIo* parOut = new FairParRootFileIo(kTRUE);
975 parOut->open(fParFileName.Data());
976 rtdb->setOutput(parOut);
977 rtdb->saveOutput();
978 rtdb->print();
979
980
981 // --- Measure time for initialisation
982 timer.Stop();
983 fRealTimeInit = timer.RealTime();
984
985 TFile* old = gFile;
986 TDirectory* oldDir = gDirectory;
987
988 // Write Transport Settings to the output file
989 auto sink = fRun->GetSink();
990 assert(sink->GetSinkType() == kFILESINK);
991 auto rootFileSink = static_cast<FairRootFileSink*>(sink);
992 TFile* outfile = rootFileSink->GetRootFile();
993 ;
994 outfile->cd();
995
996 LOG(info) << "Here I am";
997 if (fEngine == kGeant3) {
998 LOG(info) << "Write Geant3Settings";
999 fGeant3Settings->Write();
1000 }
1001 else if (fEngine == kGeant4) {
1002 LOG(info) << "Write Geant4Settings";
1003 fGeant4Settings->Write();
1004 }
1005 gFile = old;
1006 gDirectory = oldDir;
1007
1008 // --- Start run
1009 timer.Start(kFALSE); // without reset
1010 fRun->Run(nEvents);
1011 timer.Stop();
1012 fRealTimeRun = timer.RealTime() - fRealTimeInit;
1013 fCpuTime = timer.CpuTime();
1014
1015 // --- Create a geometry file if required
1016 if (!fGeoFileName.IsNull()) fRun->CreateGeometryFile(fGeoFileName);
1017
1018
1019 // --- Screen log
1020 std::cout << std::endl;
1021 LOG(info) << GetName() << ": Run finished successfully.";
1022 LOG(info) << GetName() << ": Wall time for Init : " << fRealTimeInit << " s ";
1023 LOG(info) << GetName() << ": Wall time for Run : " << fRealTimeRun << " s ("
1024 << fRealTimeRun / fEventFilter->GetNofInputEvents() << " s / event)";
1025 LOG(info) << GetName() << ": Output file : " << fOutFileName;
1026 LOG(info) << GetName() << ": Parameter file : " << fParFileName;
1027 if (!fGeoFileName.IsNull()) LOG(info) << GetName() << ": Geometry file : " << fGeoFileName;
1028 std::cout << std::endl << std::endl;
1029
1030
1031 // --- Remove TGeoManager
1032 // To avoid crashes when exiting. Reason for this behaviour is unknown.
1033 if (gGeoManager) {
1034 if (gROOT->GetVersionInt() >= 60602) {
1035 gGeoManager->GetListOfVolumes()->Delete();
1036 gGeoManager->GetListOfShapes()->Delete();
1037 }
1038 delete gGeoManager;
1039 }
1040}
1041// --------------------------------------------------------------------------
1042
1043
1044// ----- Set the beam angle distribution --------------------------------
1045void CbmTransport::SetBeamAngle(Double_t x0, Double_t y0, Double_t sigmaX, Double_t sigmaY)
1046{
1047 assert(fEventGen);
1048 fEventGen->SetBeamAngle(x0, y0, sigmaX, sigmaY);
1049}
1050// --------------------------------------------------------------------------
1051
1052
1053// ----- Set the beam position ------------------------------------------
1054void CbmTransport::SetBeamPosition(Double_t x0, Double_t y0, Double_t sigmaX, Double_t sigmaY, Double_t z)
1055{
1056 assert(fEventGen);
1057 fEventGen->SetBeamPosition(x0, y0, sigmaX, sigmaY, z);
1058}
1059// --------------------------------------------------------------------------
1060
1061
1062// ----- Set a decay mode -----------------------------------------------
1063void CbmTransport::SetDecayMode(Int_t pdg, UInt_t nDaughters, Int_t* daughterPdg)
1064{
1065
1066 if (fDecayModes.count(pdg) != 0) {
1067 LOG(fatal) << GetName() << ": User decay mode for PDG " << pdg << " is already defined!";
1068 return;
1069 }
1070
1071 for (UInt_t iDaughter = 0; iDaughter < nDaughters; iDaughter++) {
1072 fDecayModes[pdg].push_back(daughterPdg[iDaughter]);
1073 }
1074}
1075// --------------------------------------------------------------------------
1076
1077
1078// ----- Set geometry file name -----------------------------------------
1079void CbmTransport::SetGeoFileName(TString fileName)
1080{
1081
1082 // Check for the directory
1083 std::string name = fileName.Data();
1084 Int_t found = name.find_last_of("/");
1085 if (found >= 0) {
1086 TString geoDir = name.substr(0, found);
1087 if (gSystem->AccessPathName(geoDir.Data())) {
1088 LOG(error) << GetName() << ": Directory for geometry file " << geoDir
1089 << " does not exist; the file will not be created.";
1090 return;
1091 } //? Directory of geometry file does not exist
1092 } //? File name contains directory path
1093
1094 fGeoFileName = fileName;
1095}
1096// --------------------------------------------------------------------------
1097
1098
1099// ----- Set parameter file name ----------------------------------------
1100void CbmTransport::SetParFileName(TString fileName)
1101{
1102
1103 // --- If file does not exist, check the directory
1104 if (gSystem->AccessPathName(fileName)) {
1105 std::string name = fileName.Data();
1106 Int_t found = name.find_last_of("/");
1107 if (found >= 0) {
1108 TString parDir = name.substr(0, found);
1109 if (gSystem->AccessPathName(parDir.Data())) {
1110 LOG(fatal) << GetName() << ": Parameter directory " << parDir << " does not exist!";
1111 return;
1112 } //? Directory of parameter file does not exist
1113 } //? File name contains directory path
1114 } //? Parameter file does not exist
1115
1116 fParFileName = fileName;
1117}
1118// --------------------------------------------------------------------------
1119
1120
1121// ----- Set random event plane generation ------------------------------
1122void CbmTransport::SetRandomEventPlane(Double_t phiMin, Double_t phiMax) { fEventGen->SetEventPlane(phiMin, phiMax); }
1123// --------------------------------------------------------------------------
1124
1125
1126// ----- Set output file name -------------------------------------------
1127void CbmTransport::SetOutFileName(TString fileName, Bool_t overwrite)
1128{
1129
1130 // --- Protect against overwriting an existing file
1131 if ((!gSystem->AccessPathName(fileName.Data())) && (!overwrite)) {
1132 LOG(fatal) << fName << ": output file " << fileName << " already exists!";
1133 return;
1134 }
1135
1136 // --- If the directory does not yet exist, create it
1137 const char* directory = gSystem->DirName(fileName.Data());
1138 if (gSystem->AccessPathName(directory)) {
1139 Int_t success = gSystem->mkdir(directory, kTRUE);
1140 if (success == -1)
1141 LOG(fatal) << fName << ": output directory " << directory << " does not exist and cannot be created!";
1142 else
1143 LOG(info) << fName << ": created directory " << directory;
1144 }
1145
1146 fOutFileName = fileName;
1147}
1148// --------------------------------------------------------------------------
1149
1150
1151// ----- Define the target ----------------------------------------------
1152void CbmTransport::SetTarget(const char* medium, Double_t thickness, Double_t diameter, Double_t x, Double_t y,
1153 Double_t z, Double_t angle, Double_t density)
1154{
1155 if (density >= 0.) {
1156 fTarget.reset(new CbmTarget(medium, thickness, diameter, density));
1157 }
1158 else {
1159 fTarget.reset(new CbmTarget(medium, thickness, diameter));
1160 }
1161 fTarget->SetPosition(x, y, z);
1162 fTarget->SetRotation(angle);
1163}
1164// --------------------------------------------------------------------------
1165
1166
1167// ----- Enable vertex distribution in x and y --------------------------
1169{
1170 assert(fEventGen);
1171 fEventGen->SmearGausVertexXY(choice);
1172}
1173// --------------------------------------------------------------------------
1174
1175
1176// ----- Enable vertex distribution z -----------------------------------
1178{
1179 assert(fEventGen);
1180 fEventGen->SmearVertexZ(choice);
1181}
1182// --------------------------------------------------------------------------
1183
ECbmSetupSource
Definition CbmSetup.h:34
ClassImp(CbmTransport)
ECbmGenerator
@ kPluto
@ kUnigen
@ kUrqmd
@ kGeant3
@ kGeant4
friend fvec log(const fvec &a)
float Float_t
int Int_t
bool Bool_t
CbmEventGenerator.
void SetParameters(FairField *field)
User interface class to define the Geant3 simulation settings.
User interface class to define the Geant4 simulation settings.
Class deciding whether to store an MC event.
Int_t GetNumAvailableEvents()
Get the maximum number of events available in the input file.
Class for filtering the stack before writing.
Class for constructing the geometry of the CBM target.
Definition CbmTarget.h:37
User interface class for transport simulation.
void SetDecayMode(Int_t pdg, UInt_t nDaughters, Int_t *daughterPdg)
Set a decay mode for a particle.
void SetTarget(const char *medium="Gold", Double_t thickness=0.025, Double_t diameter=2.5, Double_t x=0., Double_t y=0., Double_t z=-44.0, Double_t rot=0., Double_t density=-1)
Define the target.
std::shared_ptr< CbmTarget > fTarget
void RegisterRadLength(Bool_t choice=kTRUE)
Enable registration of radiation length.
virtual ~CbmTransport()
Destructor.
void SetOutFileName(TString name, Bool_t overwrite=kFALSE)
Set the output file name.
CbmTransport()
Constructor.
CbmGeant3Settings * fGeant3Settings
std::unique_ptr< CbmMCEventFilter > fEventFilter
FairRunSim * fRun
Double_t fRealTimeInit
void SetGeoFileName(TString name)
Define geometry file name (output)
void LoadSetup(const char *setupName)
Use a standard setup.
void PiAndEtaDecay(TVirtualMC *vmc)
Correct decay modes for pi0 and eta.
void SetBeamPosition(Double_t x0, Double_t y0, Double_t sigmaX=-1., Double_t sigmaY=-1., Double_t zF=0.)
Set the beam position.
void SetRandomEventPlane(Double_t phiMin=0., Double_t phiMax=2. *TMath::Pi())
Activate random event plane.
ULong_t fRandomSeed
Double_t fCpuTime
void AddInput(const char *fileName, ECbmGenerator generator=kUnigen)
Add an input by file name and generator type.
void SetVertexSmearZ(Bool_t choice=kTRUE)
Enable smearing of event vertex in z.
void ConfigureVMC()
Set the parameters for the TVirtualMC.
void ForceVertexAtZ(Double_t zVertex)
Force the event vertex to be at a given z position.
std::vector< FairGenerator * > fGenerators
void RegisterIons()
Register ions.
void SetParFileName(TString name)
Define parameter file name.
std::unique_ptr< CbmStackFilter > fStackFilter
TString fParFileName
TString fOutFileName
CbmSetup * fSetup
void SetVertexSmearXY(Bool_t choice=kTRUE)
Enable smearing of event vertex in x and y.
void ForceUserDecays()
Force user-defined single-mode decays.
Bool_t fStoreTrajectories
ECbmEngine fEngine
FairField * fField
void InitEventGenerator()
Event generator initialisation.
Double_t fRealTimeRun
void SetSetupSource(ECbmSetupSource setupSource)
Set the source the setup will be loaded from.
void RegisterSetup()
Create and register the setup modules.
CbmGeant4Settings * fGeant4Settings
void Run(Int_t nEvents)
Execute transport run.
TString fGeoFileName
Bool_t fGenerateRunInfo
std::map< Int_t, std::vector< Int_t > > fDecayModes
CbmEventGenerator * fEventGen
void SetBeamAngle(Double_t x0, Double_t y0, Double_t sigmaX=-1., Double_t sigmaY=-1.)
Set the beam angle (emittency at the beam position)
void ForceVertexInTarget(Bool_t choice=kTRUE)
Enable or disable forcing the vertex to be in the target.
Generates input to transport simulation from files in Unigen format.
Int_t GetNumAvailableEvents()
Get the maximum number of events available in the input file.
bool IsRootFile(std::string filename)
Check if a the file exist and is a root file.