249 lines
5.2 KiB
C++
249 lines
5.2 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <map>
|
|
#include <cmath>
|
|
#include <memory>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#include <filesystem>
|
|
|
|
// ROOT
|
|
#include "TFile.h"
|
|
#include "TTree.h"
|
|
#include "TH1D.h"
|
|
#include "TH2D.h"
|
|
#include "TCanvas.h"
|
|
|
|
// Catima
|
|
#include <catima/catima.h>
|
|
|
|
using namespace std;
|
|
|
|
/* =========================
|
|
GLOBAL STRUCTURES
|
|
========================= */
|
|
|
|
struct Particle {
|
|
int z;
|
|
double mass_u;
|
|
double emax;
|
|
string name;
|
|
};
|
|
|
|
map<string, Particle> particles = {
|
|
{"alpha", {2, 4.0026, 40, "alpha"}},
|
|
{"proton", {1, 1.0078, 20, "proton"}},
|
|
{"deuteron", {1, 2.0141, 30, "deuteron"}}
|
|
};
|
|
|
|
/* =========================
|
|
INTERPOLATION STORAGE
|
|
========================= */
|
|
|
|
struct EnergyTable {
|
|
vector<double> x;
|
|
vector<double> E;
|
|
};
|
|
|
|
map<string, EnergyTable> table_cache;
|
|
|
|
/* Linear interpolation */
|
|
double interp(const vector<double>& x, const vector<double>& y, double xi) {
|
|
if (xi <= x.front()) return y.front();
|
|
if (xi >= x.back()) return y.back();
|
|
|
|
auto it = upper_bound(x.begin(), x.end(), xi);
|
|
int i = distance(x.begin(), it) - 1;
|
|
|
|
double x0 = x[i], x1 = x[i+1];
|
|
double y0 = y[i], y1 = y[i+1];
|
|
|
|
return y0 + (y1 - y0) * (xi - x0) / (x1 - x0);
|
|
}
|
|
|
|
/* =========================
|
|
ENERGY TABLE GENERATION
|
|
========================= */
|
|
|
|
void make_E_vs_x(int z, double mass_u, double emax, string label, int npoints, double P_torr, double T) {
|
|
|
|
double R = 8.3144;
|
|
|
|
double p_pa = P_torr * 133.322;
|
|
double molar_density = p_pa / (R * T);
|
|
|
|
double m_he = 4.0026;
|
|
double m_c = 12.0;
|
|
double m_o = 15.9949;
|
|
|
|
double m_mix = 0.96*m_he + 0.04*(m_c + 2*m_o);
|
|
|
|
double rho = (molar_density * m_mix) / 1e6;
|
|
|
|
catima::Material gas({
|
|
{m_he, 2, 0.96},
|
|
{m_c, 6, 0.04},
|
|
{m_o, 8, 0.08}
|
|
});
|
|
gas.density(rho);
|
|
|
|
catima::Projectile proj(mass_u, z);
|
|
|
|
vector<double> E(npoints);
|
|
vector<double> S(npoints);
|
|
|
|
for (int i = 0; i < npoints; i++) {
|
|
E[i] = 0.01 + i * (emax / npoints);
|
|
|
|
proj.T(E[i] / mass_u);
|
|
S[i] = catima::dedx(proj, gas) * rho;
|
|
}
|
|
|
|
reverse(E.begin(), E.end());
|
|
reverse(S.begin(), S.end());
|
|
|
|
vector<double> x(npoints, 0.0);
|
|
|
|
for (int i = 1; i < npoints; i++) {
|
|
double invS = 1.0 / S[i];
|
|
x[i] = x[i-1] + 0.5 * (invS + 1.0/S[i-1]) * (E[i] - E[i-1]);
|
|
}
|
|
|
|
ofstream out("E_vs_x_" + label + ".dat");
|
|
for (int i = 0; i < npoints; i++) {
|
|
out << x[i] << "\t" << E[i] << "\n";
|
|
}
|
|
|
|
cout << "Saved E_vs_x_" << label << ".dat\n";
|
|
}
|
|
|
|
/* =========================
|
|
LOAD TABLE
|
|
========================= */
|
|
|
|
EnergyTable load_table(string fname) {
|
|
EnergyTable t;
|
|
ifstream in(fname);
|
|
|
|
double x, E;
|
|
while (in >> x >> E) {
|
|
t.x.push_back(x);
|
|
t.E.push_back(E);
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/* =========================
|
|
GET TABLE
|
|
========================= */
|
|
|
|
EnergyTable& get_table(string particle) {
|
|
if (!table_cache.count(particle)) {
|
|
table_cache[particle] = load_table("E_vs_x_" + particle + ".dat");
|
|
}
|
|
return table_cache[particle];
|
|
}
|
|
|
|
/* =========================
|
|
ENERGY FUNCTIONS
|
|
========================= */
|
|
|
|
double energy_loss(string p, double Ei, double dx) {
|
|
auto &t = get_table(p);
|
|
|
|
double xi = interp(t.E, t.x, Ei);
|
|
double xf = xi + dx;
|
|
|
|
double Ef = interp(t.x, t.E, xf);
|
|
return max(Ef, 0.0);
|
|
}
|
|
|
|
double energy_reconstruction(string p, double Ef, double dx) {
|
|
auto &t = get_table(p);
|
|
|
|
double xf = interp(t.E, t.x, Ef);
|
|
double xi = xf - dx;
|
|
|
|
double Ei = interp(t.x, t.E, xi);
|
|
return max(Ei, 0.0);
|
|
}
|
|
|
|
double energy_distance(string p, double Ei, double Ef) {
|
|
auto &t = get_table(p);
|
|
|
|
double xi = interp(t.E, t.x, Ei);
|
|
double xf = interp(t.E, t.x, Ef);
|
|
|
|
return fabs(xf - xi);
|
|
}
|
|
|
|
/* =========================
|
|
ROOT FILE ANALYSIS
|
|
========================= */
|
|
|
|
void process_file(string filename) {
|
|
|
|
TFile f(filename.c_str());
|
|
TTree *tree = (TTree*)f.Get("tree");
|
|
|
|
double Tb, thetab, sx3Z;
|
|
|
|
tree->SetBranchAddress("Tb", &Tb);
|
|
tree->SetBranchAddress("thetab", &thetab);
|
|
tree->SetBranchAddress("sx3Z", &sx3Z);
|
|
|
|
vector<double> Ei, theta, sx3;
|
|
|
|
Long64_t n = tree->GetEntries();
|
|
|
|
for (Long64_t i = 0; i < n; i++) {
|
|
tree->GetEntry(i);
|
|
|
|
double th = thetab * M_PI / 180.0;
|
|
if (sin(th) == 0) continue;
|
|
|
|
Ei.push_back(Tb);
|
|
theta.push_back(th);
|
|
sx3.push_back(sx3Z);
|
|
}
|
|
|
|
cout << "Processed " << Ei.size() << " events\n";
|
|
}
|
|
|
|
/* =========================
|
|
MAIN CLI (simplified)
|
|
========================= */
|
|
|
|
int main() {
|
|
|
|
string cmd;
|
|
|
|
cout << "C++ PCEnergy Shell\n";
|
|
|
|
while (true) {
|
|
cout << ">> ";
|
|
getline(cin, cmd);
|
|
|
|
if (cmd == "exit") break;
|
|
|
|
if (cmd.rfind("make table", 0) == 0) {
|
|
string name = cmd.substr(11);
|
|
auto p = particles[name];
|
|
|
|
make_E_vs_x(p.z, p.mass_u, p.emax, p.name, 500, 400, 293.15);
|
|
}
|
|
|
|
else if (cmd.rfind("energy loss", 0) == 0) {
|
|
cout << "Use API call version in compiled mode\n";
|
|
}
|
|
|
|
else {
|
|
cout << "Unknown command\n";
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|