SND@LHC Software
Loading...
Searching...
No Matches
MuDISGenerator.cxx
Go to the documentation of this file.
1#include <math.h>
2#include "TSystem.h"
3#include "TROOT.h"
4#include "TMath.h"
5#include "TFile.h"
6#include "TRandom.h"
7#include "FairPrimaryGenerator.h"
8#include "MuDISGenerator.h"
9#include "TGeoVolume.h"
10#include "TGeoNode.h"
11#include "TGeoManager.h"
12#include "TGeoEltu.h"
13#include "TVectorD.h"
14#include "TParticle.h"
15#include "TGeoCompositeShape.h"
16#include "FairMCEventHeader.h"
17
18using std::cout;
19using std::endl;
20// read events from ntuples produced with MuDIS
21// http://MuDIS.hepforge.org/manuals/MuDIS_PhysicsAndUserManual_20130615.pdf
22// MuDIS momentum GeV
23// Vertex in SI units, assume this means m
24// important to read back number of events to give to FairRoot
25
26// ----- Default constructor -------------------------------------------
28// -------------------------------------------------------------------------
29// ----- Default constructor -------------------------------------------
30Bool_t MuDISGenerator::Init(const char* fileName) {
31 return Init(fileName, 0);
32}
33// ----- Default constructor -------------------------------------------
34Bool_t MuDISGenerator::Init(const char* fileName, const int firstEvent) {
35 LOG(INFO) << "Opening input file"<< fileName;
36
37 iMuon = 0;
38 dPart = 0;
39 if (0 == strncmp("/eos",fileName,4) ) {
40 TString tmp = gSystem->Getenv("EOSSHIP");
41 tmp+=fileName;
42 fInputFile = TFile::Open(tmp);
43 LOG(INFO) << "Open external file on eos:"<<tmp.Data();
44 }else{
45 fInputFile = new TFile(fileName);
46 }
47 if (fInputFile->IsZombie() or !fInputFile) {
48 LOG(FATAL) << "Error opening input file";
49 return kFALSE; }
50 fTree = (TTree *)fInputFile->Get("DIS");
51 fNevents = fTree->GetEntries();
52 fn = firstEvent;
53 fTree->SetBranchAddress("run",&runN); // run number
54 fTree->SetBranchAddress("event",&eventN); // event number
55 fTree->SetBranchAddress("InMuon",&iMuon); // incoming muon
56 fTree->SetBranchAddress("Particles",&dPart);
57 return kTRUE;
58}
59Double_t MuDISGenerator::MeanMaterialBudget(const Double_t *start, const Double_t *end, Double_t *mparam)
60{
61 //
62 // Calculate mean material budget and material properties between
63 // the points "start" and "end".
64 //
65 // "mparam" - parameters used for the energy and multiple scattering
66 // corrections:
67 //
68 // mparam[0] - mean density: sum(x_i*rho_i)/sum(x_i) [g/cm3]
69 // mparam[1] - equivalent rad length fraction: sum(x_i/X0_i) [adimensional]
70 // mparam[2] - mean A: sum(x_i*A_i)/sum(x_i) [adimensional]
71 // mparam[3] - mean Z: sum(x_i*Z_i)/sum(x_i) [adimensional]
72 // mparam[4] - length: sum(x_i) [cm]
73 // mparam[5] - Z/A mean: sum(x_i*Z_i/A_i)/sum(x_i) [adimensional]
74 // mparam[6] - number of boundary crosses
75 // mparam[7] - maximum density encountered (g/cm^3)
76 //
77 // Origin: Marian Ivanov, Marian.Ivanov@cern.ch
78 //
79 // Corrections and improvements by
80 // Andrea Dainese, Andrea.Dainese@lnl.infn.it,
81 // Andrei Gheata, Andrei.Gheata@cern.ch
82 //
83
84 mparam[0]=0; mparam[1]=1; mparam[2] =0; mparam[3] =0;
85 mparam[4]=0; mparam[5]=0; mparam[6]=0; mparam[7]=0;
86 //
87 Double_t bparam[6]; // total parameters
88 Double_t lparam[6]; // local parameters
89
90 for (Int_t i=0;i<6;i++) bparam[i]=0;
91
92 if (!gGeoManager) {
93 //AliFatalClass("No TGeo\n");
94 return 0.;
95 }
96 //
97 Double_t length;
98 Double_t dir[3];
99 length = TMath::Sqrt((end[0]-start[0])*(end[0]-start[0])+
100 (end[1]-start[1])*(end[1]-start[1])+
101 (end[2]-start[2])*(end[2]-start[2]));
102 mparam[4]=length;
103 if (length<TGeoShape::Tolerance()) return 0.0;
104 Double_t invlen = 1./length;
105 dir[0] = (end[0]-start[0])*invlen;
106 dir[1] = (end[1]-start[1])*invlen;
107 dir[2] = (end[2]-start[2])*invlen;
108
109 // Initialize start point and direction
110 TGeoNode *currentnode = 0;
111 TGeoNode *startnode = gGeoManager->InitTrack(start, dir);
112 if (!startnode) {
113 //AliErrorClass(Form("start point out of geometry: x %f, y %f, z %f",
114 // start[0],start[1],start[2]));
115 return 0.0;
116 }
117 TGeoMaterial *material = startnode->GetVolume()->GetMedium()->GetMaterial();
118 lparam[0] = material->GetDensity();
119 if (lparam[0] > mparam[7]) mparam[7]=lparam[0];
120 lparam[1] = material->GetRadLen();
121 lparam[2] = material->GetA();
122 lparam[3] = material->GetZ();
123 lparam[4] = length;
124 lparam[5] = lparam[3]/lparam[2];
125 if (material->IsMixture()) {
126 TGeoMixture * mixture = (TGeoMixture*)material;
127 lparam[5] =0;
128 Double_t sum =0;
129 for (Int_t iel=0;iel<mixture->GetNelements();iel++){
130 sum += mixture->GetWmixt()[iel];
131 lparam[5]+= mixture->GetZmixt()[iel]*mixture->GetWmixt()[iel]/mixture->GetAmixt()[iel];
132 }
133 lparam[5]/=sum;
134 }
135
136 // Locate next boundary within length without computing safety.
137 // Propagate either with length (if no boundary found) or just cross boundary
138 gGeoManager->FindNextBoundaryAndStep(length, kFALSE);
139 Double_t step = 0.0; // Step made
140 Double_t snext = gGeoManager->GetStep();
141 // If no boundary within proposed length, return current density
142 if (!gGeoManager->IsOnBoundary()) {
143 mparam[0] = lparam[0];
144 mparam[1] = lparam[4]/lparam[1];
145 mparam[2] = lparam[2];
146 mparam[3] = lparam[3];
147 mparam[4] = lparam[4];
148 return lparam[0];
149 }
150 // Try to cross the boundary and see what is next
151 Int_t nzero = 0;
152 while (length>TGeoShape::Tolerance()) {
153 currentnode = gGeoManager->GetCurrentNode();
154 if (snext<2.*TGeoShape::Tolerance()) nzero++;
155 else nzero = 0;
156 if (nzero>3) {
157 // This means navigation has problems on one boundary
158 // Try to cross by making a small step
159 //AliErrorClass("Cannot cross boundary\n");
160 mparam[0] = bparam[0]/step;
161 mparam[1] = bparam[1];
162 mparam[2] = bparam[2]/step;
163 mparam[3] = bparam[3]/step;
164 mparam[5] = bparam[5]/step;
165 mparam[4] = step;
166 mparam[0] = 0.; // if crash of navigation take mean density 0
167 mparam[1] = 1000000; // and infinite rad length
168 return bparam[0]/step;
169 }
170 mparam[6]+=1.;
171 step += snext;
172 bparam[1] += snext/lparam[1];
173 bparam[2] += snext*lparam[2];
174 bparam[3] += snext*lparam[3];
175 bparam[5] += snext*lparam[5];
176 bparam[0] += snext*lparam[0];
177
178 if (snext>=length) break;
179 if (!currentnode) break;
180 length -= snext;
181 material = currentnode->GetVolume()->GetMedium()->GetMaterial();
182 lparam[0] = material->GetDensity();
183 if (lparam[0] > mparam[7]) mparam[7]=lparam[0];
184 lparam[1] = material->GetRadLen();
185 lparam[2] = material->GetA();
186 lparam[3] = material->GetZ();
187 lparam[5] = lparam[3]/lparam[2];
188 if (material->IsMixture()) {
189 TGeoMixture * mixture = (TGeoMixture*)material;
190 lparam[5]=0;
191 Double_t sum =0;
192 for (Int_t iel=0;iel<mixture->GetNelements();iel++){
193 sum+= mixture->GetWmixt()[iel];
194 lparam[5]+= mixture->GetZmixt()[iel]*mixture->GetWmixt()[iel]/mixture->GetAmixt()[iel];
195 }
196 lparam[5]/=sum;
197 }
198 gGeoManager->FindNextBoundaryAndStep(length, kFALSE);
199 snext = gGeoManager->GetStep();
200 }
201 mparam[0] = bparam[0]/step;
202 mparam[1] = bparam[1];
203 mparam[2] = bparam[2]/step;
204 mparam[3] = bparam[3]/step;
205 mparam[5] = bparam[5]/step;
206 return bparam[0]/step;
207}
208
209// ----- Destructor ----------------------------------------------------
211{
212 fInputFile->Close();
213 fInputFile->Delete();
214 delete fInputFile;
215}
216// ----- Passing the event ---------------------------------------------
217Bool_t MuDISGenerator::ReadEvent(FairPrimaryGenerator* cpg)
218{
219 if (fn==fNevents) {LOG(WARNING) << "End of input file. Rewind.";}
220 fTree->GetEntry(fn%fNevents);
221 fn++;
222 if (fn%10000==0) {
223 LOG(INFO) << " heartbeat event-nr "<< fn;
224 }
225 int nf = dPart->GetEntries();
226 LOG(DEBUG) << "*********************************************************";
227 LOG(DEBUG) << " " << iMuon->GetEntries()<< " "<< iMuon->AddrAt(0) << " nf "<< nf << " fn=" << fn ;
228
229 //some start/end positions in z (f.i. emulsion to Tracker 1)
230 Double_t start[3]={0.,0.,startZ};
231 Double_t end[3]={0.,0.,endZ};
232
233 TParticle* mu = dynamic_cast<TParticle*>(iMuon->AddrAt(0));
234 LOG(DEBUG) << " in muon " << mu->GetPdgCode()<< endl;
235 Double_t x = mu->Vx();
236 Double_t y = mu->Vy();
237 Double_t z = mu->Vz();
238 Double_t w = mu->GetWeight();
239// calculate start/end positions along this muon, and amout of material in between
240 Double_t txmu=mu->Px()/mu->Pz();
241 Double_t tymu=mu->Py()/mu->Pz();
242 start[0]=x-(z-start[2])*txmu;
243 start[1]=y-(z-start[2])*tymu;
244 end[0] =x-(z-end[2])*txmu;
245 end[1] =y-(z-end[2])*tymu;
246 LOG(DEBUG) << " mu xyz position " << x << ", " << y << ", " << z << endl;
247 LOG(DEBUG) << " mu pxyz " << mu->Px() << ", " << mu->Py() << ", " << mu->Pz() ;
248 LOG(DEBUG) << " mu weight " << w ;
249 LOG(DEBUG) << " start position " << start[0] << ", " << start[1] << ", " << start[2] ;
250 LOG(DEBUG) << " end position " << end[0] << ", " << end[1] << ", " << end[2] ;
251 Double_t bparam;
252 Double_t mparam[8];
253 bparam=MeanMaterialBudget(start, end, mparam);
254 //loop over trajectory between start and end to pick an interaction point
255 Double_t prob2int = 0.;
256 Double_t xmu;
257 Double_t ymu;
258 Double_t zmu;
259 Int_t count=0;
260 LOG(DEBUG) << " Start prob2int while loop, bparam= " << bparam << ", " << bparam*1.e8 ;
261 LOG(DEBUG) << " What was maximum density, mparam[7]= " << mparam[7] << ", " << mparam[7]*1.e8 ;
262 while (prob2int<gRandom->Uniform(0.,1.)) {
263 zmu=gRandom->Uniform(start[2],end[2]);
264 xmu=x-(z-zmu)*txmu;
265 ymu=y-(z-zmu)*tymu;
266 //get local material at this point
267 TGeoNode *node = gGeoManager->FindNode(xmu,ymu,zmu);
268 TGeoMaterial *mat = 0;
269 if (node && !gGeoManager->IsOutside()) mat = node->GetVolume()->GetMaterial();
270 LOG(DEBUG) << "mat " << count << ", " << mat->GetName() << ", " << mat->GetDensity();
271 //density relative to Prob largest density along this trajectory, i.e. use rho(Pt)
272 prob2int= mat->GetDensity()/mparam[7];
273 if (prob2int>1.) LOG(WARNING) << "***WARNING*** MuDISGenerator: prob2int > Maximum density????" << prob2int << " maxrho:" << mparam[7] << " material: " << mat->GetName();
274 count+=1;
275 }
276 LOG(DEBUG) << "prob2int " << prob2int << ", " << count ;
277
278 LOG(DEBUG) << "put position " << xmu << ", " << ymu << ", " << zmu;
279 //modify weight, by multiplying with average densiy along track??
280 cpg->AddTrack(mu->GetPdgCode(),mu->Px(),mu->Py(),mu->Pz(),xmu,ymu,zmu,-1,false,mu->Energy(),mu->T(),w);
281 // in order to have a simulation of possible veto detector hits, let Geant4 follow the muon backward
282 // due to dE/dx, as soon as the muon travers thick material, this approximation will become bad.
283 // a proper implementation however would be to have this better integrated in Geant4, follow the muon, call DIS event, continue
284 cpg->AddTrack(mu->GetPdgCode(),-(mu->Px()),-(mu->Py()),-(mu->Pz()),xmu,ymu,zmu,0,true,mu->Energy(),mu->T(),w);
285// outgoing particles, [did,dpx,dpy,dpz,E], put density along trajectory as weight, g/cm^2
286 w=mparam[0]*mparam[4];
287 for(int i=0; i<nf; i++)
288 {
289 TParticle* Part = dynamic_cast<TParticle*>(dPart->AddrAt(i));
290 cpg->AddTrack(Part->GetPdgCode(),Part->Px(),Part->Py(),Part->Pz(),xmu,ymu,zmu,0,true,Part->Energy(),mu->T(),w);
291 }
292
293 // Set the generation run and event numbers through the MC event header
294 FairMCEventHeader* header = cpg->GetEvent();
295 header->SetEventID(eventN);
296 header->SetRunID(runN);
297
298 return kTRUE;
299}
300// -------------------------------------------------------------------------
302{
303 return fNevents;
304}
305
Bool_t ReadEvent(FairPrimaryGenerator *)
Double_t MeanMaterialBudget(const Double_t *start, const Double_t *end, Double_t *mparam)
virtual ~MuDISGenerator()
TFile * fInputFile
don't make it persistent, magic ROOT command
TClonesArray * iMuon
virtual Bool_t Init(const char *, int)
TClonesArray * dPart
ClassImp(ecalContFact) ecalContFact