ATTPCROOT  0.3.0-alpha
A ROOT-based framework for analyzing data from active target detectors
AtELossManager.cxx
Go to the documentation of this file.
1 #include "AtELossManager.h"
2 
3 #include <Rtypes.h>
4 #include <TGraph.h>
5 
6 #include <algorithm>
7 #include <cmath>
8 #include <fstream> // IWYU pragma: keep
9 #include <iostream>
10 
12 
14 {
15  EvD = std::make_shared<TGraph>();
16 }
17 
18 AtTools::AtELossManager::AtELossManager(std::string Eloss_file, Double_t Mass)
19 {
20  Double_t _IonEnergy = 0;
21  Double_t _dEdx_e = 0, _dEdx_n = 0;
22  Double_t _Range = 0;
23  Double_t _Stragg_lon = 0, _Stragg_lat = 0;
24  std::string aux;
25 
26  std::ifstream Read(Eloss_file.c_str());
27 
28  // cout << " Opening " << Eloss_file <<endl;
29  if (!Read.is_open()) {
30  std::cout << "*** EnergyLoss Error: File " << Eloss_file << " was not found."
31  << "\n";
32  GoodELossFile = false;
33  } else {
34  GoodELossFile = true;
35  Read >> aux >> aux >> aux >> aux >> aux >> aux; // The first line has 6 strings (columns' description).
36  points = 0;
37 
38  do {
39  Read >> _IonEnergy >> _dEdx_e >> _dEdx_n >> _Range >> _Stragg_lon >> _Stragg_lat;
40  points++;
41 
42  } while (!Read.eof());
43 
44  Read.close();
45 
46  // Go to the begining of the file and read it again to now save the info in the newly created arrays.
47  Read.open(Eloss_file.c_str());
48  Read >> aux >> aux >> aux >> aux;
49 
50  for (int p = 0; p < points; p++) {
51  Read >> _IonEnergy >> _dEdx_e >> _dEdx_n >> _Range;
52 
53  IonEnergy.push_back(_IonEnergy);
54  dEdx_e.push_back(_dEdx_e);
55  dEdx_n.push_back(_dEdx_n);
56  Range.push_back(_Range);
57  }
58 
59  Energy_in_range = true;
60  IonMass = Mass; // In MeV/c^2
61  c = 29.9792458; // Speed of light in cm/ns.
62  EvD = std::make_shared<TGraph>();
63  }
64 }
65 
67 
68 Double_t AtTools::AtELossManager::GetEnergyLossLinear(Double_t energy, Double_t distance)
69 {
70 
71  int i = -1;
72  if (energy >= 0.01) {
73  // Look for two points for which the initial energy lays in between. This for-loop should find the points
74  // unless there was a big jump from the energy used in the last point and the energy used now.
75 
76  for (int p = 0; p < points - 1; p++) {
77 
78  if (energy >= IonEnergy[p] && energy < IonEnergy[p + 1]) {
79 
80  i = p + 1;
81  last_point = p;
82 
83  break;
84  }
85  }
86 
87  // If after this two loop i is still -1 it means the energy was out of range.
88  if (i == -1) {
89  // cout << "*** EnergyLoss Error: energy not within range: " << energy << endl;
90 
91  Energy_in_range = false;
92  return 0;
93  }
94 
95  // If the initial energy is within the range of the function,
96  // get the stopping power for the initial energy.
97 
98  Double_t E1 = IonEnergy[i - 1];
99  Double_t E2 = IonEnergy[i];
100 
101  Double_t dEdx_e1 = dEdx_e[i - 1];
102  Double_t dEdx_e2 = dEdx_e[i];
103 
104  Double_t dEdx_n1 = dEdx_n[i - 1];
105  Double_t dEdx_n2 = dEdx_n[i];
106 
107  // Interpolating the electric stopping power (from point 1 to 'e').
108  Double_t dEdx_e1e = dEdx_e1 + (energy - E1) * (dEdx_e2 - dEdx_e1) / (E2 - E1);
109 
110  // Interpolating the nuclear stopping power (usually negligable).
111  Double_t dEdx_n1e = dEdx_n1 + (energy - E1) * (dEdx_n2 - dEdx_n1) / (E2 - E1);
112 
113  // The stopping power units are in MeV/mm so we multiply by 10 to convert to MeV/cm.
114  return ((dEdx_e1e + dEdx_n1e) * 10 * distance);
115  } // end of if(energy > 0.1){
116  else {
117  return 0;
118  }
119 }
120 
122 double AtTools::AtELossManager::GetEnergyLoss(double energy /*MeV*/, double distance /*cm*/)
123 {
124  Float_t a11 = 0.0, a12 = 0.0, a21 = 0.0, a22 = 0.0, a23 = 0.0, a32 = 0.0, a33 = 0.0;
125  Float_t b11 = 0.0, b22 = 0.0, b33 = 0.0;
126  Float_t a1 = 0.0, a2 = 0.0, b1 = 0.0, b2 = 0.0;
127  Float_t K0 = 0.0, K1 = 0.0, K2 = 0.0;
128  Float_t N1 = 0.0, N2 = 0.0, N3 = 0.0;
129  Float_t T1 = 0.0, T2 = 0.0, q1 = 0.0, q2 = 0.0;
130 
131  int i = -1;
132  if (energy < 0.01)
133  return (0);
134 
135  // if(energy < 0.01){
136  // break;
137  // }
138 
139  // Look for two points for which the initial energy lies in between.
140  // This for-loop should find the points
141  // unless there was a big jump from the energy used in the
142  // last point and the energy used now.
143 
144  for (int p = 0; p < points - 1; p++) {
145 
146  if (energy >= IonEnergy[p] && energy < IonEnergy[p + 1]) {
147 
148  i = p + 1;
149  last_point = p;
150 
151  break;
152  }
153  }
154  // If after this two loop i is still -1 it means the energy was out of range.
155 
156  if (i == -1) {
157 
158  std::cout << "*** EnergyLoss Error: energy not within range: " << energy << "\n";
159 
160  Energy_in_range = false;
161  return 0;
162  }
163 
164  // Ion Energy
165  Float_t x0 = IonEnergy[i - 1];
166  Float_t x1 = IonEnergy[i];
167  Float_t x2 = IonEnergy[i + 1];
168 
169  // Total Energy Loss (electric + nuclear) for one step
170  Float_t y0 = dEdx_e[i - 1] + dEdx_n[i - 1];
171  Float_t y1 = dEdx_e[i] + dEdx_n[i];
172  Float_t y2 = dEdx_e[i + 1] + dEdx_n[i + 1];
173 
174  a11 = 2 / (x1 - x0);
175  a12 = 1 / (x1 - x0);
176  a21 = 1 / (x1 - x0);
177  a22 = 2 * ((1 / (x1 - x0)) + (1 / (x2 - x1)));
178  a23 = 1 / (x2 - x1);
179  a32 = 1 / (x2 - x1);
180  a33 = 2 / (x2 - x1);
181 
182  b11 = 3 * ((y1 - y0) / ((x1 - x0) * (x1 - x0)));
183  b22 = 3 * (((y1 - y0) / ((x1 - x0) * (x1 - x0))) + ((y2 - y1) / ((x2 - x1) * (x2 - x1))));
184  b33 = 3 * ((y2 - y1) / ((x2 - x1) * (x2 - x1)));
185 
186  // mathematical terms to calculate curvatures.
187  N1 = (a21 * a33 * a12 - a11 * (a22 * a33 - a23 * a32)) / (a33 * a12);
188  N2 = (b22 * a33 - a23 * b33) / a33;
189  N3 = b11 * (a22 * a33 - a23 * a32) / (a33 * a12);
190  // cout<<"N1="<<N1<<" N2="<<N2<<" N3="<<N3<<endl;
191 
192  // curvatures
193  K0 = (N2 - N3) / N1;
194  K1 = (b11 - a11 * K0) / a12;
195  // K2 = (b33 - a32 * K1) / a33;
196  // cout<<"K0="<<K0<<" K1="<<K1<<" K2="<<K2<<endl;
197 
198  a1 = K0 * (x1 - x0) - (y1 - y0);
199  b1 = -K1 * (x1 - x0) + (y1 - y0);
200  // a2 = K1 * (x2 - x1) - (y2 - y1);
201  // b2 = -K2 * (x2 - x1) + (y2 - y1);
202  // cout<<"a1="<<a1<<" b1="<<b1<<" a2="<<a2<<" b2="<<b2<<endl;
203 
204  T1 = (energy - x0) / (x1 - x0);
205  // T2 = (energy - x1) / (x2 - x1);
206 
207  // polynomials //which gives the value of energy loss for given energy.
208  q1 = (1 - T1) * y0 + T1 * y1 + T1 * (1 - T1) * (a1 * (1 - T1) + b1 * T1);
209  // q2 = (1 - T2) * y1 + T2 * y2 + T2 * (1 - T2) * (a2 * (1 - T2) + b2 * T2);
210 
211  // cout<<"q1="<<q1<<" q2="<<q2<<endl;
212 
213  return (q1 * 10 * distance);
214 }
215 
217 Double_t AtTools::AtELossManager::GetInitialEnergy(Double_t FinalEnergy /*MeV*/, Double_t PathLength /*cm*/ /*dist*/,
218  Double_t StepSize /*cm*/)
219 {
220  Double_t Energy = FinalEnergy;
221  int Steps = (int)floor(PathLength / StepSize);
222  last_point = 0;
223 
224  // The function starts by assuming FinalEnergy is within the energy range,
225  // but this could be changed in the GetEnergyLoss() function.
226 
227  Energy_in_range = true;
228 
229  for (int s = 0; s < Steps; s++) {
230 
231  Energy = Energy + GetEnergyLoss(Energy, PathLength / Steps);
232 
233  if (!Energy_in_range) {
234  break;
235  }
236  }
237  Energy = Energy + GetEnergyLoss(Energy, PathLength - Steps * StepSize);
238 
239  if (!Energy_in_range)
240  Energy = -1000; // Return an unrealistic value.
241 
242  return Energy;
243 }
244 
246 Double_t AtTools::AtELossManager::GetFinalEnergy(Double_t InitialEnergy /*MeV*/, Double_t PathLength /*cm*/,
247  Double_t StepSize /*cm*/)
248 {
249 
250  Double_t Energy = InitialEnergy;
251  int Steps = (int)floor(PathLength / StepSize);
252 
253  // The function starts by assuming InitialEnergy is within the energy range, but
254  // this could be changes in the GetEnergyLoss() function.
255 
256  Energy_in_range = true;
257 
258  for (int s = 0; s < Steps; s++) {
259 
260  Energy = Energy - GetEnergyLoss(Energy, PathLength / Steps);
261 
262  if (!Energy_in_range) {
263  break;
264  }
265  // cout<<"1: ="<<Energy<< " "<<s*StepSize<<endl;
266  }
267 
268  Energy = Energy - GetEnergyLoss(Energy, PathLength - Steps * StepSize);
269 
270  if (!Energy_in_range) {
271  Energy = -1000;
272  }
273 
274  // if (PathLength == 6.0){
275  // cout << " Get Final Energy :"<< InitialEnergy << " " << PathLength << " " << Energy << endl;
276  //}
277  return Energy;
278 }
279 
280 Double_t AtTools::AtELossManager::GetDistance(Double_t InitialE, Double_t FinalE, Double_t StepSize)
281 {
282 
283  Double_t dist = 0;
284  Double_t E = 0, Elast = 0;
285  // Double_t Tolerance = 0.01;
286 
287  E = InitialE;
288 
289  while (E > FinalE) {
290  dist += StepSize;
291  Elast = E;
292  E = E - GetEnergyLoss(E, StepSize);
293  }
294 
295  return ((dist - StepSize) - (StepSize * (Elast - FinalE) / (E - Elast)));
296 }
297 
299 // Calulates the ion's path length in cm.
301 Double_t AtTools::AtELossManager::GetPathLength(Float_t InitialEnergy /*MeV*/, Float_t FinalEnergy /*MeV*/,
302  Float_t DeltaT /*ns*/)
303 {
304  Double_t L = 0, DeltaX = 0;
305  Double_t Kn = InitialEnergy;
306  Double_t Kn1 = InitialEnergy;
307  Int_t n = 0;
308 
309  if (IonMass == 0)
310  std::cout << "*** EnergyLoss Error: Path length cannot be calculated for IonMass = 0."
311  << "\n";
312  else {
313 
314  // The path length (L) is proportional to sqrt(Kn).
315  // After the sum, L will be multiplied by the proportionality factor.
316 
317  while (Kn > FinalEnergy && Kn1 > FinalEnergy && n < (int)pow(10.0, 6)) {
318 
319  // L += sqrt(Kn); // 2016-06-15 changed
320  L += sqrt((Kn + Kn1) / 2) * sqrt(2 / IonMass) * DeltaT * c; // DeltaL going from point n to n+1.
321  // cout<<"1 = "<<Kn<<" "<<Kn1<<endl;
322 
324  DeltaX = sqrt((Kn + Kn1) / IonMass) * DeltaT * c;
325 
326  Kn1 = Kn;
327  // Kn -= GetEnergyLoss(Kn,DeltaX); // 2016-06-15 changed
328  Kn -= GetEnergyLoss((Kn + Kn1) / 2, DeltaX); // After L is incremented the kinetic energy at n+1 is calculated.
329  // cout<<"2 = "<<Kn<<" "<<Kn1<<endl;
330  // outfile4 << Kn << "\t" << L << endl;
331  n++;
332  }
333  if (n >= (int)pow(10.0, 6)) {
334  std::cout << "*** EnergyLoss Warning: Full path length wasn't reached after 10^6 iterations."
335  << "\n";
336  L = 0;
337  } else
338  // L *= sqrt(2/IonMass)*DeltaT*c;
339  L *= 1.0;
340  }
341  return L;
342 }
343 
345 Double_t AtTools::AtELossManager::LoadRange(Float_t energy1)
346 {
347  Int_t i = -1;
348  Double_t Range1 = 0;
349 
350  if (energy1 >= 0.01) { // greater than= 10 keV
351 
352  for (Int_t p = last_point1 - 1; p < points1 - 1; p++) {
353  if (last_point1 >= 0)
354  if (energy1 >= IonEnergy[p] && energy1 < IonEnergy[p + 1]) {
355  i = p + 1;
356  last_point1 = p;
357  break;
358  }
359  }
360 
361  if (i == -1) {
362  for (Int_t p = 0; p < last_point1 - 1; p++) {
363  if (energy1 >= IonEnergy[p] && energy1 < IonEnergy[p + 1]) {
364  i = p + 1;
365  last_point1 = p;
366  break;
367  }
368  }
369  }
370 
371  if (i == -1) {
372  std::cout << "*** EnergyLoss Error: energy not within range: " << energy1 << "\n";
373  Energy_in_range = false;
374  return 0;
375  }
376  Range1 = Range[i];
377  return Range1;
378  }
379  return (0);
380 }
381 
383 // Calulates the ion's time of flight in ns.
385 
386 Double_t AtTools::AtELossManager::GetTimeOfFlight(Double_t InitialEnergy, Double_t PathLength, Double_t StepSize)
387 {
388  Double_t TOF = 0;
389  Double_t Kn = InitialEnergy;
390  int Steps = (int)(PathLength / StepSize);
391 
392  if (IonMass == 0) {
393  std::cout << "Error: Time of flight cannot be calculated because mass is zero."
394  << "\n";
395  }
396 
397  else {
398 
399  for (int n = 0; n < Steps; n++) {
400 
401  TOF += sqrt(IonMass / (2 * Kn)) * StepSize / c; // DeltaT going from point n to n+1.
402  Kn -= GetEnergyLoss(Kn, StepSize); // After the TOF is added the K.E. at point n+1 is calc.}
403  }
404  return TOF;
405  }
406  return (0);
407 }
408 
411 {
412  IonMass = Mass;
413 }
415 // Lookup Table Extension
416 void AtTools::AtELossManager::InitializeLookupTables(Double_t MaximumEnergy, Double_t MaximumDistance, Double_t DeltaE,
417  Double_t DeltaD)
418 {
419 
420  int noE = (int)ceil(MaximumEnergy / DeltaE);
421  int noD = (int)ceil(MaximumDistance / DeltaD);
422 
423  fMaximumEnergy = MaximumEnergy;
424  fMaximumDistance = MaximumDistance;
425  fDeltaD = DeltaD;
426  fDeltaE = DeltaE;
427 
428  EtoDtab.resize(noE);
429  DtoEtab.resize(noD);
430 
431  // Double_t D;
432  int i = 0;
433  //-----------------------------------------------------------
434  DtoEtab[0] = MaximumEnergy;
435  std::cout << " Number of distance entries " << noD << "\n";
436 
437  for (i = 1; i < noD; i++) {
438  // DtoEtab[i] = GetFinalEnergy(InitialEnergy,D,50000);
439 
440  // DtoEtab[i] = GetFinalEnergy(DtoEtab[i-1],DeltaD,0.05*DeltaE);
441  DtoEtab[i] = GetFinalEnergy(DtoEtab[i - 1], DeltaD, 0.05 * DeltaD);
442 
443  // cout<<"2: "<<DtoEtab[i]<< " D="<<D<<endl;
444  if (i % 1000 == 0) {
445  // cout << " Passed " << i << endl;
446  }
447  }
448 
449  // Double_t E;
450  int j = 0;
451 
452  std::cout << " Number of Energy entries " << noE << "\n";
453 
454  EtoDtab[0] = 0.;
455  for (j = 1; j < noE; j++) {
456  // EtoDtab[j] = GetDistance(MaximumEnergy,E,50000);
457  // EtoDtab[j] = GetDistance(MaximumEnergy,MaximumEnergy-j*DeltaE,0.1,5500);
458  EtoDtab[j] = EtoDtab[j - 1] +
459  GetDistance((MaximumEnergy - (j - 1) * DeltaE), (MaximumEnergy - (j)*DeltaE), (0.05 * DeltaD));
460  if (j % 1000 == 0) {
461  // cout << " Passed " << j << endl;
462  }
463  }
464  // cout << " Passed " << j << endl;
465  //-----------------------------------------------------------
466 
467  /*
468  for (i=0; i<noD; i++){
469  //DtoEtab[i] = GetFinalEnergy(InitialEnergy,D,50000);
470  DtoEtab[i] = GetFinalEnergy(MaximumEnergy,DeltaD*i,0.01);
471  //cout<<"2: "<<DtoEtab[i]<< " D="<<D<<endl;
472  }
473 
474  //Double_t E;
475  int j;
476 
477  for (j=0;j<noE;j++){
478  //EtoDtab[j] = GetDistance(MaximumEnergy,E,50000);
479  //EtoDtab[j] = GetDistance(MaximumEnergy,MaximumEnergy-j*DeltaE,0.1,5500);
480  EtoDtab[j] = GetDistance(MaximumEnergy,MaximumEnergy-j*DeltaE,0.1);
481  }
482  */
483 }
484 //=================================================
486 {
487 
488  int noE = (int)ceil(fMaximumEnergy / fDeltaE);
489  int noD = (int)ceil(fMaximumDistance / fDeltaD);
490  int i = 0;
491  std::cout << "Maximum Energy = " << fMaximumEnergy << " " << fDeltaE << noE << "\n";
492  for (i = 0; i < noE; i++) {
493  std::cout << "E,D= " << fMaximumEnergy - fDeltaE * i << "," << EtoDtab[i] << "\n";
494  }
495  std::cout << "Maximum Distance = " << fMaximumDistance << " " << fDeltaD << noD << "\n";
496  for (i = 0; i < noD; i++) {
497  std::cout << "D,E= " << fDeltaE * i << "," << DtoEtab[i] << "\n";
498  }
499 }
500 
501 Double_t AtTools::AtELossManager::GetLookupEnergy(Double_t InitialEnergy, Double_t distance)
502 {
503 
504  Double_t D1, D2, D;
505  Double_t E1, E2, E;
506  int index;
507  int imhere;
508 
509  if (InitialEnergy < 0 || InitialEnergy > fMaximumEnergy) {
510  return (-1.);
511  }
512 
513  // Find the distance for which the initial energy is matched, interpolating
514  index = (int)floor((fMaximumEnergy - InitialEnergy) / fDeltaE);
515 
516  D1 = EtoDtab[index];
517  D2 = EtoDtab[index + 1];
518 
519  E1 = fMaximumEnergy - index * fDeltaE;
520  E2 = fMaximumEnergy - (index + 1) * fDeltaE;
521 
522  D = (InitialEnergy - E1) / (E2 - E1) * (D2 - D1) + D1;
523  // cout << " 1: "<< index << ' ' <<E1 << ' ' << E2 << ' ' << D1 << ' ' << D2 << ' ' << D << endl;
524 
525  // Still in the table ?
526  if (((D + distance <= 0)) || ((D + distance) > fMaximumDistance)) {
527  // if (((D+distance)> MaximumDistance)){
528  // if (D+distance <=0){
529  std::cout << "i m here"
530  << "\n";
531  // imhere++;
532  return (0.);
533  }
534 
535  // Lookup what energy is reached for (D + distance) and interpolate
536  index = (int)floor((D + distance) / fDeltaD);
537 
538  E1 = DtoEtab[index];
539  E2 = DtoEtab[index + 1];
540 
541  D1 = index * fDeltaD;
542  D2 = (index + 1) * fDeltaD;
543 
544  E = ((D + distance) - D1) / (D2 - D1) * (E2 - E1) + E1;
545  // cout <<" 2: "<< E1 << ' ' << E2 << ' ' << D1 << ' ' << D2 << ' ' << E << endl;
546 
547  // cout<<"E == "<<E<<endl;
548  // cout<<imhere<<endl;
549  return (E);
550 }
AtTools::AtELossManager::LoadRange
Double_t LoadRange(Float_t energy1)
Definition: AtELossManager.cxx:345
TOF
Definition: S800Calc.h:147
AtELossManager.h
AtTools::AtELossManager::PrintLookupTables
void PrintLookupTables()
Definition: AtELossManager.cxx:485
AtTools::AtELossManager::GetLookupEnergy
Double_t GetLookupEnergy(Double_t InitialEnergy, Double_t distance)
Definition: AtELossManager.cxx:501
AtTools::AtELossManager::GetEnergyLossLinear
Double_t GetEnergyLossLinear(Double_t energy, Double_t distance)
Definition: AtELossManager.cxx:68
AtTools::AtELossManager::InitializeLookupTables
void InitializeLookupTables(Double_t MaximumEnergy, Double_t MaximumDistance, Double_t DeltaE, Double_t DeltaD)
Definition: AtELossManager.cxx:416
AtTools::AtELossManager::GetInitialEnergy
Double_t GetInitialEnergy(Double_t FinalEnergy, Double_t PathLength, Double_t StepSize)
Definition: AtELossManager.cxx:217
AtTools::AtELossManager::GetTimeOfFlight
Double_t GetTimeOfFlight(Double_t InitialEnergy, Double_t PathLength, Double_t StepSize)
Definition: AtELossManager.cxx:386
AtTools::AtELossManager
Definition: AtELossManager.h:24
AtTools::AtELossManager::SetIonMass
void SetIonMass(Double_t IonMass)
Definition: AtELossManager.cxx:410
AtTools::AtELossManager::~AtELossManager
~AtELossManager()
AtTools::AtELossManager::GetFinalEnergy
Double_t GetFinalEnergy(Double_t InitialEnergy, Double_t PathLength, Double_t StepSize)
Definition: AtELossManager.cxx:246
AtTools::AtELossManager::GetEnergyLoss
Double_t GetEnergyLoss(Double_t energy, Double_t distance)
Definition: AtELossManager.cxx:122
AtTools::AtELossManager::GetDistance
Double_t GetDistance(Double_t InitialE, Double_t FinalE, Double_t StepSize)
Definition: AtELossManager.cxx:280
ClassImp
ClassImp(AtTools::AtELossManager)
AtTools::AtELossManager::GetPathLength
Double_t GetPathLength(Float_t InitialEnergy, Float_t FinalEnergy, Float_t DeltaT)
Definition: AtELossManager.cxx:301
AtTools::AtELossManager::AtELossManager
AtELossManager()
Definition: AtELossManager.cxx:13
c
constexpr auto c
Definition: AtRadialChargeModel.cxx:20