HighLAND
PionInteractionSystematic.cxx
1 #include "PionInteractionSystematic.hxx"
2 #include "TFile.h"
3 #include "GeometryManager.hxx"
4 
5 //JMDEBUGVERSION code:
6 //0 is 2013
7 //1 is OR'ed volumes of interest. Should reproduce 2013 exactly with FGD1 only
8 //selection, and have a similar treatment for FGD2.
9 //2 is VOI extended to include both VOIs and the TPC between them.
10 //3 new: VOI is FGD1 for selections in FGD1 and FGD2 for selections in FGD2 (automatic)
11 #define JMDEBUGVERSION 1
12 
13 
14 //For easy access to the cross section data.
15 using namespace PiXSec;
16 
17 
18 //Empty, do nothing constructor, as we fill it manually.
19 //Loads the geometry, so a new object must be created before begin computations
20 //of the quantities that go in this object.
21 PionInteractionSystematic::PionInteractionSystematic(){
22 
23  nPions = 0;
24  pionType = NULL;
25 
26  totalSteps = 0;
27  nSteps = NULL;
28 
29  initMom = NULL;
30 
31  stepLengths = NULL;
32 
33  nInteractions = 0;
34  pInteraction = NULL;
35  typeInteraction = NULL;
36 
37  pionID = NULL;
38  TrueParticles = NULL;
39  InteractionTrueParticles = NULL;
40 
41 }
42 
43 PionInteractionSystematic::~PionInteractionSystematic(){
44  if(pionType)
45  delete [] pionType;
46  pionType = NULL;
47 
48  if(nSteps)
49  delete [] nSteps;
50  nSteps = NULL;
51 
52  if(initMom)
53  delete [] initMom;
54  initMom = NULL;
55 
56  if(pInteraction)
57  delete [] pInteraction;
58  pInteraction = NULL;
59 
60  if(typeInteraction)
61  delete [] typeInteraction;
62  typeInteraction = NULL;
63 
64  if(pionID)
65  delete [] pionID;
66  pionID = NULL;
67 
68  if(TrueParticles)
69  delete [] TrueParticles;
70  TrueParticles = NULL;
71 
72  if(InteractionTrueParticles)
73  delete [] InteractionTrueParticles;
74  InteractionTrueParticles = NULL;
75 
76 
77  if(stepLengths)
78  delete [] stepLengths;
79  stepLengths = NULL;
80 }
81 
82 
83 
84 
85 //Define the constructor for the StepResult object.
86 SteppingResult::SteppingResult(Float_t mcSum,
87  Float_t dataSum,
88  std::vector<Float_t> steps,
89  Float_t momFinal,
90  TLorentzVector posFinal){
91 
92  MCSumNSigmaStepLength = mcSum;
93  DataSumNSigmaStepLength = dataSum;
94  stepLengths = steps;
95  finalMom = momFinal;
96  finalPos = posFinal;
97 }
98 
99 //===================================================================
100 //Stepping Code.
101 //===================================================================
102 //Density of scattering centres.
103 //i.e. the number of atoms per unit volume.
104 //Any ignored elements (H, Na, Ti) aren't considered.
105 //Also, the answer for FGDScintillator will differ slightly from the
106 //pre-calculated FGDScintillator value due to the inclusion of small amounts
107 //of N and O.
108 //N = (N_A/M_r)*rho
109 //Where N is the number density (particles/cm^3), N_A is Avogadro's constant,
110 //M_r is the molar mass, and rho is the density.
111 //For a composite, material, if w_j is the fraction by weight,
112 //rho*wj gives the density of that element, sub that in for rho in
113 //the above equation, and that gives the number of that element
114 //per unit volume.
115 //Could be calculated separately and tabulated in a function that returns the
116 //right one when supplied with a given material name.
117 //This function takes in a pointer to a
118 //material and computes it.
119 //Use it to fill a map at run time that can then consult instead of recalculating.
120 //The FGDScintillator value is pre-computed and hard-coded where needed.
121 Double_t DScattCentres(TGeoMixture* mixture){
122 
123  //Get the atomic number, mass (i.e. molar mass) and weight by mass arrays,
124  //as well as the number of elements.
125  Double_t* ZArray = mixture->GetZmixt();
126  Double_t* AArray = mixture->GetAmixt();
127  Double_t* WArray = mixture->GetWmixt();
128  Int_t NElts = mixture->GetNelements();
129 
130  //Avogadro's constant (according to the PDG, last two decimal places removed).
131  Double_t NA = 6.02214e23;
132 
133  //Go through and compute the number of scattering centres of each element per unit
134  //volume. Add them together to get the total number of scattering centres per
135  //unit volume.
136  Double_t result = 0;
137  for(Int_t i = 0; i< NElts; i++){
138 
139  if(ZArray[i] != 1 //Exclude H
140  && ZArray[i] != 11 //Exclude Na
141  && ZArray[i] != 22){ //Exclude Ti
142 
143  //Extra factor required to convert density to g/cm^3
144  result += (NA/AArray[i])*WArray[i]*((1000.0/(6.2415e21))*mixture->GetDensity());
145  }
146  }
147 
148  //All constituents having now been looped over, return the value.
149  return result;
150 }
151 
152 //Takes in a material name and returns the "material Series" number,
153 //a multiple of 10 that is used to tabulate the cross sections.
154 //Key:
155 //Carbon: 0
156 //Oxygen: 10
157 //Aluminum: 20
158 //Iron: 30
159 //AlG10: 40
160 //WaterSystem: 50
161 //G10FGD1, G10: 60
162 //FGDGlue: 70
163 //G10Roha: 80
164 Int_t GetMaterialSeries(std::string matName){
165 
166  //Air, use O.
167  if (matName == "Air") return 10;
168  //CO2, use O.
169  else if (matName == "CO2") return 10;
170  //Aluminum
171  else if (matName == "Aluminum") return 20;
172  //Steel, use Fe.
173  else if (matName == "Steel") return 30;
174  //AlRoha2 or AlRoha, use Aluminum.
175  else if (matName == "AlRoha" || matName == "AlRoha2") return 20;
176  //AlG10
177  else if (matName == "AlG10") return 40;
178  //WaterSystem
179  else if (matName == "WaterSystem") return 50;
180  //G10FGD1/G10
181  else if (matName == "G10FGD1" || matName == "G10") return 60;
182  //FGDScintillator (use Carbon)
183  //There are some extra letters beyond "FGDScintillator" possible
184  //in the name of this material.
185  else if (matName.find("FGDScintillator") != std::string::npos) return 0;
186  //FGDGlue
187  else if (matName == "FGDGlue") return 70;
188  //G10Roha
189  else if (matName == "G10Roha") return 80;
190  //-----------------------------
191  //New materials added for 2014.
192  //-----------------------------
193  //G10FGD2 has the same composition as G10 and G10FGD1, as far as molar
194  //fractions of elements are concerned.
195  else if (matName == "G10FGD2") return 60;
196  //ActiveWater gets approximated by Oxygen.
197  else if (matName == "ActiveWater") return 10;
198  //Polypropylene is just Carbon and (ignored) Hydrogen
199  else if (matName == "Polypropylene") return 0;
200  //FGDWaterModuleEpoxy has the same composition as FGDGlue (70 series).
201  else if (matName == "FGDWaterModuleEpoxy") return 70;
202  //GasMixtureTPC is mostly Argon. The closest element we have to Argon is
203  //Aluminum, which is not a great approximation, but with such a low density
204  //of scattering centres in the TPC Gas, should be good enough, and is
205  //certainly closer than the Carbon we would otherwise default to.
206  //NB: The Material Series is only for which set of pion cross sections to
207  //use. Other properties (like density) are determined from data taken from
208  //the geometry.
209  else if (matName == "GasMixtureTPC") return 20;
210  //If it was something we've somehow missed, just use Carbon.
211  else return 0;
212 }
213 
214 //Takes in an atomic number and returns the Mean Ionization Potential for
215 //that element, from http://physics.nist.gov/PhysRefData/XrayMassCoef/tab1.html
216 //Only filled for elements present in ND280UserDetectorConstruction.cc
217 //Uses units of eV. Must be converted to MeV later.
218 Double_t GetIElement(Int_t Z){
219 
220  switch(Z){
221  case 1: //Hydrogen
222  return 19.2;
223  case 5: //Boron
224  return 76.0;
225  case 6: //Carbon
226  return 78.0;
227  case 7: //Nitrogen
228  return 82.0;
229  case 8: //Oxygen
230  return 95.0;
231  case 9: //Fluorine
232  return 115.0;
233  case 11: //Sodium
234  return 149.0;
235  case 13: //Aluminum
236  return 166.0;
237  case 14: //Silicon
238  return 173.0;
239  case 17: //Chlorine
240  return 174.0;
241  case 18: //Argon
242  return 188.0;
243  case 22: //Titanium
244  return 233.0;
245  case 26: //Iron
246  return 286.0;
247  case 27: //Cobalt
248  return 297.0;
249  case 29: //Copper
250  return 322.0;
251  case 30: //Zinc
252  return 330.0;
253  case 50: //Tin
254  return 488.0;
255  case 82: //Lead
256  return 823.0;
257  default: //If unrecognized, just assume FGD scintillator.
258  return 68.7;
259  }
260 }
261 
262 //Returns the ZoverA value for a given material.
263 //(Calculated from weights and content.)
264 Double_t GetZoverAMaterial(TGeoMixture* mat){
265 
266  Double_t ZoverA = 0;
267 
268  //Get the number of elements
269  Int_t NElements = mat->GetNelements();
270 
271  //Get the Z values for the material constituents.
272  Double_t* Zmixt = mat->GetZmixt();
273 
274  //Get the A values for the material constituents.
275  Double_t* Amixt = mat->GetAmixt();
276 
277  //Get the weight by mass of the elements.
278  Double_t* Wmixt = mat->GetWmixt();
279 
280  //Compute Z/A
281  for(Int_t i = 0; i < NElements; i++){
282 
283  ZoverA += Wmixt[i]*(Zmixt[i]/Amixt[i]);
284 
285  }
286  return ZoverA;
287 }
288 
289 
290 //Calculates the effective mean excitation energy for
291 //a mixture.
292 ///Equation taken from Leo p.29.
293 Double_t GetIMaterial(TGeoMixture* mat, Double_t ZoverA){
294 
295  Double_t lnI = 0;
296 
297  //Get the number of elements
298  Int_t NElements = mat->GetNelements();
299 
300  //Get the Z values for the material constituents.
301  Double_t* Zmixt = mat->GetZmixt();
302 
303  //Get the A values for the material constituents.
304  Double_t* Amixt = mat->GetAmixt();
305 
306  //Get the weight by mass of the elements.
307  Double_t* Wmixt = mat->GetWmixt();
308 
309  //lnIeff = sum(w_i*(Z_i/A_i)*lnI_i)/(Z/A)
310  for(Int_t i = 0; i < NElements; i++){
311 
312  lnI += (Wmixt[i]*(Zmixt[i]/Amixt[i])*log(GetIElement((Int_t)Zmixt[i])))/ZoverA;
313  }
314 
315  return exp(lnI);
316 }
317 
318 
319 //Takes in the initial momentum value and returns the corresponding
320 //kinetic energy of a pi+/-.
321 //pi+/- mass = 139.57 MeV (PDG)
322 Double_t computeEkinFromMom(Double_t mom){
323 
324  Double_t Ekin = sqrt(pow(mom,2) + pow(139.57,2)) - 139.57;
325  return Ekin;
326 }
327 
328 Double_t Interpolate(double xsec1, double xsec2, double mom1, double mom){
329  //We use 10MeV bins for the calculation
330  return (((mom/10.)-mom1)*(xsec2-xsec1) + xsec1);
331 }
332 
333 
334 //Only propagates pi+/- (i.e. assumes their mass, 139.57 MeV/c^2)
335 //Takes the pion, propagates it by the given step length. (The step length
336 //should be small.)
337 //Output is a pair <finalPosition,finalMomentum>
338 std::pair<TLorentzVector,TVector3> TakeSmallStep(Int_t charge,
339  TLorentzVector initPos,
340  TVector3 initMom,
341  Double_t stepLength, //in mm
342  TGeoMaterial* material,
343  std::string materialName,
344  TGeoMixture* mixture){
345 
346  //Find the initial kinetic energy.
347  Double_t initEkin = computeEkinFromMom(initMom.Mag());
348 
349  //Find the initial direction.
350  TVector3 initDir = initMom*(1/initMom.Mag());
351 
352 
353  //========Fill the information used for the energy loss calculation here.==========
354  //To start, the \delta(\beta\gamma)/2 (density) correction is only needed at high energies (Leo, 25),
355  //so we don't need to include that term. The shell correction exists at low energies, but the effect
356  //is typically small (Leo, 26) so we'll leave that out too.
357 
358  //Now, set up the values that we need for the formula.
359  Double_t K = 0.307075;
360  Double_t z2 = 1.0; //Incident particle is a pi+ or pi-, either way charge^2 = 1.
361  Double_t mec2 = 0.510998918;
362  Double_t m_pi = 139.57;
363 
364  //Compute the momentum of the particle from the kinetic energy.
365  Double_t p_pi = initMom.Mag();
366  Double_t betagamma = p_pi/m_pi;
367  Double_t beta = p_pi/(initEkin + m_pi);
368  Double_t gamma = betagamma/beta;
369  Double_t T_max = (2*mec2*pow(betagamma,2))/(1 + 2*gamma*(mec2/m_pi) + pow(mec2/m_pi,2));
370 
371  //==========================================
372  //The following parameters are for FGD scintillator. Change them later if not in FGD scintillator.
373  Double_t ZoverA = 0.53768; //From http://pdg.lbl.gov/2011/reviews/rpp2011-rev-atomic-nuclear-prop.pdf
374  Double_t I = 68.7E-6; //Mean Excitation energy, 68.7 eV from http://physics.nist.gov/cgi-bin/Star/compos.pl?refer=ap&matno=226
375  Double_t rho = 1.032;
376  //==========================================
377 
378  //If the material name does not contain "FGDScintillator", calculate different material based parameters.
379  if (materialName.find("FGDScintillator") == std::string::npos){
380 
381  ZoverA = GetZoverAMaterial(mixture);
382  I = GetIMaterial(mixture,ZoverA)*(1E-6); //Make sure to convert to MeV!
383 
384  //The conversion factor converts the density stored in the geometry to g/cm^3
385  rho = (1000.0/(6.2415e21))*(material->GetDensity());
386  }
387 
388  Double_t dEdx = K*z2*(ZoverA)*(1/pow(beta,2))*((1.0/2.0)*log(2*mec2*pow(betagamma,2)*T_max/pow(I,2)) - pow(beta,2));
389 
390  //Remember, it is dE/dx * length in material * density of material
391  //Used 1.032 g/cm^3, the density of the scintillator bars (from TN-91), as opposed
392  //to the full module density which took into account the G10, glue, and fiber.
393  //Factor of 0.1 to convert the mm tracklength to cm.
394  Double_t finalEkin = initEkin - dEdx*(0.1)*stepLength*rho;
395 
396  //Now, since we're taking small steps, we're assuming that the change in momentum is small, so we'll
397  //just use the initial momentum as the feed through into the helix code.
398  //The velocity of the pion in m/s)
399  //PDG speed of light value: 299 792 458 m/s
400  Double_t c = 299792458;
401  TVector3 initVelocity = beta*c*initDir;
402 
403  //The magnetic field is 0.2 T in the x direction.
404  TVector3 field(0.2,0.0,0.0);
405 
406  //dp/dt = q(v x B), where p = \beta\gamma*mc
407  //1 unit of charge is 1.602176e-19 Coulombs
408  TVector3 dpdt = charge*(1.602176e-19)*initVelocity.Cross(field);
409 
410  //So the change in momentum is therefore dpdt*dt, where dt = stepLength/initVelocity.Mag()
411  //0.001 converts stepLength from mm to m.
412  Double_t dt = ((0.001*stepLength)/initVelocity.Mag());
413  TVector3 dp = dpdt*dt;
414 
415  //So that we're working all in the same units, use gamma*m*initVelocity to get the initial momentum back
416  //(i.e. p = gamma*m*v)
417  //Convert m_pi from MeV/c^2 to kg with factor of 1.782662e-30
418  TVector3 pFinal = gamma*m_pi*(1.782662e-30)*initVelocity + dp;
419 
420  //Now we know the final momentum in kg*m/s. The Lorentz force only changes the direction and not the
421  //magnitude of the momentum. So, all we care about is the direction.
422  TVector3 finalDir = pFinal*(1/pFinal.Mag());
423 
424  //The final position of a step is going to be
425  //the result of going the step length in the direction of the initial momentum.
426  //The final momentum is going to be the final kinetic energy converted back to a momentum
427  //and in the direction of the final direction.
428  TLorentzVector positionChange(stepLength*initDir.X(),stepLength*initDir.Y(),stepLength*initDir.Z(),(1e9)*dt);
429  TLorentzVector finalPosition = initPos + positionChange;
430 
431  //Declare the vector the final momentum of the step will go into.
432  TVector3 finalMomVec;
433 
434  //If the final kinetic energy is <=0, set the finalMomVec to (0.0,0.0,0.0)
435  if(finalEkin <= 0 ){
436  TVector3 zeroVec(0.0,0.0,0.0);
437  finalMomVec = zeroVec;
438  }
439 
440  //Otherwise, use the actual computed Ekin to compute the momentum vector.
441  else{
442  Double_t finalMom = sqrt(pow(finalEkin + m_pi,2) - pow(m_pi,2));
443  finalMomVec = finalMom*finalDir;
444  }
445 
446  return std::make_pair(finalPosition,finalMomVec);
447 
448 }
449 
450 // Pion SI Manager business
451 
452 Bool_t PionSIManager::InVOI(SubDetId_h det, Float_t* pos) const{
453 
454 #if JMDEBUGVERSION == 0
455  if (det == SubDetId::kFGD1 && InVOI1(pos)) return true;
456 #elif JMDEBUGVERSION == 1
457  (void) det;
458  if (InVOI1(pos) || InVOI2(pos)) return true;
459 #elif JMDEBUGVERSION == 2
460  (void) det;
461  if (InVOIext(pos)) return true;
462 #elif JMDEBUGVERSION == 3
463  if (det == SubDetId::kFGD1 && InVOI1(pos)) return true;
464  else if (det == SubDetId::kFGD2 && InVOI2(pos)) return true;
465 #endif
466 
467 
468  return false;
469 }
470 
471 
472 Bool_t PionSIManager::InVOI1(Float_t* pos) const{
473 
474  //This is the edges of the FGD1 volume, plus all the way out to TPCGasMixture in downstream z.
475  //(Rounded to the next integer value that includes the value from the geometry in its range).
476 
477  Bool_t xOK = -1150.0 < pos[0] && pos[0] < 1150.0;
478  Bool_t yOK = -1170.0 < pos[1] && pos[1] < 1230.0;
479  Bool_t zOK = 98.0 < pos[2] && pos[2] < 576.0;
480 
481  return xOK && yOK && zOK;
482 
483 }
484 
485 Bool_t PionSIManager::InVOI2(Float_t* pos) const{
486 
487  //This is from the TPCGasMixture in upstream z through FGD2 all the way out to TPCGasMixture in downstream z.
488  //(Rounded to the next integer value that includes the value from the geometry in its range).
489  Bool_t xOK = -1150.0 < pos[0] && pos[0] < 1150.0;
490  Bool_t yOK = -1170.0 < pos[1] && pos[1] < 1230.0;
491  Bool_t zOK = 1347.0 < pos[2] && pos[2] < 1934.0;
492 
493  return xOK && yOK && zOK;
494 
495 }
496 
497 Bool_t PionSIManager::InVOIext(Float_t* pos) const{
498  //This is the edges of the FGD1 volume, plus all the way out to TPCGasMixture in TPC3 in downstream z.
499  //(Rounded to the next integer value that includes the value from the geometry in its range).
500  Bool_t xOK = -1150.0 < pos[0] && pos[0] < 1150.0;
501  Bool_t yOK = -1170.0 < pos[1] && pos[1] < 1230.0;
502  Bool_t zOK = 98.0 < pos[2] && pos[2] < 1934.0;
503 
504  return xOK && yOK && zOK;
505 }
506 
507 
508 
509 
510 //Given the info from two saved trajectory points, steps between them and saves step positions
511 //and momenta at appropriate points.
512 //The initial and final position and momentum are as come from the oaAnalysis info.
513 //Also need to return MC and Data sum of n*sigma*stepLength.
514 //Returns an object containing the information that we need for weighting, plus some
515 //information for testing/validation purposes.
516 SteppingResult PionSIManager::StepBetweenPoints(SubDetId_h det, Int_t charge,
517  TLorentzVector initPos,
518  TVector3 initMom,
519  TLorentzVector finalPos,
520  Double_t stepLength,
521  TGeoManager* geom) const{
522 
523  //Set up a variable to store the step result.
524  std::pair<TLorentzVector,TVector3> stepResult;
525 
526  //These are the variables to store the n*sigma*stepLength sums in for MC and Data.
527  Float_t MCSumNSigmaStepLength = 0;
528  Float_t DataSumNSigmaStepLength = 0;
529 
530 
531  //Loop over taking steps until the separation from start to end point
532  //is the is the same from oaAnalysis saved and from stepping.
533  Double_t initPointSep = (finalPos - initPos).Vect().Mag();
534  Double_t stepPointSep = 0.0;
535 
536  //Initialize the starting conditions of the step to those
537  //supplied to this function.
538  TLorentzVector stepStartPos = initPos;
539  TVector3 stepStartMom = initMom;
540 
541  //A variable to store the step length that is to be saved.
542  //(in mm, is the number of small steps in a saved step, multiplied by the step length.)
543  Double_t totalStepLength = 0;
544  std::vector<Float_t> totalStepLengths;
545 
546  //Also need to save the momentum of the particle at the last saved point.
547  TVector3 lastSavedMomentum = initMom;
548 
549  //The stepEnd information.
550  TLorentzVector stepEndPos;
551  TVector3 stepEndMom;
552 
553  while(stepPointSep < initPointSep){
554  //Grab the material information for this step.
555  //We use the material at the step start position for the step's material.
556  //(Steps are small enough that this should be pretty accurate.)
557  TGeoNode *node = geom->FindNode(stepStartPos.X(),stepStartPos.Y(),stepStartPos.Z());
558  TGeoVolume *volume = node->GetVolume();
559  TGeoMaterial *material = volume->GetMaterial();
560  std::string materialName = material->GetName();
561  TGeoMixture *mixture = (TGeoMixture*)material;
562 
563 
564  //Given the information supplied, take a small step.
565  stepResult = TakeSmallStep(charge,stepStartPos,stepStartMom,stepLength,
566  material,materialName,mixture);
567 
568  //Store the information at the end of the step for usage and later copying to
569  //the next stepStart.
570  stepEndPos = stepResult.first;
571  stepEndMom = stepResult.second;
572 
573 
574  //Also compute the separation between the step end point and the initial point.
575  stepPointSep = (stepEndPos - initPos).Vect().Mag();
576  //std::cout<<" step point sep "<<stepPointSep<<std::endl;
577  //Define the number density of scattering centres for scintillator here,
578  //as will use it both inside and outside the "If not scintillator" check.
579  Double_t NDScint = ((6.02214e23)/12.011)*0.89538563*1.03552; //nuclei/cm^3
580 
581  //=============================
582  //Define some variables for easy looping over the maps of XSecs.
583  //=============================
584  Int_t intTypes[3] = {0,1,4};
585 
586  //If it is a pi-, must add 100 to get the correct XSecs.
587  Int_t piT;
588  if (charge == 1){
589 
590  piT = 0;
591 
592  }
593 
594  else {
595 
596  piT = 100;
597 
598  }
599  //==================================
600 
601  //If we're not in FGD scintillator, scale the step length for different
602  //number density of scattering centres and interaction cross sections.
603  //If the material name does not contain "FGDScintillator", calculate different material based parameters.
604  if (materialName.find("FGDScintillator") == std::string::npos){
605 
606  Double_t scaledStepLength = stepLength;
607 
608  //Two things to take into account: density of scattering centres,
609  //and scaling of cross section with Z and A.
610 
611  //Density of scattering centres.
612  //i.e. the number of atoms per unit volume.
613  //Any ignored elements (H, Na, etc.) aren't considered.
614  //N = (N_A/M_r)*rho
615  //Where N is the number density (particles/cm^3), N_A is Avogadro's constant,
616  //M_r is the molar mass, and rho is the density.
617  //For a composite, material, if w_j is the fraction by weight,
618  //rho*wj gives the density of that element, sub that in for rho in
619  //the above equation, and that gives the number of that element
620  //per unit volume.
621  //These should really just be calculated separately and tabulated though.
622  //The FGD Scintillator one needs to be pre-calculated for the BANFF interface.
623  //NA = 6.02214e23;
624  //Mr = 12.011 (Carbon, weighted average of isotopes from periodic table)
625  //Fraction by weight of carbon: 0.89538563
626  //Density of scintillator (from geometry file): 1.03552 g/cm^3
627 
628  //The number density of scattering centres in the material,
629  //in number/cm^3
630  Double_t NDMat = DScattCentres(mixture);
631 
632  //Scale the step length by (NDMat/NDScint)
633  //(Going through a material with a denser number of scattering centres
634  //is equivalent to going through a longer distance of the scintillator.)
635  scaledStepLength *= (NDMat/NDScint);
636 
637 
638  //Now handle the difference in cross section between the non-scintillator
639  //material's constituents and Carbon.
640  //Need the sum of the cross sections of interest on Carbon at the step momentum,
641  //and the sum on whatever material this is.
642  //The material series is a multiple of 10 corresponding to where cross sections
643  //for the material are stored in a map.
644  Int_t materialSeries = GetMaterialSeries(materialName);
645 
646  //Now, get the sum of the XSecs for Carbon and for this material.
647  Double_t cXSecSum = 0;
648  Double_t matXSecSum = 0;
649  Double_t matMCXSecSum = 0;
650 
651  for(Int_t ti = 0; ti < 3; ti++){
652 
653  //.first is data, which is what we want.
654  int momBin = int(stepStartMom.Mag()/10);
655  if (momBin>800) momBin = 800;
656  cXSecSum += Interpolate(PiXSec::xsec_data[piT + intTypes[ti]][momBin], PiXSec::xsec_data[piT + intTypes[ti]][momBin+1],momBin,stepStartMom.Mag());
657  matXSecSum += Interpolate(PiXSec::xsec_data[materialSeries + piT + intTypes[ti]][momBin], PiXSec::xsec_data[materialSeries + piT + intTypes[ti]][momBin+1],momBin,stepStartMom.Mag());
658  matMCXSecSum += Interpolate(PiXSec::xsec_MC[materialSeries + piT + intTypes[ti]][momBin], PiXSec::xsec_MC[materialSeries + piT + intTypes[ti]][momBin+1],momBin,stepStartMom.Mag());
659 
660  }
661 
662  //With the carbon and actual material cross section determined, scale the step
663  //length.
664  if(cXSecSum != 0.0){
665  scaledStepLength *= (matXSecSum/cXSecSum);
666  }
667 
668  //The step length has now been scaled properly. Add it to the total step length.
669  totalStepLength += scaledStepLength;
670  //Add to the MC and Data N*sigma*stepLengths.
671  //Make sure to convert the stepLength to cm (from mm) and the cross section to cm^2
672  //(from mbarn)
673  //1 barn = 10^-28 m^2 => 1 mbarn = 10^-31 m^2 = 10^-27 cm^2
674  //Potential 2000 MeV/c cutoff: If wanted not to weight steps above 2000 MeV/c, would
675  //delete the next two commented lines:
676  //if (stepStartMom.Mag() < 2000.0){
677  MCSumNSigmaStepLength += NDMat*(1E-27)*matMCXSecSum*(stepLength/10.0);
678  DataSumNSigmaStepLength += NDMat*(1E-27)*matXSecSum*(stepLength/10.0);
679 
680  //}
681 
682  }
683 
684  //Otherwise, just use the actual step length, and use scintillator for cross section calculations.
685  else{
686  totalStepLength += stepLength;
687 
688  //Get the cross section information for weight calculation.
689  Double_t cXSecSum = 0;
690  Double_t cMCXSecSum = 0;
691  for(Int_t ti = 0; ti < 3; ti++){
692  int momBin = int(stepStartMom.Mag()/10);
693  if (momBin>800) momBin = 800;
694  cXSecSum += Interpolate(PiXSec::xsec_data[piT + intTypes[ti]][momBin], PiXSec::xsec_data[piT + intTypes[ti]][momBin+1],momBin,stepStartMom.Mag());
695  cMCXSecSum += Interpolate(PiXSec::xsec_MC[piT + intTypes[ti]][momBin], PiXSec::xsec_MC[piT + intTypes[ti]][momBin+1],momBin,stepStartMom.Mag());
696  }
697 
698  //Add to the sums now.
699  //Potential 2000 MeV/c cutoff: If wanted not to weight steps above 2000 MeV/c, would
700  //delete the next two commented lines:
701  //if (stepStartMom.Mag() < 2000.0){
702  MCSumNSigmaStepLength += NDScint*(1E-27)*cMCXSecSum*(stepLength/10.0);
703  DataSumNSigmaStepLength += NDScint*(1E-27)*cXSecSum*(stepLength/10.0);
704 
705  //}
706 
707  }
708 
709  //If the pion has stopped or left the volume of interest,
710  //save its information and exit this function by returning the result.
711 
712  Float_t stepEndPosArray[4];
713  anaUtils::VectorToArray(stepEndPos,stepEndPosArray);
714  if(stepEndMom.Mag() == 0.0 || !InVOI(det, stepEndPosArray)){
715  totalStepLengths.push_back(totalStepLength);
716 
717  //Prepare the results to return.
718  SteppingResult sr(MCSumNSigmaStepLength,
719  DataSumNSigmaStepLength,
720  totalStepLengths,
721  stepEndMom.Mag(),
722  stepEndPos);
723 
724  return sr;
725  }
726 
727  //Only save a point if the momentum has decreased by approximately 10 MeV.
728  //Also save a point if we're going to break out of the while loop.
729  else if (lastSavedMomentum.Mag() - stepEndMom.Mag() >= 10.0
730  || stepPointSep >= initPointSep){
731 
732  lastSavedMomentum = stepEndMom;
733  totalStepLengths.push_back(totalStepLength);
734 
735  //Reset the step length for the next set of small steps.
736  totalStepLength = 0;
737 
738  }
739 
740  //Copy the results of the step to the start position for the next run through.
741  stepStartPos = stepResult.first;
742  stepStartMom = stepResult.second;
743 
744 
745  }//End while loop.
746 
747  //The lastSavedMomentum is the momentum at the end of the last step
748  //(i.e. the "final momentum") as far as
749  //my code is concerned (for interaction momentum tagging purposes.)
750 
751  //Prepare the results to return.
752  SteppingResult sr(MCSumNSigmaStepLength,
753  DataSumNSigmaStepLength,
754  totalStepLengths,
755  lastSavedMomentum.Mag(),
756  stepEndPos);
757 
758  return sr;
759 
760 }
761 
762 
763 
764 //##########################################################
765 //The weight computing code.
766 //##########################################################
768 
769  // Get the geometry from the GeometryManager
770  TGeoManager* pionSIGeom = ND::hgman().GeoManager();
771 
772  //Only load in the geometry if it has not already been loaded by the InputConverter. Use in this case the default file
773  if (!pionSIGeom){
774  ND::hgman().LoadGeometry(); // Use default file
775  pionSIGeom = ND::hgman().GeoManager();
776  }
777 
778  AnaTrueParticleB* allTrajInTPCFGD[NMAXTRUEPARTICLES];
779  int nTraj = anaUtils::GetAllTrajInBunch(event, allTrajInTPCFGD);
780  if((UInt_t) nTraj>NMAXTRUEPARTICLES) nTraj = NMAXTRUEPARTICLES;
781 
782  //Declare the object the result will be written into.
783  //If the geometry has not already been loaded, this will load the geometry.
785  //Now, go through and select only those trajectories that start in the volume we're concerned with.
786  //FGD1FV plus dead material between that and TPC gas.
787  //It is a trajectory of interest if it starts in the volume of interest, as defined by InVOI, or its parent ends
788  //in the volume of interest.
789  std::vector<AnaTrueParticleB*> trajOfInterest;
790  for (Int_t it = 0; it < nTraj; it++){
791 
792  AnaTrueParticleB* track = allTrajInTPCFGD[it];
793 
794  //If the trajectory starts in the volume of interest, save it.
795  //One contiguous VOI, just use the one function.
796  if(InVOI(det, track->Position) ){
797  trajOfInterest.push_back(track);
798  }
799  else{
800  //Otherwise, find its parent, and if the parent ends in the volume of interest,
801  //save this trajectory.
802  for (Int_t jt = 0; jt < nTraj; jt++){
803  AnaTrueParticleB* track2 = allTrajInTPCFGD[jt];
804  if(track->ParentID == track2->ID){
805  if(InVOI(det, track2->PositionEnd) )
806  trajOfInterest.push_back(track);
807  break;
808  }
809  }
810  }
811  }
812 
813  //So at this point we have a vector of all true trajectories that start in the volume of interest and those
814  //whose parents end in the volume of interest. (This is to guard against unsaved trajectories resulting
815  //in an apparent child being created outside the volume of interest, but corresponding to the interaction
816  //that ended the trajectory in the volume of interest.)
817 
818  //We want to go through this list of trajectories, picking out pion trajectories and taking all trajectories with
819  //a pi+/- as a parent and assembling them into Interactions.
820  std::vector<AnaTrueParticleB*> pionTrajs;
821  std::vector<Interaction*> interactions;
822 
823  for(UInt_t oai = 0; oai < trajOfInterest.size(); oai++){
824  //If it's a pi+/- trajectory beginning in the volume of interest, save to pionTrajs.
825  if (trajOfInterest[oai]->PDG == 211 || trajOfInterest[oai]->PDG == -211){
826  if(InVOI(det, trajOfInterest[oai]->Position) )
827  pionTrajs.push_back(trajOfInterest[oai]);
828  }
829 
830  //If it lists a pion as a parent, assign it to an Interaction.
831  if(trajOfInterest[oai]->ParentPDG == 211 || trajOfInterest[oai]->ParentPDG == -211){
832 
833  AnaTrueParticleB* parent = GetParent(trajOfInterest[oai],allTrajInTPCFGD,nTraj);
834  Bool_t matchFound = false;
835  for (UInt_t jsi = 0; jsi < interactions.size(); jsi++){
836  if (interactions[jsi]->IncludesTrajectory(trajOfInterest[oai])){
837  interactions[jsi]->AddTrajectory(trajOfInterest[oai],parent);
838  matchFound = true;
839  break;
840  }
841  }
842 
843  //If an existing interaction does not match the trajectory, make a new interaction for
844  //it to reside in, and add that to the interactions vector.
845  if(!matchFound){
846  Interaction *newInteraction = new Interaction(trajOfInterest[oai], parent);
847  interactions.push_back(newInteraction);
848  }
849  }
850  }
851 
852 
853  //So at this point we have all pion trajectories identified, and all non-primary trajectories assembled into
854  //interactions.
855  //Now, loop through the pion trajectories and the interactions, and assign them to a specific parent pion.
856  //Then, use those trajectories to determine the secondary interaction type of the pion.
857  //Loop over the pions.
858  std::vector< std::pair<AnaTrueParticleB*,Int_t> > pionTrajAndInteraction;
859 
860  //Might as well count the interactions we're interested in now, so we can fill arrays later.
861  Int_t nInteractions = 0;
862  for (UInt_t p = 0; p < pionTrajs.size(); p++){
863 
864  AnaTrueParticleB* pionTraj = pionTrajs[p];
865  TLorentzVector pos(pionTraj->Position[0],pionTraj->Position[1],pionTraj->Position[2],pionTraj->Position[3]);
866  TLorentzVector posEnd(pionTraj->PositionEnd[0],pionTraj->PositionEnd[1],pionTraj->PositionEnd[2],pionTraj->PositionEnd[3]);
867  //Only look for the interaction type if the pion trajectory ends inside of the volume of interest.
868 #if (JMDEBUGVERSION == 0) || (JMDEBUGVERSION == 2) || (JMDEBUGVERSION == 3)
869  if(InVOI(sel.GetDetectorFV(branch), pionTraj->PositionEnd)){
870 
871  //If there are two separate VOIs, since tracking ends at the end of the VOI, we
872  //want to consider any pion trajectory that ends outside the VOI it started in
873  //as having "escaped" (what this if statement elses to.)
874 #elif JMDEBUGVERSION == 1
875  if( (InVOI1( pionTraj->Position ) && InVOI1( pionTraj->PositionEnd )) || (InVOI2( pionTraj->Position ) && InVOI2( pionTraj->PositionEnd ))){
876 #endif
877 
878  //Define a vector to store the (relevant) interactions belonging to this pion.
879  std::vector<Interaction*> thisPionInteractions;
880 
881  //Loop over the interactions vector and fill thisPionInteractions with the ones corresponding to
882  //this pion trajectory.
883  for (UInt_t i = 0; i < interactions.size(); i++){
884 
885  //If the interaction lists the pion as a parent, add it to the list.
886  //Also, we're only interested in interactions at or after the end of the pion trajectory.
887  if (interactions[i]->parentID == pionTraj->ID
888  && interactions[i]->position[3] >= pionTraj->PositionEnd[3]){
889  thisPionInteractions.push_back(interactions[i]);
890  }
891  }
892 
893  //So, at this point should have all the Interactions considered a result of this pion.
894  //Use this vector of interactions and the pion's position to determine its interaction type.
895  //Go through the interactions:
896  //A mu of correct charge originating from the trajectory end point => decay.
897  //A mu originating in a later interactions indicates decay of a pion that need to
898  //count as part of the original secondary interactions.
899  //If it's pi0 decay within 10^-4 ns of the end point, add a pi0.
900  //If it's outside of that time range, attribute it to a pion of the same type as the
901  //incoming pion undergoing a charge exchange (so add another pi+/-)
902  //Once have the full count of relevant particle types, use that to determine the
903  //secondary interaction type.
904  //Start by defining the counters.
905  Int_t NPiPlus = 0;
906  Int_t NPiZero = 0;
907  Int_t NPiMinus = 0;
908  Int_t NMuMinus = 0;
909  Int_t NMuPlus = 0;
910  Int_t NExotic = 0;
911 
912  for (UInt_t i = 0; i < thisPionInteractions.size(); i++){
913 
914  TLorentzVector thisPos(thisPionInteractions[i]->position[0],thisPionInteractions[i]->position[1],thisPionInteractions[i]->position[2],thisPionInteractions[i]->position[3]);
915  //First check the interaction that shares the position with the end of the pion trajectory.
916  //note that this condition only works if posEnd is a TLorentzVector!
917  if(posEnd == thisPos){
918 
919  NPiPlus += thisPionInteractions[i]->NumberOfParticleType(211);
920  NPiZero += thisPionInteractions[i]->NumberOfParticleType(111)
921  + thisPionInteractions[i]->NPiZeroFromDecayProducts();
922  NPiMinus += thisPionInteractions[i]->NumberOfParticleType(-211);
923  NMuPlus += thisPionInteractions[i]->NumberOfParticleType(-13);
924  NMuMinus += thisPionInteractions[i]->NumberOfParticleType(13);
925  NExotic += thisPionInteractions[i]->CountExoticParticles();
926  }
927 
928  //Otherwise it's time separated.
929  //In the below case, assume the particles considered below originate from
930  //something coming out of the original pion trajectory ending vertex (as opposed
931  //to some tertiary or beyond interaction of unsaved trajectories, which is unlikely.)
932  else{
933 
934  //A time separated mu+ implies an unsaved pi+ trajectory.
935  NPiPlus += thisPionInteractions[i]->NumberOfParticleType(-13);
936 
937  //A time separated mu- implies an unsaved pi- trajectory.
938  NPiMinus += thisPionInteractions[i]->NumberOfParticleType(13);
939 
940  //If a pi0 decay was within 10^-4 ns of the pion trajectory end,
941  //count it as being a product of the interaction the pion trajectory ended in.
942  //If there was a saved pi0 trajectory in this time region, assume
943  //that it originated from a time separated interaction.
944  Int_t TSPiZero = 0;
945  if(thisPionInteractions[i]->position[3] - pionTraj->PositionEnd[3] < 10E-4){
946 
947  //Consider the decay products as originating from a pi0 from the
948  //original pion's interaction.
949  NPiZero += thisPionInteractions[i]->NPiZeroFromDecayProducts();
950 
951  //Consider any saved pi0 as originating from a time separated
952  //interaction of an unsaved charged pion trajectory.
953  TSPiZero += thisPionInteractions[i]->NumberOfParticleType(111);
954 
955  }
956 
957  //Otherwise, count it or any saved pi0 as "Time Separated" pi0, which
958  //we later assume originated from a time separated interaction of an
959  //unsaved pi+/- trajectory.
960  else{
961  TSPiZero += thisPionInteractions[i]->NumberOfParticleType(111)
962  + thisPionInteractions[i]->NPiZeroFromDecayProducts();
963  }
964 
965  //Any time separated pions or exotics are likely collectively due
966  //to an unsaved pion trajectory of the same charge as the original pion
967  //trajectory. So count all pi+, time separated pi0, pi-, and exotics, and if the amount is
968  //greater than 0, add a pion of the same charge as the parent of the
969  //interaction.
970  if (thisPionInteractions[i]->NumberOfParticleType(211)
971  + TSPiZero
972  + thisPionInteractions[i]->NumberOfParticleType(-211)
973  + thisPionInteractions[i]->CountExoticParticles() > 0){
974 
975  if(pionTraj->PDG == 211){
976 
977  NPiPlus += 1;
978  }
979 
980  else{
981  NPiMinus += 1;
982  }
983 
984 
985  }
986 
987  }
988 
989  }
990 
991  //clean memory
992  std::vector<Interaction*> interactions;
993  for (std::vector<Interaction*>::iterator it = interactions.begin(); it != interactions.end(); it++){
994  delete (*it);
995 
996  }
997 
998  interactions.clear();
999 
1000 
1001 
1002  //At this point we have all of the relevant particles in the pion's interaction counted.
1003  //Use these counts to determine the interaction type.
1004  Int_t interactionType;
1005 
1006  //First take care of decays.
1007  if((pionTraj->PDG == 211 && NMuPlus == 1)
1008  || (pionTraj->PDG == -211 && NMuMinus == 1)){
1009 
1010  interactionType = 3;
1011 
1012  }
1013 
1014  //Now slot anything with exotic particles in it into Other.
1015  else if(NExotic > 0){
1016  interactionType = 7;
1017  }
1018 
1019  //Multi-pi.
1020  //If it has more than 1 pion total.
1021  else if (NPiPlus + NPiZero + NPiMinus > 1){
1022  interactionType = 5;
1023  }
1024 
1025  //CEX
1026  //Since we've excluded multi-pi events, only have to check the number
1027  //of the desired pion here.
1028  //This is CEX for both pi+ and pi-
1029  else if (NPiZero == 1){
1030  interactionType = 1;
1031  }
1032 
1033  //DCEX
1034  //Has a pi- if parent was pi+, or has a pi+ if parent was pi-
1035  else if ((pionTraj->PDG == 211 && NPiMinus == 1)
1036  || (pionTraj->PDG == -211 && NPiPlus == 1)){
1037  interactionType = 2;
1038  }
1039 
1040  //QE
1041  //If there is one pion of the same kind coming in going out.
1042  else if ((pionTraj->PDG == 211 && NPiPlus == 1)
1043  || (pionTraj->PDG == -211 && NPiMinus == 1)){
1044  interactionType = 4;
1045  }
1046 
1047  //ABS
1048  //If there's no pions or muons, it's absorption.
1049  else if (NPiPlus + NPiZero + NPiMinus
1050  + NMuMinus + NMuPlus == 0){
1051  interactionType = 0;
1052  }
1053 
1054  //As a catch all for weird stuff that shouldn't exist
1055  //(everything is expected to have been caught above.)
1056  else{
1057  interactionType = 7;
1058  }
1059 
1060 
1061  //With the interaction type now determined, write this pion trajectory and its
1062  //interaction type out to the vector that stores them.
1063  pionTrajAndInteraction.push_back(std::make_pair(pionTraj,interactionType));
1064  }
1065 
1066  //If it's not in the volume of interest, assign it the "Escaped" interaction type (8).
1067  else{
1068  pionTrajAndInteraction.push_back(std::make_pair(pionTraj,8));
1069 
1070  }
1071 
1072  //Now, check the recently just added pair to see whether it is one of the interaction
1073  //types we're interested in. If it is, count as one of the nInteractions.
1074  Int_t thisIntType = pionTrajAndInteraction.back().second;
1075 
1076  //If it's one of the interactions we're interested in, count it and
1077  //store its information for later processing.
1078  if(thisIntType == 0 || thisIntType == 1 || thisIntType == 4){
1079 
1080  nInteractions++;
1081  }
1082 
1083 
1084  } //Close loop over pion trajectories.
1085 
1086  //So, at this point we now have a vector of pion trajectories paired with the interaction that ends them
1087  //(or if this interaction occured outside the volume of interest, indication that they escaped.)
1088  //Now we need to step these pions through the detector.
1089  //Propagate from beginning to the end of the trajectory. Elastic interactions aren't accounted for,
1090  //but the error due to that should be small. Propagates out to length between start and end point,
1091  //either stopping when it hits that length or when it goes outside of the volume of interest.
1092 
1093  std::vector<Float_t> allPionSteps;
1094 
1095  Float_t AllPionsMCSumNSigmaStepLength = 0.0;
1096  Float_t AllPionsDataSumNSigmaStepLength = 0.0;
1097 
1098  //Set up as many variables as can.
1099  Int_t nPions = (Int_t)pionTrajAndInteraction.size();
1100  Bool_t* pionType = new Bool_t[(UInt_t)nPions];
1101  Int_t* nSteps = new Int_t[(UInt_t)nPions];
1102  Float_t* initMom = new Float_t[(UInt_t)nPions];
1103  Float_t* pInteraction = new Float_t[(UInt_t)nInteractions];
1104  Int_t* typeInteraction = new Int_t[(UInt_t)nInteractions];
1105  Int_t interactionsSoFar = 0; // Since not every pion has an interaction to count.
1106 
1107  //Variables for validation purposes.
1108  std::vector<Float_t> testFinalMom;
1109  std::vector<TLorentzVector> testFinalPos;
1110  std::vector<Int_t> testInteractionType;
1111  Int_t* pionID = new Int_t[nPions];
1112  AnaTrueParticleB** TrueParticles = new AnaTrueParticleB*[nPions];
1113  AnaTrueParticleB** InteractionTrueParticles = new AnaTrueParticleB*[nInteractions];
1114 
1115  for(UInt_t ip = 0; ip < pionTrajAndInteraction.size(); ip++){
1116 
1117  AnaTrueParticleB* pionTraj = pionTrajAndInteraction[ip].first;
1118  Int_t intCode = pionTrajAndInteraction[ip].second;
1119 
1120  //Set whether it is a pi+ or a pi-.
1121  if(pionTraj->PDG == 211){
1122 
1123  pionType[ip] = true;
1124 
1125  }
1126  else{
1127 
1128  pionType[ip] = false;
1129 
1130  }
1131 
1132  //Store the initial momentum.
1133  //Remember: In highland the magnitude of the momentum
1134  //is stored as Momentum, and the direction elsewhere.
1135  initMom[ip] = pionTraj->Momentum;
1136 
1137  //Store the pion trajectory ID, for validation purposes.
1138  pionID[ip] = pionTraj->ID;
1139 
1140  TrueParticles[ip] = pionTraj;
1141 
1142  TVector3 dir(pionTraj->Direction[0], pionTraj->Direction[1], pionTraj->Direction[2]);
1143  TLorentzVector pos(pionTraj->Position[0],pionTraj->Position[1],pionTraj->Position[2],pionTraj->Position[3]);
1144  TLorentzVector posEnd(pionTraj->PositionEnd[0],pionTraj->PositionEnd[1],pionTraj->PositionEnd[2],pionTraj->PositionEnd[3]);
1145 
1146  SteppingResult sr = StepBetweenPoints(det, (pionTraj->PDG)/211, //Charge
1147  pos,
1148  (pionTraj->Momentum)*dir,
1149  posEnd,
1150  0.1, //Step length, 0.1 mm
1151  pionSIGeom); //The geometry.
1152 
1153  //Store the number of steps for this pion.
1154  nSteps[ip] = sr.stepLengths.size();
1155  //Fill the test variables.
1156  testFinalMom.push_back(sr.finalMom);
1157 
1158  testFinalPos.push_back(sr.finalPos);
1159 
1160  testInteractionType.push_back(intCode);
1161 
1162  //If it's one of the interactions we're interested in, store the information
1163  //we need to store to generate weights.
1164  if(intCode == 0 || intCode == 1 || intCode == 4){
1165 
1166  pInteraction[interactionsSoFar] = sr.finalMom;
1167 
1168  //Get the material this interaction occurred in.
1169  //(Use the true MC end as opposed to the propagated one, which is not exact.
1170  //The interaction necessarily occurred at the end of the trajectory
1171  TGeoNode *node = pionSIGeom->FindNode(pionTraj->PositionEnd[0],
1172  pionTraj->PositionEnd[1],
1173  pionTraj->PositionEnd[2]);
1174 
1175  TGeoVolume *volume = node->GetVolume();
1176  TGeoMaterial *material = volume->GetMaterial();
1177  std::string materialName = material->GetName();
1178 
1179  Int_t materialSeries = GetMaterialSeries(materialName);
1180 
1181 
1182  //Get the pionType Series to add to the interaction type.
1183  //0 for pi+, 100 for pi-
1184  //Int_t pionTypeSeries = (100)*(1-pionType[ip]);
1185  //pionType == true for pi+, false for pi-
1186  Int_t pionTypeSeries = 0;
1187  if(!pionType[ip]){
1188  pionTypeSeries = 100;
1189  }
1190 
1191 
1192  typeInteraction[interactionsSoFar] = intCode + materialSeries + pionTypeSeries;
1193 
1194  InteractionTrueParticles[interactionsSoFar] = pionTraj;
1195 
1196  //Increase the interaction counter to move on to
1197  //the next element.
1198  interactionsSoFar++;
1199  }
1200 
1201 
1202 
1203  //Loop over all the steps for this pion, and add them to allPionSteps
1204  for(UInt_t sIdx = 0; sIdx < sr.stepLengths.size() ; sIdx++){
1205 
1206  allPionSteps.push_back(sr.stepLengths[sIdx]);
1207 
1208  }
1209 
1210  //Add this pion's MC and Data sum N*sigma*StepLength to the total for
1211  //all pions in the event.
1212  AllPionsMCSumNSigmaStepLength += sr.MCSumNSigmaStepLength;
1213  AllPionsDataSumNSigmaStepLength += sr.DataSumNSigmaStepLength;
1214 
1215 
1216  }
1217 
1218 
1219  //Can't fill some output variables until know everything there is to know about the event. Do that here.
1220  Int_t totalSteps = (Int_t)allPionSteps.size();
1221 
1222  //Can now create and fill the stepLengths array.
1223  Float_t* stepLengths = new Float_t[totalSteps];
1224 
1225  for(UInt_t i = 0; i < allPionSteps.size(); i++){
1226 
1227  stepLengths[i] = allPionSteps[i];
1228  }
1229 
1230 
1231  //Use the Step sums and the interactions arrays to compute the MC to data weights.
1232  //Start with the weight portion from the stepping.
1233  Float_t weightMCToData = TMath::Exp(-(AllPionsDataSumNSigmaStepLength - AllPionsMCSumNSigmaStepLength));
1234 
1235  //Now, go through the interactions and multiply the exponential by their contributions.
1236  for(Int_t ni = 0; ni < nInteractions; ni++){
1237 
1238  Int_t siType = typeInteraction[ni];
1239  Float_t siMom = pInteraction[ni];
1240 
1241  int momBin = int(siMom/10);
1242  if (momBin>800) momBin = 800;
1243 
1244  Double_t dataXSec = Interpolate(PiXSec::xsec_data[siType][momBin], PiXSec::xsec_data[siType][momBin+1],momBin,siMom);
1245  Double_t mcXSec = Interpolate(PiXSec::xsec_MC[siType][momBin], PiXSec::xsec_MC[siType][momBin+1],momBin,siMom);
1246 
1247  //Potential 2000 MeV/c cutoff: If want not to weight pions above 2000 MeV/c,
1248  //uncomment the next two commented lines.
1249  //if(pInteraction[ni] < 2000.0){
1250  if(mcXSec != 0.0){
1251  weightMCToData *= dataXSec/mcXSec;
1252  }
1253 
1254  //}
1255  }
1256 
1257  //Now all the variables that are needed have been filled. They need to be written out to the microtree.
1258  //Pass them to our ad-hoc object. May have a better solution later.
1259  //PionInteractionSystematic result;
1260  //This is declared at the beginning of this function now, so that the
1261  //geometry initialization code is called before try to use the geometry.
1262  result->nPions = nPions;
1263  result->pionType = pionType;
1264  result->totalSteps = totalSteps;
1265  result->nSteps = nSteps;
1266  result->initMom = initMom;
1267  result->stepLengths = stepLengths;
1268  result->nInteractions = nInteractions;
1269  result->pInteraction = pInteraction;
1270  result->typeInteraction = typeInteraction;
1271  result->testFinalMom = testFinalMom;
1272  result->testFinalPos = testFinalPos;
1273  result->testInteractionType = testInteractionType;
1274  result->weightMCToData = weightMCToData;
1275  result->MCSumNSigmaStepLength = AllPionsMCSumNSigmaStepLength;
1276  result->DataSumNSigmaStepLength = AllPionsDataSumNSigmaStepLength;
1277  result->MCProbNoInt = TMath::Exp(-AllPionsMCSumNSigmaStepLength);
1278  result->DataProbNoInt = TMath::Exp(-AllPionsDataSumNSigmaStepLength);
1279  result->pionID = pionID;
1280  result->TrueParticles = TrueParticles;
1281  result->InteractionTrueParticles = InteractionTrueParticles;
1282 
1283  return result;
1284 
1285 }
1286 
1287 //*******************************************************************************
1288 AnaTrueParticleB* GetParent(AnaTrueParticleB* track, AnaTrueParticleB* allTrajInTPCFGD[], Int_t nTraj){
1289 //*******************************************************************************
1290 
1291  for (Int_t it = 0; it < nTraj; it++){
1292  AnaTrueParticleB* track2 = allTrajInTPCFGD[it];
1293 
1294  if (track->ParentID == track2->ID) return track2;
1295  }
1296 
1297  return NULL;
1298 }
int GetAllTrajInBunch(const AnaEventB &event, AnaTrueParticleB *traj[])
Definition: SubDetUtils.cxx:12
Float_t Momentum
The initial momentum of the true particle.
Int_t ID
The ID of the trueObj, which corresponds to the ID of the TTruthParticle that created it...
Representation of a true Monte Carlo trajectory/particle.
const TVector3 field
Constants.
Int_t PDG
The PDG code of this particle.
const Double_t K
Bethe-Bloch constants.
PionInteractionSystematic * ComputePionWeightInfo(const AnaEventB &event, SubDetId_h det) const
Int_t ParentID
The ID of this particle&#39;s immediate parent, or 0 if there is no parent.
Float_t PositionEnd[4]
The end position of the true particle.
Float_t Position[4]
The initial position of the true particle.
Float_t Direction[3]
The initial direction of the true particle.
bool LoadGeometry(const std::string &file="", Int_t geomID=-1, const std::string &geomDir="")
Load the TGeoManager from the input root file. Returns true when the new geometry was loaded...