er  dev
ERDecayEXP1811.cxx
1 /********************************************************************************
2  * Copyright (C) Joint Institute for Nuclear Research *
3  * *
4  * This software is distributed under the terms of the *
5  * GNU Lesser General Public Licence version 3 (LGPL) version 3, *
6  * copied verbatim in the file "LICENSE" *
7  ********************************************************************************/
8 
9 #include "ERDecayEXP1811.h"
10 
11 #include <iostream>
12 #include <string>
13 #include <sstream>
14 using namespace std;
15 
16 #include "TVirtualMC.h"
17 #include "TLorentzVector.h"
18 #include "TMCProcess.h"
19 #include "TRandom.h"
20 #include "TVector.h"
21 
22 #include "FairRunSim.h"
23 #include "FairLogger.h"
24 
25 #include "ERDecayMCEventHeader.h"
26 #include "EREXP1811EventHeader.h"
27 #include "ERMCEventHeader.h"
28 
29 #include "G4IonTable.hh"
30 
31 ERDecayEXP1811::ERDecayEXP1811():
32  ERDecay("EXP1811"),
33  fDecayFinish(kFALSE),
34  fTargetReactZ(0.),
35  fMinStep(0.01),
36  f8He(NULL),
37  f2H (NULL),
38  f3He(NULL),
39  f7H (NULL),
40  f3H (NULL),
41  fn (NULL),
42  fIon3He(NULL),
43  f7HMass(0.),
44  fIs7HUserMassSet(false),
45  fIs7HExcitationSet(false),
46  fADInput(NULL),
47  fADFunction(NULL),
48  fDecayFilePath(""),
49  fDecayFileFinished(kFALSE),
50  fDecayFileCurrentEvent(0)
51 {
52  fRnd = new TRandom3();
53  // fRnd->SetSeed();
54  fRnd2 = new TRandom3();
55  fRnd2->SetSeed();
56  fReactionPhaseSpace = new TGenPhaseSpace();
57  fDecayPhaseSpace = new TGenPhaseSpace();
58  FairRunSim* run = FairRunSim::Instance();
59  fUnstableIon7H = new FairIon("7H", 1, 7, 1);
60  fIon3He = new FairIon("3He", 2, 3, 2);
61  run->AddNewIon(fUnstableIon7H);
62  run->AddNewIon(fIon3He);
63 
64  fLv7H = new TLorentzVector();
65  fLv3He = new TLorentzVector();
66 }
67 
68 //-------------------------------------------------------------------------------------------------
69 ERDecayEXP1811::~ERDecayEXP1811() {
70  if (fDecayFile.is_open())
71  fDecayFile.close();
72  if (fDecayFilePath == ""){ // LV from TGenPhaseSpace will be deleted in TGenPhaseSpace
73  if (fLv3H){
74  delete fLv3H;
75  delete fLvn1;
76  delete fLvn2;
77  delete fLvn3;
78  delete fLvn4;
79  }
80  }
81 }
82 
83 //-------------------------------------------------------------------------------------------------
84 void ERDecayEXP1811::SetH7Exitation(Double_t excMean, Double_t fwhm, Double_t distibWeight) {
85  f7HExcitationMean.push_back(excMean);
86  f7HExcitationSigma.push_back(fwhm / 2.355);
87  if (!fIs7HExcitationSet) {
88  f7HExcitationWeight.push_back(distibWeight);
89  fIs7HExcitationSet = true;
90  return ;
91  }
92  f7HExcitationWeight.push_back(f7HExcitationWeight.back() + distibWeight);
93 }
94 
95 //-------------------------------------------------------------------------------------------------
96 Bool_t ERDecayEXP1811::Init() {
97 
98  cout << "Decayer Init." << endl;
99 
100  f8He = TDatabasePDG::Instance()->GetParticle("8He");
101  if ( ! f8He ) {
102  std::cerr << "-W- ERDecayEXP1811: Ion 8He not found in database!" << endl;
103  return kFALSE;
104  }
105 
106  f2H = TDatabasePDG::Instance()->GetParticle("Deuteron");
107  if ( ! f2H ) {
108  std::cerr << "-W- ERDecayEXP1811: Ion Deuteron not found in database!" << endl;
109  return kFALSE;
110  }
111 
112  f7H = TDatabasePDG::Instance()->GetParticle("7H");
113  if ( ! f7H ) {
114  std::cerr << "-W- ERDecayEXP1811: Ion 7H not found in database!" << endl;
115  return kFALSE;
116  }
117 
118  f3He = TDatabasePDG::Instance()->GetParticle(fIon3He->GetName());
119  if ( ! f3He ) {
120  std::cerr << "-W- ERDecayEXP1811: Ion 3He not found in database!" << endl;
121  return kFALSE;
122  }
123 
124  f3H = TDatabasePDG::Instance()->GetParticle("Triton");
125  if ( ! f3H ) {
126  std::cerr << "-W- ERDecayEXP1811: Ion Triton not found in database!" << endl;
127  return kFALSE;
128  }
129 
130  fn = TDatabasePDG::Instance()->GetParticle("neutron");
131  if ( ! fn ) {
132  std::cerr << "-W- ERDecayEXP1811: Particle neutron not found in database!" << endl;
133  return kFALSE;
134  }
135  if (fIs7HUserMassSet) {
136  fUnstableIon7H->SetMass(f7HMass / .931494028);
137  } else {
138  f7HMass = f7H->Mass(); // if user mass is not defined in ERDecayEXP1811::SetH7Mass() than get a GEANT mass
139  }
140  CalculateTargetParameters();
141 
142 
143  if (fDecayFilePath != ""){
144  LOG(INFO) << "Use decay kinematics from external text file" << FairLogger::endl;
145  fDecayFile.open(fDecayFilePath.Data());
146  if (!fDecayFile.is_open())
147  LOG(FATAL) << "Can`t open decay file " << fDecayFilePath << FairLogger::endl;
148  //Пропускаем шапку файла
149  std::string header;
150  std::getline(fDecayFile,header);
151 
152  fLv3H = new TLorentzVector();
153  fLvn1 = new TLorentzVector();
154  fLvn2 = new TLorentzVector();
155  fLvn3 = new TLorentzVector();
156  fLvn4 = new TLorentzVector();
157  }
158 
159  return kTRUE;
160 }
161 
162 //-------------------------------------------------------------------------------------------------
163 Bool_t ERDecayEXP1811::Stepping() {
164  if(!fDecayFinish && gMC->TrackPid() == 1000020080
165  && TString(gMC->CurrentVolName()).Contains(GetInteractionVolumeName()))
166  {
167  if (!fIsInterationPointFound) {
168  if (!FindInteractionPoint()) {
169  fDecayFinish = kTRUE;
170  return kTRUE;
171  } else {
172  fDistanceFromEntrance = 0;
173  }
174  }
175  gMC->SetMaxStep(fMinStep);
176  TLorentzVector curPos;
177  gMC->TrackPosition(curPos);
178  Double_t trackStep = gMC->TrackStep();
179  fDistanceFromEntrance += trackStep;
180  // std::cout << "Track step: " << fDistanceFromEntrance << "; Diff " << (curPos.Vect() - fInputPoint).Mag() << endl;
181  // std::cout << "Track step: " << fDistanceFromEntrance << endl;
182  if (fDistanceFromEntrance > fDistanceToInteractPoint) {
183  // std::cout << "Start reation in target. Defined pos: " << fDistanceToInteractPoint << ", current pos: " << curPos.Z() << endl;
184 
185  // 8He + 2H → 3He + 7H
186  TLorentzVector lv8He;
187  gMC->TrackMomentum(lv8He);
188 
189  if (lv8He.P() == 0) { // temporary fix of bug with zero kinetic energy
190  return kTRUE;
191  }
192 
193  TLorentzVector lv2H(0., 0., 0., 1.875612);
194  TLorentzVector lvReaction;
195  lvReaction = lv8He + lv2H;
196 
197  const TVector3 boost = lvReaction.BoostVector(); //Get Pcm 3 vector
198  Double_t ECM = 0;
199  TLorentzVector lv8HeCM, lv2HCM;
200  lv8HeCM = lv8He;
201  lv2HCM = lv2H;
202  lv8HeCM.Boost(-boost);
203  lv2HCM.Boost(-boost);
204  ECM = lv8HeCM(3) + lv2HCM(3);
205 
206  Int_t reactionHappen = kFALSE;
207 
208  Double_t decay7HMass;
209  Int_t reactionAttempsCounter = 0;
210  Double_t excitation = 0; // excitation energy
211  while (reactionHappen==kFALSE) { // while reaction condition is not fullfilled
212  decay7HMass = f7HMass;
213  if (fIs7HExcitationSet) {
214  Double_t randWeight = gRandom->Uniform(0., f7HExcitationWeight.back());
215  Int_t distribNum = 0;
216  // choose distribution by weight
217  for (; distribNum < f7HExcitationWeight.size(); distribNum++) {
218  if (randWeight < f7HExcitationWeight[distribNum]) {
219  break;
220  }
221  }
222  excitation = gRandom->Gaus(f7HExcitationMean[distribNum], f7HExcitationSigma[distribNum]);
223  fUnstableIon7H->SetExcEnergy(excitation);
224  }
225  decay7HMass += excitation;
226  const float he3_mass = G4IonTable::GetIonTable()->GetIon(2,3)->GetPDGMass() * 1e-3;
227  if((ECM - he3_mass - decay7HMass) > 0) { // выход из цикла while для PhaseGenerator
228  reactionHappen = kTRUE;
229  LOG(DEBUG) << "[ERDecayEXP1811] Reaction is happen" << endl;
230  }
231  reactionAttempsCounter++;
232  if (reactionAttempsCounter > 1000){
233  LOG(DEBUG) << "[ERDecayEXP1811] Reaction is forbidden for this CM energy" << endl;
234  fDecayFinish = kTRUE;
235  return kTRUE;
236  }
237  }
238 
239  ReactionPhaseGenerator(ECM, decay7HMass);
240  fLv7H->Boost(boost);
241  fLv3He->Boost(boost);
242 
243  //7H → f3H + n +n +n +n
244  if (!DecayPhaseGenerator(excitation)){
245  fDecayFinish = kTRUE;
246  return kTRUE;
247  }
248 
249  Int_t He8TrackNb, H7TrackNb, He3TrackNb, H3TrackNb, n1TrackNb, n2TrackNb, n3TrackNb, n4TrackNb;
250 
251  He8TrackNb = gMC->GetStack()->GetCurrentTrackNumber();
252  // std::cout << "He8TrackNb " << He8TrackNb << std::endl;
253  /*
254  gMC->GetStack()->PushTrack(1, He8TrackNb, f7H->PdgCode(),
255  fLv7H->Px(), fLv7H->Py(), fLv7H->Pz(),
256  fLv7H->E(), curPos.X(), curPos.Y(), curPos.Z(),
257  gMC->TrackTime(), 0., 0., 0.,
258  kPDecay, H7TrackNb, decay7HMass, 0);*/
259 
260  gMC->GetStack()->PushTrack(1, He8TrackNb, f3He->PdgCode(),
261  fLv3He->Px(), fLv3He->Py(), fLv3He->Pz(),
262  fLv3He->E(), curPos.X(), curPos.Y(), curPos.Z(),
263  gMC->TrackTime(), 0., 0., 0.,
264  kPDecay, He3TrackNb, f3He->Mass(), 0);
265  gMC->GetStack()->PushTrack(1, He8TrackNb, f3H->PdgCode(),
266  fLv3H->Px(), fLv3H->Py(), fLv3H->Pz(),
267  fLv3H->E(), curPos.X(), curPos.Y(), curPos.Z(),
268  gMC->TrackTime(), 0., 0., 0.,
269  kPDecay, H3TrackNb, f3H->Mass(), 0);
270  gMC->GetStack()->PushTrack(1, He8TrackNb, fn->PdgCode(),
271  fLvn1->Px(),fLvn1->Py(),fLvn1->Pz(),
272  fLvn1->E(), curPos.X(), curPos.Y(), curPos.Z(),
273  gMC->TrackTime(), 0., 0., 0.,
274  kPDecay, n1TrackNb, fn->Mass(), 0);
275  gMC->GetStack()->PushTrack(1, He8TrackNb, fn->PdgCode(),
276  fLvn2->Px(),fLvn2->Py(),fLvn2->Pz(),
277  fLvn2->E(), curPos.X(), curPos.Y(), curPos.Z(),
278  gMC->TrackTime(), 0., 0., 0.,
279  kPDecay, n2TrackNb, fn->Mass(), 0);
280  gMC->GetStack()->PushTrack(1, He8TrackNb, fn->PdgCode(),
281  fLvn3->Px(),fLvn3->Py(),fLvn3->Pz(),
282  fLvn3->E(), curPos.X(), curPos.Y(), curPos.Z(),
283  gMC->TrackTime(), 0., 0., 0.,
284  kPDecay, n3TrackNb, fn->Mass(), 0);
285  gMC->GetStack()->PushTrack(1, He8TrackNb, fn->PdgCode(),
286  fLvn4->Px(),fLvn4->Py(),fLvn4->Pz(),
287  fLvn4->E(), curPos.X(), curPos.Y(), curPos.Z(),
288  gMC->TrackTime(), 0., 0., 0.,
289  kPDecay, n4TrackNb, fn->Mass(), 0);
290  gMC->StopTrack();
291  fDecayFinish = kTRUE;
292  gMC->SetMaxStep(100.);
293 
294  FairRunSim* run = FairRunSim::Instance();
295  if (TString(run->GetMCEventHeader()->ClassName()).Contains("ERDecayMCEventHeader")){
296  ERDecayMCEventHeader* header = (ERDecayMCEventHeader*)run->GetMCEventHeader();
297  header->SetDecayPos(curPos.Vect());
298  header->SetInputIon(He8TrackNb);
299  header->AddOutputParticle(H7TrackNb);
300  header->AddOutputParticle(He3TrackNb);
301  header->AddOutputParticle(H3TrackNb);
302  header->AddOutputParticle(n1TrackNb);
303  header->AddOutputParticle(n2TrackNb);
304  header->AddOutputParticle(n3TrackNb);
305  header->AddOutputParticle(n4TrackNb);
306  }
307  if (TString(run->GetMCEventHeader()->ClassName()).Contains("EREXP1811EventHeader")){
308  EREXP1811EventHeader* header = (EREXP1811EventHeader*)run->GetMCEventHeader();
309  header->SetData(curPos.Vect(), lv8He, lv2H, *fLv3He, *fLv3H, *fLv7H, *fLvn1, *fLvn2, *fLvn3, *fLvn4);
310  header->SetTrigger(1);
311  }
312  }
313  }
314  return kTRUE;
315 }
316 
317 //-------------------------------------------------------------------------------------------------
318 void ERDecayEXP1811::BeginEvent() {
319  fDecayFinish = kFALSE;
320  fIsInterationPointFound = kFALSE;
321  fTargetReactZ = fRnd->Uniform(-fTargetThickness / 2, fTargetThickness / 2);
322  FairRunSim* run = FairRunSim::Instance();
323 }
324 
325 //-------------------------------------------------------------------------------------------------
326 void ERDecayEXP1811::FinishEvent() {
327  FairRunSim* run = FairRunSim::Instance();
328  if (TString(run->GetMCEventHeader()->ClassName()).Contains("ERDecayMCEventHeader")){
329  ERDecayMCEventHeader* header = (ERDecayMCEventHeader*)run->GetMCEventHeader();
330  header->Clear();
331  }
332  if (TString(run->GetMCEventHeader()->ClassName()).Contains("EREXP1811EventHeader")){
333  EREXP1811EventHeader* header = (EREXP1811EventHeader*)run->GetMCEventHeader();
334  header->Clear();
335  }
336 }
337 
338 //-------------------------------------------------------------------------------------------------
339 void ERDecayEXP1811::ReactionPhaseGenerator(Double_t Ecm, Double_t h7Mass) {
340  Double_t m1 = h7Mass;
341  Double_t m2 = G4IonTable::GetIonTable()->GetIon(2,3)->GetPDGMass() * 1e-3;
342 
343  // Energy of 1-st particle in cm.
344  // total energy of the first particle is calculated as
345  Double_t E1 = 0.5 * (Ecm * Ecm + m1 * m1 - m2 * m2) / Ecm;
346 
347  //Impulse in CM
348  Double_t Pcm = TMath::Sqrt(E1 * E1 - m1 * m1);
349  //Generate angles of particles in CM
350  Double_t thetaCM;
351  if(!fADInput) { // if file with angular distribution isn't setted than isotropic distribution is generated
352  thetaCM = TMath::ACos(gRandom->Uniform(-1, 1));
353  } else {
354  thetaCM = fADFunction->GetRandom(fThetaMin, fThetaMax)*TMath::DegToRad();
355  }
356  Double_t phi = gRandom->Uniform(0., 2. * TMath::Pi());
357  TVector3 Pcmv;
358  Pcmv.SetMagThetaPhi(Pcm, thetaCM, phi);
359 
360  fLv7H->SetXYZM(0., 0., 0., 0.);
361  fLv3He->SetXYZM(0., 0., 0., 0.);
362  fLv7H->SetXYZM(Pcmv(0), Pcmv(1), Pcmv(2), m1);
363  fLv3He->SetXYZM(-Pcmv(0), -Pcmv(1), -Pcmv(2), m2);
364 }
365 
366 //-------------------------------------------------------------------------------------------------
367 Bool_t ERDecayEXP1811::DecayPhaseGenerator(const Double_t excitation) {
368  if (fDecayFilePath == ""){ // if decay file not defined, per morm decay using phase space
369  Double_t decayMasses[5];
370  decayMasses[0] = f3H->Mass();
371  decayMasses[1] = fn->Mass();
372  decayMasses[2] = fn->Mass();
373  decayMasses[3] = fn->Mass();
374  decayMasses[4] = fn->Mass();
375  fDecayPhaseSpace->SetDecay(*fLv7H, 5, decayMasses);
376  fDecayPhaseSpace->Generate();
377  fLv3H = fDecayPhaseSpace->GetDecay(0);
378  fLvn1 = fDecayPhaseSpace->GetDecay(1);
379  fLvn2 = fDecayPhaseSpace->GetDecay(2);
380  fLvn3 = fDecayPhaseSpace->GetDecay(3);
381  fLvn4 = fDecayPhaseSpace->GetDecay(4);
382  return kTRUE;
383  }
384  if (fDecayFile.eof()){
385  LOG(ERROR) << "Decay file finished! There are no more events in file " << fDecayFilePath
386  << " to be processed." << FairLogger::endl;
387  return kFALSE;
388  }
389  std::string event_line;
390  std::getline(fDecayFile,event_line);
391  std::istringstream iss(event_line);
392  std::vector<std::string> outputs_components((std::istream_iterator<std::string>(iss)),
393  std::istream_iterator<std::string>());
394  if (outputs_components.size() < 5*3){
395  LOG(ERROR) << "Wrong components number in raw in decay file!" << FairLogger::endl;
396  return kFALSE;
397  }
398  // Fill momentum vectors in CM.
399  TVector3 pn1(std::stod(outputs_components[0]),std::stod(outputs_components[1]),
400  std::stod(outputs_components[2]));
401  TVector3 pn2(std::stod(outputs_components[3]),std::stod(outputs_components[4]),
402  std::stod(outputs_components[5]));
403  TVector3 pn3(std::stod(outputs_components[6]),std::stod(outputs_components[7]),
404  std::stod(outputs_components[8]));
405  TVector3 pn4(std::stod(outputs_components[9]),std::stod(outputs_components[10]),
406  std::stod(outputs_components[11]));
407  TVector3 p3H(std::stod(outputs_components[12]),std::stod(outputs_components[13]),
408  std::stod(outputs_components[14]));
409  // Apply scale factor
410  const auto excitationScale = excitation > 0. ? sqrt(excitation / fDecayFileExcitation) : 1.;
411  const auto MeV2GeV = 1./1000.;
412  const auto scale = excitationScale * MeV2GeV;
413  pn1 *= scale;
414  pn2 *= scale;
415  pn3 *= scale;
416  pn4 *= scale;
417  p3H *= scale;
418  const auto fill_output_lorentz_vectors_in_lab =
419  [this](TLorentzVector* lv, const TVector3& p, const Double_t mass) {
420  lv->SetXYZM(p.X(), p.Y(), p.Z(), mass);
421  lv->Boost(fLv7H->BoostVector());
422  };
423  fill_output_lorentz_vectors_in_lab(fLvn1, pn1, fn->Mass());
424  fill_output_lorentz_vectors_in_lab(fLvn2, pn2, fn->Mass());
425  fill_output_lorentz_vectors_in_lab(fLvn3, pn3, fn->Mass());
426  fill_output_lorentz_vectors_in_lab(fLvn4, pn4, fn->Mass());
427  fill_output_lorentz_vectors_in_lab(fLv3H, p3H, f3H->Mass());
428  return kTRUE;
429 }
430 
431 //-------------------------------------------------------------------------------------------------
432 Double_t ERDecayEXP1811::ADEvaluate(Double_t *x, Double_t *p) {
433  if (fADInput->IsZombie()) {
434  Error("ERDecayEXP1811::ADEvaluate", "AD input was not loaded");
435  return -1;
436  }
437  // on each step of creating distribution function returns interpolated value of input data
438  return fADInput->Eval(x[0]);
439 }
440 
441 //-------------------------------------------------------------------------------------------------
443  TString ADFilePath = gSystem->Getenv("VMCWORKDIR");
444  ADFilePath += "/input/" + ADFile;
445  std::ifstream f;
446  f.open(ADFilePath.Data());
447  if (!f.is_open()) {
448  LOG(FATAL) << "Can't open file " << ADFilePath << FairLogger::endl;
449  }
450  Int_t nPoints = std::count(std::istreambuf_iterator<char>(f),
451  std::istreambuf_iterator<char>(), '\n');
452  f.seekg(0, std::ios::beg);
453  TVectorD tet(nPoints);
454  TVectorD sigma(nPoints);
455  LOG(DEBUG2) << "nPoints = " << nPoints << FairLogger::endl;
456  Int_t i = 0;
457  while (!f.eof()) {
458  // Костыль
459  if (i == nPoints) break;
460  f >> tet(i) >> sigma(i);
461  LOG(DEBUG2) << i << ": " << tet(i) << "\t" << sigma(i) << FairLogger::endl;
462  i++;
463  }
464  fADInput = new TGraph(tet, sigma);
465  if (fADInput->GetN() <= 0) { //if there are no points in input file
466  LOG(INFO) << "ERDecayEXP1811::SetAngularDistribution: "
467  << "Too few inputs for creation of AD function!" << FairLogger::endl;
468  return;
469  }
470  Double_t* angle = fADInput->GetX(); // get first column variables that contains number of point
471 
472  // Creation of angular distribution function using class member function.
473  // Constructor divides interval (0; fADInput->GetN()-1) into grid.
474  // On each step of grid it calls ADEvaluate() to get interpolated values of input data.
475  fThetaMin = angle[0];
476  fThetaMax = angle[fADInput->GetN()-1];
477  fADFunction = new TF1("angDistr", this, &ERDecayEXP1811::ADEvaluate,
478  fThetaMin, fThetaMax, 0, "ERDecayEXP1811", "ADEvaluate");
479  fADFunction->Eval(1.);
480 }
481 //-------------------------------------------------------------------------------------------------
482 ClassImp(ERDecayEXP1811)
void SetAngularDistribution(TString ADfile)
Sets distribution is contained in file.
TF1 * fADFunction
distribution (angular distribution) graph containing AD input
TString GetInteractionVolumeName()
Method returns interaction volume name.
Definition: ERDecay.h:45
void ReactionPhaseGenerator(Double_t Ecm, Double_t h7Mass)
Body reaction in phase space approach.
Bool_t FindInteractionPoint()
Definition: ERDecay.cxx:122