Skip to content

Commit a6b646b

Browse files
committed
Add macro for simulating many tracks
1 parent c2f5c1a commit a6b646b

2 files changed

Lines changed: 223 additions & 0 deletions

File tree

macro/e12014/adam/ML/readme.md

Whitespace-only changes.
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
std::string getEnergyPath()
2+
{
3+
auto env = std::getenv("VMCWORKDIR");
4+
if (env == nullptr) {
5+
return "../../resources/energy_loss/HinH.txt"; // Default path assuming cwd is build/AtTools
6+
}
7+
return std::string(env) + "/resources/energy_loss/HinH.txt"; // Use environment variable
8+
}
9+
using ROOT::Math::XYZPoint;
10+
using ROOT::Math::XYZVector;
11+
12+
const double mass_p = 938.272; // Mass of proton in MeV/c^2
13+
const double charge_p = 1.602176634e-19; // Charge of proton
14+
15+
// Vectors to store the simulated points to compare to
16+
std::vector<double> x_sim, y_sim, z_sim, Eloss_sim;
17+
TH1F *hMom = nullptr;
18+
TH1F *hMomSampled = nullptr;
19+
TH1F *hMomError = nullptr;
20+
TH1F *hMomError2 = nullptr;
21+
22+
TCanvas *c1 = new TCanvas();
23+
TCanvas *c2 = new TCanvas();
24+
25+
// Parameters for model
26+
const int pointsToCluster = 5;
27+
const double sigma_pos = 1; // Position uncertainty of 10 mm
28+
const double sigma_mom = 0.1; // Momentum uncertainty in percentage
29+
const double sigma_mom_sample = 0.05; // Sampled momentum uncertainty in percentage
30+
const double sigma_theta = 1 * M_PI / 180; // Angular uncertainty of 1 degree
31+
const double sigma_phi = 1 * M_PI / 180; // Angular uncertainty of 1 degree
32+
const double gasDensity = 3.553e-5; // g/cm^3
33+
const double fAlpha = 1e-1;
34+
const double fBeta = 2;
35+
const double fKappa = 0;
36+
37+
// Global variables
38+
kf::TrackFitterUKF *ukf = nullptr;
39+
40+
// Functions in file
41+
/// Loads hits from an input file
42+
void LoadHits();
43+
/// Run a single UKF for the passed initial state
44+
void SingleUKF(XYZPoint initialPos, XYZVector initialMom, TMatrixD initialCov);
45+
/// @brief Create the ukf pointer to reuse.
46+
void CreateUKF();
47+
48+
TMatrixD CalculateInitialCov(double p);
49+
TMatrixD CalculatePosCov();
50+
51+
/// @brief Test many tracks, saving stat properties
52+
/// @param n
53+
/// @param bias
54+
void TestManyTracks(int n, double bias = 0)
55+
{
56+
LoadHits();
57+
CreateUKF();
58+
59+
XYZPoint fTruePos(-3.40046e-04, -1.49863e-04, 1.0018);
60+
XYZVector fTrueMom(0.00935463, -0.0454279, 0.00826042);
61+
fTrueMom *= 1e3;
62+
double prevKE = AtTools::Kinematics::KE(fTrueMom.R(), mass_p) - Eloss_sim[0];
63+
double fMomPrev = AtTools::Kinematics::GetRelMomFromKE(prevKE, mass_p);
64+
std::cout << "Initial mom: " << fTrueMom.R() << " past mom " << fMomPrev << std::endl;
65+
66+
double fSigmaMom = fTrueMom.R() * sigma_mom_sample;
67+
68+
hMom = new TH1F("hMom", "Reconstructed Momentum (MeV/c)", 100, fTrueMom.R() - 4 * fSigmaMom,
69+
fTrueMom.R() + 4 * fSigmaMom);
70+
hMomSampled = new TH1F("hMom", "Reconstructed Momentum (MeV/c)", 100, fTrueMom.R() - 4 * fSigmaMom,
71+
fTrueMom.R() + 4 * fSigmaMom);
72+
hMomError = new TH1F("hMomError", "Error (%)", 100, -2, 2);
73+
hMomError2 =
74+
new TH1F("hMomError2", "Error (%)", 100, -4 * fSigmaMom / fTrueMom.R() * 100, 4 * fSigmaMom / fTrueMom.R() * 100);
75+
76+
for (int i = 0; i < n; ++i) {
77+
78+
if (i % 100 == 0)
79+
std::cout << "On iteration " << i << std::endl;
80+
81+
double pSampled = gRandom->Gaus(fTrueMom.R(), sigma_mom_sample * fTrueMom.R());
82+
pSampled += bias;
83+
hMomSampled->Fill(pSampled);
84+
85+
// pSampled = fTrueMom.R();
86+
87+
ROOT::Math::Polar3DVector sampledMom(pSampled, fTrueMom.Theta(), fTrueMom.Phi());
88+
SingleUKF(fTruePos, XYZVector(sampledMom), CalculateInitialCov(pSampled));
89+
90+
auto filtState = ukf->GetFilteredStates()[0];
91+
auto smoothState = ukf->GetSmoothedStates()[0];
92+
auto smoothStatePrev = ukf->GetSmoothedStates()[1];
93+
94+
double pReco = (smoothState[3] + smoothStatePrev[3]) / 2; // Average of current and previous state
95+
hMom->Fill(pReco);
96+
double error = (pReco - fTrueMom.R()) / fTrueMom.R() * 100;
97+
hMomError->Fill(error);
98+
double errorPrev = (ukf->GetSmoothedStates()[1][3] - fMomPrev) / fMomPrev * 100;
99+
hMomError2->Fill(errorPrev);
100+
101+
std::cout << std::endl
102+
<< std::endl
103+
<< "With initial momentum " << pSampled << " reconstructed " << pReco << " Error: " << error << "%"
104+
<< std::endl
105+
<< std::endl;
106+
}
107+
108+
// Draw results
109+
c1->cd();
110+
hMomSampled->Scale(10);
111+
hMomSampled->SetStats(0);
112+
hMom->SetStats(0);
113+
hMom->Draw("hist");
114+
hMomSampled->SetLineColor(kRed);
115+
hMomSampled->Draw("same hist");
116+
117+
auto legend = new TLegend(0.65, 0.75, 0.88, 0.88);
118+
legend->AddEntry(hMom, "Reconstructed", "l");
119+
legend->AddEntry(hMomSampled, "Sampled (scale x10)", "l");
120+
legend->Draw();
121+
122+
c2->cd();
123+
hMomError->Draw("hist");
124+
// hMomError2->SetLineColor(kRed);
125+
// hMomError2->Draw("same hist");
126+
}
127+
128+
/*********** Function implementations **************/
129+
void LoadHits()
130+
{
131+
if (x_sim.size() != 0)
132+
return;
133+
Eloss_sim.clear();
134+
std::ifstream infile("hits.txt");
135+
double xi, yi, zi, Ei;
136+
int i = 0;
137+
double eLoss = 0;
138+
139+
// Save first point.
140+
infile >> xi >> yi >> zi >> Ei;
141+
eLoss = Ei; // Initialize energy loss
142+
x_sim.push_back(xi * 10); // Convert to mm
143+
y_sim.push_back(yi * 10); // Convert to mm
144+
z_sim.push_back(zi * 10); // Convert to mm
145+
146+
while (infile >> xi >> yi >> zi >> Ei) {
147+
// Ei *= 1e3; // Convert to MeV
148+
149+
if (++i % pointsToCluster != 0) {
150+
eLoss += Ei;
151+
continue; // Skip every 5th point
152+
}
153+
x_sim.push_back(xi * 10);
154+
y_sim.push_back(yi * 10);
155+
z_sim.push_back(zi * 10);
156+
Eloss_sim.push_back(eLoss);
157+
eLoss = 0; // Reset energy loss for the next segment
158+
}
159+
}
160+
161+
void CreateUKF()
162+
{
163+
auto elossModel2 = std::make_unique<AtTools::AtELossCATIMA>(gasDensity);
164+
elossModel2->SetProjectile(1, 1, 1);
165+
std::vector<std::tuple<int, int, int>> mat;
166+
mat.push_back({1, 1, 1});
167+
elossModel2->SetMaterial(mat);
168+
169+
auto elossModel = std::make_unique<AtTools::AtELossTable>(0);
170+
elossModel->LoadSrimTable(getEnergyPath()); // Use the function to get the path
171+
elossModel->SetDensity(gasDensity);
172+
173+
AtTools::AtPropagator propagator(charge_p, mass_p, std::move(elossModel));
174+
propagator.SetEField({0, 0, 0}); // No electric field
175+
propagator.SetBField({0, 0, 2.85}); // Magnetic field
176+
177+
// Setup stepper for UKF
178+
auto stepper = std::make_unique<AtTools::AtRK4Stepper>();
179+
180+
// Setup UKF
181+
ukf = new kf::TrackFitterUKF(std::move(propagator), std::move(stepper));
182+
ukf->setParameters(fAlpha, fBeta, fKappa);
183+
}
184+
185+
TMatrixD CalculateInitialCov(double p)
186+
{
187+
TMatrixD cov(6, 6);
188+
cov.Zero();
189+
for (int i = 0; i < 3; ++i) {
190+
191+
cov(i, i) = sigma_pos * sigma_pos; // Set diagonal covariance to some small number
192+
}
193+
cov(3, 3) = p * p * sigma_mom * sigma_mom; // Momentum uncertainty
194+
cov(4, 4) = sigma_theta * sigma_theta; // Angular uncertainty
195+
cov(5, 5) = sigma_phi * sigma_phi; // Angular uncertainty
196+
197+
return cov;
198+
}
199+
TMatrixD CalculatePosCov()
200+
{
201+
TMatrixD cov(3, 3);
202+
cov.Zero();
203+
for (int i = 0; i < 3; ++i) {
204+
205+
cov(i, i) = sigma_pos * sigma_pos; // Set diagonal covariance to some small number
206+
}
207+
return cov;
208+
}
209+
210+
void SingleUKF(XYZPoint intitialPos, XYZVector initialMom, TMatrixD intitialCov)
211+
{
212+
ukf->SetInitialState(intitialPos, initialMom, intitialCov);
213+
214+
for (int i = 1; i < x_sim.size(); ++i) {
215+
ukf->SetMeasCov(CalculatePosCov());
216+
XYZPoint point(x_sim[i], y_sim[i], z_sim[i]);
217+
218+
ukf->predictUKF(point);
219+
ukf->correctUKF(point);
220+
}
221+
222+
ukf->smoothUKF();
223+
}

0 commit comments

Comments
 (0)