GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TSRIM.cxx
Go to the documentation of this file.
1#include "TSRIM.h"
2
3#include "Globals.h"
4#include "TGRSIUtilities.h"
5
6#include <TVector3.h>
7#include <TMath.h>
8
9#include <cmath>
10#include <sstream>
11#include <TStopwatch.h>
12
13#include <cstdio>
14
15const double TSRIM::dx = 1.0; // um [sets accuracy of energy loss E vs X functions]
16
17TSRIM::TSRIM(const char* infilename, double emax, double emin, bool printfile)
18{
19 ReadEnergyLossFile(infilename, emax, emin, printfile);
20}
21
22void TSRIM::ReadEnergyLossFile(const char* filename, double emax, double emin, bool printfile)
23{
24 // if Steffen makes a TSRIM file that this thing can't read it's beacuse of mac encoding.
25 // use dos2unix -c mac d_in_Si.txt in terminal
26 std::ifstream infile;
27
28 std::string fname = filename;
29 if(fname.find(".txt") == std::string::npos) {
30 fname.append(".txt");
31 }
32
33 std::string grsipath = getenv("GRSISYS");
34 std::ostringstream ostr;
35 ostr << grsipath << "/libraries/TAnalysis/SRIMData/";
36 if(!DirectoryExists(ostr.str().c_str())) {
37 ostr.str(std::string());
38 ostr << grsipath << "/SRIMData/";
39 }
40 if(!DirectoryExists(ostr.str().c_str())) {
41 std::cout << std::endl
42 << "Failed to find directory with SRIM data, tried \"" << grsipath << "/libraries/TAnalysis/SRIMData/\" and \"" << grsipath << "/SRIMData/\"!" << std::endl;
43 }
44 ostr << fname;
45 if(printfile) {
46 std::cout << std::endl
47 << "Searching for " << ostr.str() << "..." << std::endl;
48 }
49
50 infile.open(ostr.str().c_str());
51 if(!infile.good()) {
52 std::cout << "{TSRIM} Warning : Couldn't find the file '" << filename << "' ..." << std::endl;
53 return;
54 }
55 std::string line;
56 std::string word;
57 double density_scale = 0.;
58 double temp = 0.;
59
60 std::vector<double> number_input;
61 std::vector<double> dEdX_temp;
62 std::vector<std::string> string_input;
63
64 while(!std::getline(infile, line).fail()) {
65 if(line.length() == 0u) {
66 continue;
67 }
68 std::istringstream linestream(line);
69 number_input.clear();
70 string_input.clear();
71 while(!(linestream >> word).fail()) {
72 std::istringstream str(word);
73 if(!(str >> temp).fail()) { // if it's a number
74 number_input.push_back(temp);
75 } else {
76 string_input.push_back(str.str());
77 }
78 }
79
80 if((string_input[0].compare(0, 3, "keV") == 0) && (string_input[1].compare(0, 1, "/") == 0) &&
81 (string_input[2].compare(0, 6, "micron") == 0)) {
82 density_scale = number_input[0];
83 // cout<<"dEdX will be scaled by "<<density_scale<<" so that stopping power is in keV/um \n";
84 } else if(number_input.size() != 6) {
85 continue;
86 }
87
88 if(string_input[0].compare(0, 3, "eV") == 0 && string_input[1].compare(0, 1, "/") != 0) {
89 fIonEnergy.push_back(number_input[0] * 1e-3); // convert eV to keV.
90 } else if(string_input[0].compare(0, 3, "keV") == 0 && string_input[1].compare(0, 1, "/") != 0) {
91 fIonEnergy.push_back(number_input[0]); // already in keV.
92 } else if(string_input[0].compare(0, 3, "MeV") == 0 && string_input[1].compare(0, 1, "/") != 0) {
93 fIonEnergy.push_back(number_input[0] * 1e3); // convert MeV to keV.
94 } else if(string_input[0].compare(0, 3, "GeV") == 0 && string_input[1].compare(0, 1, "/") != 0) {
95 fIonEnergy.push_back(number_input[0] * 1e6); // convert GeV to keV.
96 } else {
97 continue;
98 }
99
100 dEdX_temp.push_back((number_input[1] + number_input[2]));
101 }
102
103 if(!dEdX_temp.empty()) {
104 if(density_scale == 0.) {
105 std::cout << "WARNING: stopping power remains in original units, unable to find scale factor." << std::endl;
106 density_scale = 1.;
107 }
108
109 for(double index : dEdX_temp) {
110 fdEdX.push_back(index * density_scale);
111 }
112
113 fEnergyLoss = new TGraph(static_cast<Int_t>(fIonEnergy.size()), fIonEnergy.data(), fdEdX.data());
114 fEnergyLoss->GetXaxis()->SetTitle("Energy (keV)");
115 fEnergyLoss->GetYaxis()->SetTitle("dE/dx (keV/um)");
116 fsEnergyLoss = new TSpline3("dEdX_vs_E", fEnergyLoss);
117
118 double dataEmax = TMath::MaxElement(static_cast<Int_t>(fIonEnergy.size()), fIonEnergy.data());
119 double dataEmin = TMath::MinElement(static_cast<Int_t>(fIonEnergy.size()), fIonEnergy.data());
120
121 if(emax == -1.0) {
122 emax = dataEmax; // default to highest available energy in data table
123 } else if(emax > dataEmax || emax < dataEmin) {
124 std::cout << std::endl
125 << "{TSRIM} WARNING: specified emax is out of range. Setting emax to default value (" << dataEmax << ")" << std::endl;
126 emax = dataEmax; // default to highest available energy in data table
127 }
128 if(emin == 0.0) {
129 emin = dataEmin; // default to lowest available energy in data table
130 } else if(emin < dataEmin || emin > dataEmax) {
131 std::cout << std::endl
132 << "{TSRIM} WARNING: specified emin is out of range. Setting emin to default value (" << dataEmin << ")" << std::endl;
133 emin = dataEmin; // default to lowest available energy in data table
134 }
135 if(emax < emin) {
136 double emaxtemp = emax;
137 emax = emin;
138 emin = emaxtemp;
139 }
140
141 // Use linear multistep method (order 3) - Adams-Bashford method (explicit).
142 double xtemp = 0;
143 double xstep = dx;
144 double etemp = emax;
145 std::array<double, 4> k = {0, 0, 0, 0};
146
147 for(int i = 0; i < 3; i++) { // start by using euler step on first few points
148 fX.push_back(xtemp);
149 fE.push_back(etemp);
150 k[i] = fsEnergyLoss->Eval(etemp); // contains gradient at previous steps
151
152 xtemp += xstep;
153 etemp -= xstep * fsEnergyLoss->Eval(etemp);
154 }
155
156 while(fE.back() > 0) { // keep going until E goes negative
157 fX.push_back(xtemp);
158 fE.push_back(etemp);
159
160 xtemp += xstep;
161 k[3] = k[2];
162 k[2] = k[1];
163 k[1] = k[0];
164 k[0] = fsEnergyLoss->Eval(etemp);
165 // extrapolate to new energy using weighted average of gradients at previous points
166 etemp -= xstep * (55 / 24 * k[0] - 59 / 24 * k[1] + 37 / 24 * k[2] - 8 / 24 * k[3]);
167 }
168 // force the last element to be emin (linear interpolation, small error)
169 fX.back() = fX[fX.size() - 2] + (fX.back() - fX[fX.size() - 2]) * (emin - fE[fE.size() - 2]) / (fE.back() - fE[fE.size() - 2]);
170 fE.back() = emin;
171
172 fEmin = TMath::MinElement(static_cast<Long64_t>(fE.size()), fE.data());
173 fEmax = TMath::MaxElement(static_cast<Long64_t>(fE.size()), fE.data());
174 fXmin = TMath::MinElement(static_cast<Long64_t>(fX.size()), fX.data());
175 fXmax = TMath::MaxElement(static_cast<Long64_t>(fX.size()), fX.data());
176
177 fXgetE = new TGraph(static_cast<Int_t>(fX.size()), fX.data(), fE.data());
178 fXgetE->SetName("XgetE");
179 fXgetE->SetTitle(filename);
180 fXgetE->GetXaxis()->SetTitle("Distance (um)");
181 fXgetE->GetYaxis()->SetTitle("Energy (keV)");
182 fsXgetE = new TSpline3(Form("%s_Xspline", filename), fXgetE);
183 fsXgetE->SetName(Form("%s_Xspline", filename));
184
185 fEgetX = new TGraph(static_cast<Int_t>(fE.size()));
186 for(int x = fE.size() - 1; x >= 0; x--) { // make sure x data is increasing
187 fEgetX->SetPoint(fE.size() - x - 1, fE.at(x), fX.at(x));
188 }
189 fEgetX->SetName("EgetX");
190 fEgetX->SetTitle(filename);
191 fEgetX->GetYaxis()->SetTitle("Distance (um)");
192 fEgetX->GetXaxis()->SetTitle("Energy (keV)");
193 fsEgetX = new TSpline3(Form("%s_Espline", filename), fEgetX);
194 fsEgetX->SetName(Form("%s_Espline", filename));
195 }
196
197 if(printfile) {
198 std::cout << std::endl
199 << "\t" << fname << " file read in, " << fdEdX.size() << " entries found." << std::endl;
200 std::cout << "[Energy loss range = " << fEmax << " - " << fEmin << " keV & total range = " << fXmin << " - " << fXmax << " um ]" << std::endl;
201 }
202}
203
204double TSRIM::GetEnergy(double energy, double dist)
205{
206 double xbegin = fsEgetX->Eval(energy);
207
208 if(energy > fEmax || xbegin + dist < fXmin) {
209 std::cout << std::endl
210 << " {TSRIM} WARNING: data is out of range. Results may be unpredictable." << std::endl
211 << DRED "\t\tenergy = " << energy << " keV \txbegin = " << xbegin << " um\t dist = " << dist << " um\t xend = " << xbegin + dist << " um" << std::endl
212 << DYELLOW << "\t\tErange = [" << fEmin << ", " << fEmax << "] keV \t\t Xrange = [0 , " << fXmax << " um" << RESET_COLOR << std::endl;
213 } else if(xbegin > fXmax || xbegin + dist > fXmax) {
214 return 0.0;
215 }
216
217 return fsXgetE->Eval(xbegin + dist);
218}
219
220// THIS FUNCTION DOES A MORE ACCURATE ENERGY LOSS CALCULATION BASED ON SMALL EXTRAPOLATIONS
221double TSRIM::GetAdjustedEnergy(double energy, double thickness, double stepsize)
222{
223 if(fEnergyLoss == nullptr) {
224 std::cout << "energy loss file has not yet been read in." << std::endl;
225 return 0.0;
226 }
227
228 double energy_temp = energy;
229 double xstep = stepsize;
230 double xtot = 0.0; // MAKE XSTEP SMALLER FOR BETTER RESULTS. 1UM SHOULD BE FINE ... UNLESS YOU ARE AT THE BRAGG PEAK ??
231 energy_temp -= fmod(thickness, xstep) * fsEnergyLoss->Eval(energy_temp); // get rid of fractional distance
232 xtot += fmod(thickness, xstep);
233
234 if(thickness >= xstep) {
235 while(xtot < thickness) {
236 energy_temp -= xstep * fsEnergyLoss->Eval(energy_temp); // update energy recursively so that it decreases each step
237 xtot += xstep;
238 if(energy_temp <= 0.0) {
239 return 0.0; // if no energy is remaining then final energy is zero
240 }
241 }
242 }
243
244 return energy_temp;
245}
#define DYELLOW
Definition Globals.h:16
#define DRED
Definition Globals.h:18
#define RESET_COLOR
Definition Globals.h:5
bool DirectoryExists(const char *dirname)
double fXmax
Definition TSRIM.h:47
TGraph * fXgetE
Definition TSRIM.h:38
TSpline3 * fsXgetE
Definition TSRIM.h:41
static const double dx
Definition TSRIM.h:48
void ReadEnergyLossFile(const char *filename, double emax=-1.0, double emin=0.0, bool printfile=true)
Definition TSRIM.cxx:22
double fEmin
Definition TSRIM.h:44
std::vector< double > fX
Definition TSRIM.h:43
double GetAdjustedEnergy(double energy, double thickness, double stepsize=dx)
Definition TSRIM.cxx:221
TGraph * fEgetX
Definition TSRIM.h:37
double GetEnergy(double energy, double dist)
Definition TSRIM.cxx:204
std::vector< double > fIonEnergy
Definition TSRIM.h:34
TSRIM()=default
double fXmin
Definition TSRIM.h:46
TSpline3 * fsEnergyLoss
Definition TSRIM.h:39
std::vector< double > fE
Definition TSRIM.h:42
TSpline3 * fsEgetX
Definition TSRIM.h:40
TGraph * fEnergyLoss
Definition TSRIM.h:36
std::vector< double > fdEdX
Definition TSRIM.h:35
double fEmax
Definition TSRIM.h:45