26
#include "TSpectrum.h"
29
#include "DataStructure/Spill.hh"
30
#include "DataStructure/Data.hh"
31
#include "DataStructure/ReconEvent.hh"
32
#include "DataStructure/TOFEvent.hh"
33
#include "DataStructure/SciFiEvent.hh"
35
// Returns the global coordinates of the detectors (fetched in the geometry)
36
class DetectorGlobals {
39
// Default constructor, initilizes everything to 0
40
DetectorGlobals() : _globals(0., 0., 0.), _angles (0., 0., 0.) {}
43
DetectorGlobals(std::string filename, std::string name) {
44
this->Load(filename, name);
48
DetectorGlobals(const DetectorGlobals& detector_globals) {
49
*this = detector_globals;
53
DetectorGlobals operator=(const DetectorGlobals& detector_globals) {
54
if ( this == &detector_globals )
57
this->SetDetectorGlobals(detector_globals._globals);
58
this->SetDetectorRotations(detector_globals._angles);
64
~DetectorGlobals () {}
66
// Loads the global constants from the parent geometry file
67
bool Load(std::string filename, std::string name) {
68
std::ifstream infile(filename.c_str());
69
if ( !infile.is_open() ) {
70
std::cerr << "The geometry file could not be found: " << filename << std::endl;
74
bool det_found(false);
75
while ( !infile.eof() ) {
78
if ( word.find(name) != std::string::npos ) {
80
while ( word != "}" ) {
82
if ( word == "Position" ) {
84
_globals.SetX(std::atof(word.c_str()));
86
_globals.SetY(std::atof(word.c_str()));
88
_globals.SetZ(std::atof(word.c_str()));
89
} else if ( word == "Rotation" ) {
91
_angles.SetX(std::atof(word.c_str()));
93
_angles.SetY(std::atof(word.c_str()));
95
_angles.SetZ(std::atof(word.c_str()));
105
std::cerr << "Detector not found in geometry file: " << name << std::endl;
112
// Setters and getters
113
void SetDetectorGlobals(TVector3 globals) { _globals = globals; }
114
TVector3 GetDetectorGlobals() { return _globals; }
115
void SetDetectorRotations(TVector3 angles) { _angles = angles; }
116
TVector3 GetDetectorRotations() { return _angles; }
117
double x() { return _globals.x(); }
118
double y() { return _globals.y(); }
119
double z() { return _globals.z(); }
120
double alpha() { return _angles.x(); }
121
double beta() { return _angles.y(); }
122
double gamma() { return _angles.z(); }
129
// Computes the geometrical distance between two detector space points
130
double distance (const TVector3& a, const TVector3& b) {
132
return sqrt( pow(b.x()-a.x(), 2) +
133
pow(b.y()-a.y(), 2) +
134
pow(b.z()-a.z(), 2) );
140
// Main alignment code
141
int main(int argc, char ** argv) {
143
// Return if there is no input file
145
std::cerr << "No data card specified, please execute in the following fashion:" << std::endl;
146
std::cerr << "./align_trackers datacard.txt data0.root [... dataN.root]" << std::endl;
151
std::cerr << "No data file specified, please execute in the following fashion:" << std::endl;
152
std::cerr << "./align_trackers datacard.txt data0.root [... dataN.root]" << std::endl;
156
// Get the run name from the file name (remove superfluous with regex)
157
std::string run_name = std::regex_replace(std::string(argv[2]),
158
std::regex("(.*/)|(.root)"), "");
160
// Fitting algorithm parameters
161
std::string geo_file;
162
size_t iterations(0);
166
std::ifstream datacard(argv[1]);
167
if ( !datacard.is_open() ) {
168
std::cerr << "Datacards not found, please verify path: " << argv[1] << std::endl;
171
while ( !datacard.eof() ) {
172
std::string variable, value;
173
datacard >> variable >> value;
174
if ( variable == "geometry_filename" )
176
else if ( variable == "number_of_iterations" )
177
iterations = atoi(value.c_str());
178
else if ( variable == "do_pid" )
179
do_pid = (bool)atoi(value.c_str());
180
else if ( variable == "do_roll" )
181
do_roll = (bool)atoi(value.c_str());
182
else if ( variable.size() )
183
std::cerr << "Unrecognised argument: " << variable << std::endl;
187
// Position of the detectors of interest in the beam line
188
DetectorGlobals tof1_globals(geo_file, "TOF1");
189
DetectorGlobals tof2_globals(geo_file, "TOF2");
190
DetectorGlobals tku_globals(geo_file, "Tracker0");
191
DetectorGlobals tkd_globals(geo_file, "Tracker1");
193
// Trackers alignment constants
194
double alphau(0.), betau(0.), gammau(0.), xu(0.), yu(0.);
195
double alphad(0.), betad(0.), gammad(0.), xd(0.), yd(0.);
197
// METHOD THAT DOES NOT INCLUDE THE ROLL OF THE TRACKERS
198
// Residuals distributions to fit at the centres (not roll sensitive)
199
TH2D* htku_resxy = new TH2D("tku_resxy",
200
"Residuals TKU/TOF12;"
201
"x_{u}-#xi_{12}^{u} [mm];y_{u}-#upsilon_{12}^{u} [mm]",
202
50, -250, 250, 50, -250, 250);
203
TH2D* htku_resxpyp = new TH2D("tku_resxpyp",
204
"Angular residuals TKU/TOF12;"
205
"x'_{u}-#xi'_{12} [mrad];y'_{u}-#upsilon'_{12} [mrad]",
206
50, -100, 100, 50, -100, 100);
208
TH2D* htkd_resxy = new TH2D("tkd_resxy",
209
"Residuals TKD/TOF12;"
210
"x_{d}-#xi_{12}^{d} [mm];y_{d}-#upsilon_{12}^{d} [mm]",
211
50, -250, 250, 50, -250, 250);
212
TH2D* htkd_resxpyp = new TH2D("tkd_resxpyp",
213
"Angular residuals TKD/TOF12;"
214
"x'_{d}-#xi'_{12} [mrad];y'_{d}-#upsilon'_{12} [mrad]",
215
50, -100, 100, 50, -100, 100);
217
std::vector<TH2D*> res_hists;
218
res_hists.push_back(htku_resxy);
219
res_hists.push_back(htku_resxpyp);
220
res_hists.push_back(htkd_resxy);
221
res_hists.push_back(htkd_resxpyp);
223
// METHOD THAT INCLUDES THE ROLL OF THE TRACKERS
224
// Residuals distributions as a function the position (roll sensitive)
225
TH2D* htku_resy_x = new TH2D("tku_resy_x",
226
"res_{y} vs x in TKU; x_{u} [mm]; y_{u}-#upsilon_{12}^{u} [mm]",
227
40, -200, 200, 50, -250, 250);
228
TH2D* htku_resx_y = new TH2D("tku_resx_y",
229
"res_{x} vs y in TKU; y_{u} [mm]; x_{u}-#xi_{12}^{u} [mm]",
230
40, -200, 200, 50, -250, 250);
231
TH2D* htku_resyp_xp = new TH2D("tku_resyp_xp",
232
"res_{y'} vs x' in TKU; x'_{u} [mrad]; y'_{u}-#upsilon'_{12} [mrad]",
233
25, -50, 50, 50, -100, 100);
234
TH2D* htku_resxp_yp = new TH2D("tku_resxp_yp",
235
"res_{x'} vs y' in TKU; y'_{u} [mrad]; x'_{u}-#xi'_{12} [mrad]",
236
25, -50, 50, 50, -100, 100);
238
TH2D* htkd_resy_x = new TH2D("tkd_resy_x",
239
"res_{y} vs x in TKD; x_{d} [mm]; y_{d}-#upsilon_{12}^{d} [mm]",
240
40, -200, 200, 50, -250, 250);
241
TH2D* htkd_resx_y = new TH2D("tkd_resx_y",
242
"res_{x} vs y in TKD; y_{d} [mm]; x_{d}-#xi_{12}^{d} [mm]",
243
40, -200, 200, 50, -250, 250);
244
TH2D* htkd_resyp_xp = new TH2D("tkd_resyp_xp",
245
"res_{y'} vs x' in TKD; x'_{d} [mrad]; y'_{d}-#upsilon'_{12} [mrad]",
246
25, -50, 50, 50, -100, 100);
247
TH2D* htkd_resxp_yp = new TH2D("tkd_resxp_yp",
248
"res_{x'} vs y' in TKD; y'_{d} [mrad]; x'_{d}-#xi'_{12} [mrad]",
249
25, -50, 50, 50, -100, 100);
251
std::vector<TH2D*> res_hists_roll;
252
res_hists_roll.push_back(htku_resx_y);
253
res_hists_roll.push_back(htku_resy_x);
254
res_hists_roll.push_back(htku_resxp_yp);
255
res_hists_roll.push_back(htku_resyp_xp);
256
res_hists_roll.push_back(htkd_resx_y);
257
res_hists_roll.push_back(htkd_resy_x);
258
res_hists_roll.push_back(htkd_resxp_yp);
259
res_hists_roll.push_back(htkd_resyp_xp);
261
// Iterative histograms
262
TH1D* htku_optx = new TH1D("tku_optx", "TKU optimal x;;x_{TKU}^{*} [mm]",
263
iterations, .5, iterations+.5);
264
TH1D* htku_opty = new TH1D("tku_opty", "TKU optimal y;;y_{TKU}^{*} [mm]",
265
iterations, .5, iterations+.5);
266
TH1D* htku_optalpha = new TH1D("tku_optalpha", "TKU optimal #alpha;;#alpha_{TKU}^{*} [mrad]",
267
iterations, .5, iterations+.5);
268
TH1D* htku_optbeta = new TH1D("tku_optbeta", "TKU optimal #beta;;#beta_{TKU}^{*} [mrad]",
269
iterations, .5, iterations+.5);
270
TH1D* htku_optgamma = new TH1D("tku_optgamma", "TKU optimal #gamma;;gamma_{TKU}^{*} [mrad]",
271
iterations, .5, iterations+.5);
273
TH1D* htkd_optx = new TH1D("tkd_optx", "TKD optimal x;;x_{TKD}^{*} [mm]",
274
iterations, .5, iterations+.5);
275
TH1D* htkd_opty = new TH1D("tkd_opty", "TKD optimal y;;y_{TKD}^{*} [mm]",
276
iterations, .5, iterations+.5);
277
TH1D* htkd_optalpha = new TH1D("tkd_optalpha", "TKD optimal #alpha;;#alpha_{TKD}^{*} [mrad]",
278
iterations, .5, iterations+.5);
279
TH1D* htkd_optbeta = new TH1D("tkd_optbeta", "TKD optimal #beta;;#beta_{TKD}^{*} [mrad]",
280
iterations, .5, iterations+.5);
281
TH1D* htkd_optgamma = new TH1D("tkd_optgamma", "TKD optimal #gamma;;#gamma_{TKD}^{*} [mrad]",
282
iterations, .5, iterations+.5);
284
std::vector<TH1D*> ite_hists;
285
ite_hists.push_back(htku_optx);
286
ite_hists.push_back(htku_opty);
287
ite_hists.push_back(htku_optalpha);
288
ite_hists.push_back(htku_optbeta);
289
ite_hists.push_back(htku_optgamma);
290
ite_hists.push_back(htkd_optx);
291
ite_hists.push_back(htkd_opty);
292
ite_hists.push_back(htkd_optalpha);
293
ite_hists.push_back(htkd_optbeta);
294
ite_hists.push_back(htkd_optgamma);
296
for (size_t i = 0; i < ite_hists.size(); i++)
297
ite_hists[i]->GetXaxis()->SetTitle("Iteration ID");
299
// PARTICLE IDENTIFICATION
300
double mu[2] = {0., 0.}; // Peak means
301
double sig[2] = {0., 0.}; // Peak spreads
303
// Here the muon and pion peaks are identified and fitted (for pion beams only)
305
// Number of particles to look for before trying to fit the distribution
307
const int nentries(10000);
309
std::cerr << "Fitting the time-of-flight TOF1->2 for PID (";
310
std::cerr << nentries << " entries requested)" << std::endl;
312
// Find the time taken by a particle travelling at the speed of light
313
double c = 299792458; // [m/s]
314
double s12 = tof2_globals.z()-tof1_globals.z(); // [mm]
315
double ct12 = 1e9*s12*1e-3/c; // [ns]
317
// Define a histogram that will contain the time of flight profile
318
// Bin width ~ 250 ps (5*res)
319
// Min TOF = ct12+.5 ns (a bit slower than light)
320
// Max TOF = 50 ns (70 MeV/c muons)
321
TH1F* htof12 = new TH1F("tof12", "Time-of-flight", 100, ct12+0.5, 50);
322
htof12->GetXaxis()->SetTitle("TOF_{12} [ns]");
324
for (size_t iFile = 2; iFile < (size_t)argc; iFile++) {
325
// Set up the ROOT file and data pointer
326
TFile f1(argv[iFile]); // Load the MAUS output file
327
TTree *T = (TTree*)f1.Get("Spill"); // Pull out the TTree
328
MAUS::Data *data_ptr = new MAUS::Data(); // A variable to store the Data from each spill
329
T->SetBranchAddress("data", &data_ptr); // Set the address of data_ptr
331
// Loop over the spills, get the recon events
332
for (size_t i = 0; i < (size_t)T->GetEntries(); ++i) {
334
// Update the spill pointed to by data_ptr
336
MAUS::Spill* spill = data_ptr->GetSpill();
337
if (spill == NULL || !(spill->GetDaqEventType() == "physics_event"))
339
std::vector<MAUS::ReconEvent*>* revts = spill->GetReconEvents();
341
// Loop over recon events in spill
342
for ( size_t ev = 0; ev < revts->size(); ++ev ) {
343
if ( !revts->at(ev) )
346
MAUS::TOFEvent *tofevent = revts->at(ev)->GetTOFEvent();
347
MAUS::TOFEventSpacePoint tofsp = tofevent->GetTOFEventSpacePoint();
348
std::vector<MAUS::TOFSpacePoint> tof1sps = tofsp.GetTOF1SpacePointArray();
349
std::vector<MAUS::TOFSpacePoint> tof2sps = tofsp.GetTOF2SpacePointArray();
352
if ( tof1sps.size() == 1 ) {
353
t1 = tof1sps[0].GetTime();
359
if ( tof2sps.size() == 1 ) {
360
t2 = tof2sps[0].GetTime();
365
// Display the progress in %
366
size_t j = (50*n)/(nentries-1);
367
if ( j > (size_t)(50*(n-1))/(nentries-1) || !i ) {
369
for (size_t k = 0; k < 51; k++) {
370
if ( k < j ) std::cerr << "=";
371
if ( k == j ) std::cerr << ">";
372
if ( k > j ) std::cerr << " ";
374
std::cerr << "] " << j*2;
375
if ( n != (size_t)(nentries-1) ) {
379
std::cerr << std::endl;
383
// Fill the TOF histogram and increment the count
384
htof12->Fill(t2 - t1);
394
std::cerr << "\n Not enough entries in the files to fit the TOF distributions" << std::endl;
396
// Find the peaks using the root TSpectrum code
397
const int npeaks = 2; // muons, pions
398
TSpectrum *spc = new TSpectrum(npeaks);
399
int nfound = spc->Search(htof12);
401
if ( npeaks != nfound ) {
402
std::cerr << "Wrong number of peaks found (" << nfound << "), aborting..." << std::endl;
404
float *xpeaks = spc->GetPositionX(); // array of npeaks doubles
405
std::vector<double> posx;
406
for (size_t i = 0; i < npeaks; i++)
407
posx.push_back((double)xpeaks[i]);
408
std::sort(posx.begin(), posx.end());
410
// Define a two peaks gaussian to fit to the TOF distribution
411
TF1 *fpeaks = new TF1("fpeaks",
412
"[0]*exp(-0.5*((x-[1])/[2])*((x-[1])/[2]))+"
413
"[3]*exp(-0.5*((x-[4])/[5])*((x-[4])/[5]))", 25, 50);
414
fpeaks->SetParNames("A_{#mu}","#mu_{#mu}","#sigma_{#mu}",
415
"A_{#pi}","#mu_{#pi}","#sigma_{#pi}");
417
// Set first approximation of parameters
418
for(size_t p = 0; p < npeaks; p++) {
419
int bin = htof12->GetXaxis()->FindBin(posx[p]);
420
double yp = htof12->GetBinContent(bin);
422
fpeaks->FixParameter(3*p, yp);
423
fpeaks->FixParameter(3*p+1, posx[p]);
424
fpeaks->SetParameter(3*p+2, .1);
427
// Fit peaks with the two peak gaussian and extract the parameters
428
htof12->Fit("fpeaks", "RQ");
429
for(size_t p = 0; p < npeaks; p++) {
430
mu[p] = fpeaks->GetParameter(3*p+1);
431
sig[p] = fpeaks->GetParameter(3*p+2);
434
// Now plot the histogram
435
gStyle->SetStatX(.9);
436
gStyle->SetStatY(.9);
437
gStyle->SetOptFit(1);
438
TCanvas *c = new TCanvas("tof12", "tof12", 1200, 800);
440
c->SaveAs("tof12.png");
446
// Here the offsets, pitches and yaws (and roll) of the two trackers are optimized
447
for (size_t it = 0; it < iterations; it++) {
448
std::cerr << "Iteration " << it+1 << " of the tracker alignment algorithm" << std::endl;
450
for (size_t iFile = 2; iFile < (size_t)argc; iFile++) {
451
// Set up the ROOT file and data pointer
452
TFile f1(argv[iFile]); // Load the MAUS output file
453
TTree *T = (TTree*)f1.Get("Spill"); // Pull out the TTree
454
MAUS::Data *data_ptr = new MAUS::Data(); // A variable to store the Data from each spill
455
T->SetBranchAddress("data", &data_ptr); // Set the address of data_ptr
457
// Number of spills to process
458
std::cerr << "Processing \"" << argv[iFile] << "\"" << std::endl;
460
// Loop over the spills, get the recon events
461
for (size_t i = 0; i < (size_t)T->GetEntries(); ++i) {
463
// Display the progress in %
464
size_t j = (50*i)/(T->GetEntries()-1);
465
if ( j > (size_t)(50*(i-1))/(T->GetEntries()-1) || !i ) {
467
for (size_t k = 0; k < 51; k++) {
468
if ( k < j ) std::cerr << "=";
469
if ( k == j ) std::cerr << ">";
470
if ( k > j ) std::cerr << " ";
472
std::cerr << "] " << j*2;
473
if ( i != (size_t)(T->GetEntries()-1) ) {
477
std::cerr << std::endl;
481
// Update the spill pointed to by data_ptr
483
MAUS::Spill* spill = data_ptr->GetSpill();
484
if (spill == NULL || !(spill->GetDaqEventType() == "physics_event"))
486
std::vector<MAUS::ReconEvent*>* revts = spill->GetReconEvents();
488
// Loop over recon events in spill
489
for ( size_t ev = 0; ev < revts->size(); ++ev ) {
490
if ( !revts->at(ev) )
493
//////////////////////////////
494
////// TOF1 COORDINATES //////
495
//////////////////////////////
498
MAUS::TOFEvent *tofevent = revts->at(ev)->GetTOFEvent();
499
MAUS::TOFEventSpacePoint tofsp = tofevent->GetTOFEventSpacePoint();
500
std::vector<MAUS::TOFSpacePoint> tof1sps = tofsp.GetTOF1SpacePointArray();
502
if ( tof1sps.size() == 1 ) {
503
threeve1.SetX(tof1sps[0].GetGlobalPosX());
504
threeve1.SetY(tof1sps[0].GetGlobalPosY());
505
threeve1.SetZ(tof1sps[0].GetGlobalPosZ());
506
t1 = tof1sps[0].GetTime();
512
//////////////////////////////
513
////// TOF2 COORDINATES //////
514
//////////////////////////////
517
std::vector<MAUS::TOFSpacePoint> tof2sps = tofsp.GetTOF2SpacePointArray();
519
if ( tof2sps.size() == 1 ) {
520
threeve2.SetX(tof2sps[0].GetGlobalPosX());
521
threeve2.SetY(tof2sps[0].GetGlobalPosY());
522
threeve2.SetZ(tof2sps[0].GetGlobalPosZ());
523
t2 = tof2sps[0].GetTime();
529
//////////////////////////////
530
//////// TOFs ANGLES /////////
531
//////////////////////////////
532
// Reconstruct the angles between the TOFs
533
double ax12 = (threeve2.x()-threeve1.x())/(threeve2.z()-threeve1.z());
534
double ay12 = (threeve2.y()-threeve1.y())/(threeve2.z()-threeve1.z());
537
//////////////////////////////
538
////////// TOF PID ///////////
539
//////////////////////////////
540
// Evaluate the time between TOF1 and TOF2 and use to reject electrons/positrons
541
// as they have a radically different scattering pattern from mu and pi
542
double c = 299792458; // [m/s]
543
double t12 = t2 - t1; // [ns]
544
double s12 = distance(threeve1, threeve2); // [mm]
545
double ct12 = 1e9*s12*1e-3/c; // [ns]
546
if ( t12 < ct12 + .5 ) // 5 sigma electron rejection
549
// Develop a momentum based fiducial area downstream
550
// Calculate the momentum and Lorentz beta of the particle assuming it's a muon
551
// Perform pid based on the time-of-flight if requested
553
double mmu = 105.66; // [MeV/c^2]
554
double mpi = 139.57; // [MeV/c^2]
556
if ( fabs(t12-mu[0])/sig[0] < fabs(t12-mu[1])/sig[1] ) {
565
double p12 = m/sqrt(pow(t12*1e-9*c/(s12*1e-3), 2)-1); // [MeV/c]
566
double beta12 = 1./sqrt(pow(m/p12, 2)+1);
568
// Calculate the width of the scattering distribution in angle
569
// The form factor, g(x/X0), has been studied for run 07418 and yielded 0.212
570
double th0 = 2.88/(p12*beta12); // [rad]
572
// Define the cut based on the probability to be contained in TKD
573
// The effective distance, Delta z, has been studied for run 07418 and yielded 2935.37 mm
574
double dz_eff = 2935.37; // [mm]
575
double rad_cut = 150.-2*dz_eff*th0; // 2 sigma containment
578
//////////////////////////////
579
////// TKD&U COORDINATES /////
580
//////////////////////////////
581
TVector3 threeved, threeveu;
582
double mx[2] = {-999, -999}; // Gradients of the linear fits
583
double my[2] = {-999, -999};
584
double dz_trackers = tkd_globals.z()-tku_globals.z(); // [mm]
585
double dz_tku_tof1 = tku_globals.z()-threeve1.z();
586
double dz_tkd_tof2 = tkd_globals.z()-threeve2.z();
587
double dz_ref = -549.9513; // [mm]
588
bool fiducial(false);
590
// PATTERN REGOGNITION METHOD //
591
MAUS::SciFiEvent* sfevt = revts->at(ev)->GetSciFiEvent(); // Pull out scifi event
592
MAUS::SciFiStraightPRTrackPArray sfst = sfevt->straightprtracks();
593
MAUS::SciFiTrackPArray sft = sfevt->scifitracks();
595
if ( sfst.size() != 2 )
597
for ( size_t st = 0; st < sfst.size(); ++st ) { // Loop over straight tracks
598
if ( sfst[st]->get_tracker() == 0 ) { // Upstream
600
// Fetch the local fitting parameters (given at the ref. plane)
601
threeveu.SetX(-sfst[st]->get_x0()); // x flipped
602
threeveu.SetY( sfst[st]->get_y0()); // y conserved
603
threeveu.SetZ(-dz_ref); // z flipped
604
mx[0] = sfst[st]->get_mx(); // x flipped, z flipped
605
my[0] = -sfst[st]->get_my(); // y conserved, z flipped
607
// Get the global position in the centre of TKU
608
TVector3 vtku(threeveu.x()+mx[0]*dz_ref, threeveu.y()+my[0]*dz_ref, 0);
609
vtku.RotateX(alphau*1e-3);
610
vtku.RotateY(betau*1e-3);
611
vtku.RotateZ(gammau*1e-3);
612
vtku += TVector3(xu, yu, 0);
614
// Get the global gradients of the track in TKU
615
TVector3 gtku(mx[0], my[0], 1);
616
gtku.RotateX(alphau*1e-3);
617
gtku.RotateY(betau*1e-3);
618
gtku.RotateZ(gammau*1e-3);
620
// Estimate where we expect the particle to hit the centre of TKD
621
double xp = vtku.x() + dz_trackers*gtku.x()/gtku.z();
622
double yp = vtku.y() + dz_trackers*gtku.y()/gtku.z();
624
// For the alignment, only keep the particles that do not scatter out
625
if ( sqrt(pow(xp, 2) + pow(yp, 2)) < rad_cut ) {
628
} else if ( sfst[st]->get_tracker() == 1 ) { // Downstream
630
// Fetch the local fitting parameters (given at the ref. plane)
631
threeved.SetX(sfst[st]->get_x0());
632
threeved.SetY(sfst[st]->get_y0());
633
threeved.SetZ(dz_ref);
634
mx[1] = sfst[st]->get_mx();
635
my[1] = sfst[st]->get_my();
640
//////////////////////////////
641
////// FILL HISTOGRAMS ///////
642
//////////////////////////////
646
htku_resxpyp->Fill(1000*(mx[0]-ax12), 1000*(my[0]-ay12));
647
htku_resxy->Fill(threeveu.x()+dz_ref*mx[0] - (threeve1.x()+ax12*dz_tku_tof1),
648
threeveu.y()+dz_ref*my[0] - (threeve1.y()+ay12*dz_tku_tof1));
650
htkd_resxpyp->Fill(1000*(mx[1]-ax12), 1000*(my[1]-ay12));
651
htkd_resxy->Fill(threeved.x()-dz_ref*mx[1] - (threeve2.x()+ax12*dz_tkd_tof2),
652
threeved.y()-dz_ref*my[1] - (threeve2.y()+ay12*dz_tkd_tof2));
654
htku_resx_y->Fill(threeveu.y()+dz_ref*my[0],
655
threeveu.x()+dz_ref*mx[0] - (threeve1.x()+ax12*dz_tku_tof1));
656
htku_resy_x->Fill(threeveu.x()+dz_ref*mx[0],
657
threeveu.y()+dz_ref*my[0] - (threeve1.y()+ay12*dz_tku_tof1));
658
htku_resxp_yp->Fill(1000*my[0], 1000*(mx[0]-ax12));
659
htku_resyp_xp->Fill(1000*mx[0], 1000*(my[0]-ay12));
661
htkd_resx_y->Fill(threeved.y()-dz_ref*my[1],
662
threeved.x()-dz_ref*mx[1] - (threeve2.x()+ax12*dz_tkd_tof2));
663
htkd_resy_x->Fill(threeved.x()-dz_ref*mx[1],
664
threeved.y()-dz_ref*my[1] - (threeve2.y()+ay12*dz_tkd_tof2));
665
htkd_resxp_yp->Fill(1000*my[1], 1000*(mx[1]-ax12));
666
htkd_resyp_xp->Fill(1000*mx[1], 1000*(my[1]-ay12));
669
} // End of the list of recEvents
670
} // End of the list of TTree entries
672
} // End of the list of files
675
// Fit the distributions and get the constants from the peak
676
TF2 *gausxy = new TF2("gausxy", "[0]*TMath::Gaus(x, [1], [2])*TMath::Gaus(y, [3], [4])",
677
-250, 250, -250, 250);
678
gausxy->SetParNames("A", "#mu_{x}", "#sigma_{x}", "#mu_{y}", "#sigma_{y}");
680
// Upstream tracker paramters, fit the peak
681
gausxy->SetRange(-40, 40, -40, 40);
682
gausxy->SetParameters(htku_resxy->GetMaximum(), 0, 10, 0, 10);
683
htku_resxy->Fit("gausxy", "RQ0");
684
xu = -gausxy->GetParameter(1);
685
yu = -gausxy->GetParameter(3);
686
htku_optx->SetBinContent(it+1, xu);
687
htku_opty->SetBinContent(it+1, yu);
688
htku_optx->SetBinError(it+1, gausxy->GetParError(1));
689
htku_opty->SetBinError(it+1, gausxy->GetParError(3));
691
gausxy->SetRange(-20, 20, -20, 20);
692
gausxy->SetParameters(htku_resxpyp->GetMaximum(), 0, 10, 0, 10);
693
htku_resxpyp->Fit("gausxy", "RQ0");
694
alphau = gausxy->GetParameter(3);
695
betau = -gausxy->GetParameter(1);
696
htku_optalpha->SetBinContent(it+1, alphau);
697
htku_optbeta->SetBinContent(it+1, betau);
698
htku_optalpha->SetBinError(it+1, gausxy->GetParError(3));
699
htku_optbeta->SetBinError(it+1, gausxy->GetParError(1));
701
// Downstream tracker parameters, fit the peak
702
gausxy->SetRange(-40, 40, -40, 40);
703
gausxy->SetParameters(htkd_resxy->GetMaximum(), 0, 10, 0, 10);
704
htkd_resxy->Fit("gausxy", "RQ0");
705
xd = -gausxy->GetParameter(1);
706
yd = -gausxy->GetParameter(3);
707
htkd_optx->SetBinContent(it+1, xd);
708
htkd_opty->SetBinContent(it+1, yd);
709
htkd_optx->SetBinError(it+1, gausxy->GetParError(1));
710
htkd_opty->SetBinError(it+1, gausxy->GetParError(3));
712
gausxy->SetRange(-20, 20, -20, 20);
713
gausxy->SetParameters(htkd_resxpyp->GetMaximum(), 0, 10, 0, 10);
714
htkd_resxpyp->Fit("gausxy", "RQ0");
715
alphad = gausxy->GetParameter(3);
716
betad = -gausxy->GetParameter(1);
717
htkd_optalpha->SetBinContent(it+1, alphad);
718
htkd_optbeta->SetBinContent(it+1, betad);
719
htkd_optalpha->SetBinError(it+1, gausxy->GetParError(3));
720
htkd_optbeta->SetBinError(it+1, gausxy->GetParError(1));
724
// Vectors to hold the different measurements of the roll, gamma
725
std::vector<double> gamu, gamue;
726
std::vector<double> gamd, gamde;
728
// Get the fitting parameters for the upstream tracker
729
// res_x vs y in TKU, measures -x_U and gamma_U
730
TH1D *htku_resx_y_1D = new TH1D("", "", htku_resx_y->GetNbinsX(),
731
htku_resx_y->GetXaxis()->GetXmin(),
732
htku_resx_y->GetXaxis()->GetXmax());
733
for (int k = 0; k < htku_resx_y->GetNbinsX(); k++) {
734
TH1D *hbinsy = htku_resx_y->ProjectionY(Form("bin%d",k+1), k+1, k+1);
735
double mean = hbinsy->GetMean();
736
double meanerr = hbinsy->GetMeanError();
738
htku_resx_y_1D->SetBinContent(k+1, mean);
739
htku_resx_y_1D->SetBinError(k+1, meanerr);
742
htku_resx_y_1D->Fit("pol1", "Q", "",
743
htku_resx_y->GetMean(1)-2*htku_resx_y->GetRMS(1),
744
htku_resx_y->GetMean(1)+2*htku_resx_y->GetRMS(1));
745
xu = -htku_resx_y_1D->GetFunction("pol1")->GetParameter(0);
746
htku_optx->SetBinContent(it+1, xu);
747
htku_optx->SetBinError(it+1, htku_resx_y_1D->GetFunction("pol1")->GetParError(0));
748
gamu.push_back(htku_resx_y_1D->GetFunction("pol1")->GetParameter(1));
749
gamue.push_back(htku_resx_y_1D->GetFunction("pol1")->GetParError(1));
750
delete htku_resx_y_1D;
752
// res_y vs x in TKU, measures -y_U and -gamma_U
753
TH1D *htku_resy_x_1D = new TH1D("", "", htku_resy_x->GetNbinsX(),
754
htku_resy_x->GetXaxis()->GetXmin(),
755
htku_resy_x->GetXaxis()->GetXmax());
756
for (int k = 0; k <htku_resy_x->GetNbinsX(); k++) {
757
TH1D *hbinsy = htku_resy_x->ProjectionY(Form("bin%d",k+1), k+1, k+1);
758
double mean = hbinsy->GetMean();
759
double meanerr = hbinsy->GetMeanError();
761
htku_resy_x_1D->SetBinContent(k+1, mean);
762
htku_resy_x_1D->SetBinError(k+1, meanerr);
765
htku_resy_x_1D->Fit("pol1", "Q", "",
766
htku_resy_x->GetMean(1)-2*htku_resy_x->GetRMS(1),
767
htku_resy_x->GetMean(1)+2*htku_resy_x->GetRMS(1));
768
yu = -htku_resy_x_1D->GetFunction("pol1")->GetParameter(0);
769
htku_opty->SetBinContent(it+1, yu);
770
htku_opty->SetBinError(it+1, htku_resy_x_1D->GetFunction("pol1")->GetParError(0));
771
gamu.push_back(-htku_resy_x_1D->GetFunction("pol1")->GetParameter(1));
772
gamue.push_back(htku_resy_x_1D->GetFunction("pol1")->GetParError(1));
773
delete htku_resy_x_1D;
775
// res_xp vs yp in TKU, measures -beta_U and gamma_U
776
TH1D *htku_resxp_yp_1D = new TH1D("", "", htku_resxp_yp->GetNbinsX(),
777
htku_resxp_yp->GetXaxis()->GetXmin(),
778
htku_resxp_yp->GetXaxis()->GetXmax());
779
for (int k = 0; k <htku_resxp_yp->GetNbinsX(); k++) {
780
TH1D *hbinsy = htku_resxp_yp->ProjectionY(Form("bin%d",k+1), k+1, k+1);
781
double mean = hbinsy->GetMean();
782
double meanerr = hbinsy->GetMeanError();
784
htku_resxp_yp_1D->SetBinContent(k+1, mean);
785
htku_resxp_yp_1D->SetBinError(k+1, meanerr);
788
htku_resxp_yp_1D->Fit("pol1", "Q", "",
789
htku_resxp_yp->GetMean(1)-2*htku_resxp_yp->GetRMS(1),
790
htku_resxp_yp->GetMean(1)+2*htku_resxp_yp->GetRMS(1));
791
betau = -htku_resxp_yp_1D->GetFunction("pol1")->GetParameter(0);
792
htku_optbeta->SetBinContent(it+1, betau);
793
htku_optbeta->SetBinError(it+1, htku_resxp_yp_1D->GetFunction("pol1")->GetParError(0));
794
gamu.push_back(htku_resxp_yp_1D->GetFunction("pol1")->GetParameter(1));
795
gamue.push_back(htku_resxp_yp_1D->GetFunction("pol1")->GetParError(1));
796
delete htku_resxp_yp_1D;
798
// res_yp vs xp in TKU, measures alpha_U and -gamma_U
799
TH1D *htku_resyp_xp_1D = new TH1D("", "", htku_resyp_xp->GetNbinsX(),
800
htku_resyp_xp->GetXaxis()->GetXmin(),
801
htku_resyp_xp->GetXaxis()->GetXmax());
802
for (int k = 0; k <htku_resyp_xp->GetNbinsX(); k++) {
803
TH1D *hbinsy = htku_resyp_xp->ProjectionY(Form("bin%d",k+1), k+1, k+1);
804
double mean = hbinsy->GetMean();
805
double meanerr = hbinsy->GetMeanError();
807
htku_resyp_xp_1D->SetBinContent(k+1, mean);
808
htku_resyp_xp_1D->SetBinError(k+1, meanerr);
811
htku_resyp_xp_1D->Fit("pol1", "Q", "",
812
htku_resyp_xp->GetMean(1)-2*htku_resyp_xp->GetRMS(1),
813
htku_resyp_xp->GetMean(1)+2*htku_resyp_xp->GetRMS(1));
814
alphau = htku_resyp_xp_1D->GetFunction("pol1")->GetParameter(0);
815
htku_optalpha->SetBinContent(it+1, alphau);
816
htku_optalpha->SetBinError(it+1, htku_resyp_xp_1D->GetFunction("pol1")->GetParError(0));
817
gamu.push_back(-htku_resyp_xp_1D->GetFunction("pol1")->GetParameter(1));
818
gamue.push_back(htku_resyp_xp_1D->GetFunction("pol1")->GetParError(1));
819
delete htku_resyp_xp_1D;
821
// res_x vs y in TKD, measures -x_D and gamma_D
822
TH1D *htkd_resx_y_1D = new TH1D("", "", htkd_resx_y->GetNbinsX(),
823
htkd_resx_y->GetXaxis()->GetXmin(),
824
htkd_resx_y->GetXaxis()->GetXmax());
825
for (int k = 0; k <htkd_resx_y->GetNbinsX(); k++) {
826
TH1D *hbinsy = htkd_resx_y->ProjectionY(Form("bin%d",k+1), k+1, k+1);
827
double mean = hbinsy->GetMean();
828
double meanerr = hbinsy->GetMeanError();
830
htkd_resx_y_1D->SetBinContent(k+1, mean);
831
htkd_resx_y_1D->SetBinError(k+1, meanerr);
834
htkd_resx_y_1D->Fit("pol1", "Q", "",
835
htkd_resx_y->GetMean(1)-2*htkd_resx_y->GetRMS(1),
836
htkd_resx_y->GetMean(1)+2*htkd_resx_y->GetRMS(1));
837
xd = -htkd_resx_y_1D->GetFunction("pol1")->GetParameter(0);
838
htkd_optx->SetBinContent(it+1, xd);
839
htkd_optx->SetBinError(it+1, htkd_resx_y_1D->GetFunction("pol1")->GetParError(0));
840
gamd.push_back(htkd_resx_y_1D->GetFunction("pol1")->GetParameter(1));
841
gamde.push_back(htkd_resx_y_1D->GetFunction("pol1")->GetParError(1));
842
delete htkd_resx_y_1D;
844
// res_y vs x in TKD, measures -x_D and gamma_D
845
TH1D *htkd_resy_x_1D = new TH1D("", "", htkd_resy_x->GetNbinsX(),
846
htkd_resy_x->GetXaxis()->GetXmin(),
847
htkd_resy_x->GetXaxis()->GetXmax());
848
for (int k = 0; k < htkd_resy_x->GetNbinsX(); k++) {
849
TH1D *hbinsy = htkd_resy_x->ProjectionY(Form("bin%d",k+1), k+1, k+1);
850
double mean = hbinsy->GetMean();
851
double meanerr = hbinsy->GetMeanError();
853
htkd_resy_x_1D->SetBinContent(k+1, mean);
854
htkd_resy_x_1D->SetBinError(k+1, meanerr);
857
htkd_resy_x_1D->Fit("pol1", "Q", "",
858
htkd_resy_x->GetMean(1)-2*htkd_resy_x->GetRMS(1),
859
htkd_resy_x->GetMean(1)+2*htkd_resy_x->GetRMS(1));
860
yd = -htkd_resy_x_1D->GetFunction("pol1")->GetParameter(0);
861
htkd_opty->SetBinContent(it+1, yd);
862
htkd_opty->SetBinError(it+1, htkd_resy_x_1D->GetFunction("pol1")->GetParError(0));
863
gamd.push_back(-htkd_resy_x_1D->GetFunction("pol1")->GetParameter(1));
864
gamde.push_back(htkd_resy_x_1D->GetFunction("pol1")->GetParError(1));
865
delete htkd_resy_x_1D;
867
// res_xp vs yp in TKD, measures -x_D and gamma_D
868
TH1D *htkd_resxp_yp_1D = new TH1D("", "", htkd_resxp_yp->GetNbinsX(),
869
htkd_resxp_yp->GetXaxis()->GetXmin(),
870
htkd_resxp_yp->GetXaxis()->GetXmax());
871
for (int k = 0; k < htkd_resxp_yp->GetNbinsX(); k++) {
872
TH1D *hbinsy = htkd_resxp_yp->ProjectionY(Form("bin%d",k+1), k+1, k+1);
873
double mean = hbinsy->GetMean();
874
double meanerr = hbinsy->GetMeanError();
876
htkd_resxp_yp_1D->SetBinContent(k+1, mean);
877
htkd_resxp_yp_1D->SetBinError(k+1, meanerr);
879
htkd_resxp_yp_1D->Fit("pol1", "Q", "",
880
htkd_resxp_yp->GetMean(1)-2*htkd_resxp_yp->GetRMS(1),
881
htkd_resxp_yp->GetMean(1)+2*htkd_resxp_yp->GetRMS(1));
882
betad = -htkd_resxp_yp_1D->GetFunction("pol1")->GetParameter(0);
883
htkd_optbeta->SetBinContent(it+1, betad);
884
htkd_optbeta->SetBinError(it+1, htkd_resxp_yp_1D->GetFunction("pol1")->GetParError(0));
885
gamd.push_back(htkd_resxp_yp_1D->GetFunction("pol1")->GetParameter(1));
886
gamde.push_back(htkd_resxp_yp_1D->GetFunction("pol1")->GetParError(1));
887
delete htkd_resxp_yp_1D;
889
// res_yp vs xp in TKD, measures -x_D and gamma_D
890
TH1D *htkd_resyp_xp_1D = new TH1D("", "", htkd_resyp_xp->GetNbinsX(),
891
htkd_resyp_xp->GetXaxis()->GetXmin(),
892
htkd_resyp_xp->GetXaxis()->GetXmax());
893
for (int k = 0; k < htkd_resyp_xp->GetNbinsX(); k++) {
894
TH1D *hbinsy = htkd_resyp_xp->ProjectionY(Form("bin%d",k+1), k+1, k+1);
895
double mean = hbinsy->GetMean();
896
double meanerr = hbinsy->GetMeanError();
898
htkd_resyp_xp_1D->SetBinContent(k+1, mean);
899
htkd_resyp_xp_1D->SetBinError(k+1, meanerr);
902
htkd_resyp_xp_1D->Fit("pol1", "Q", "",
903
htkd_resyp_xp->GetMean(1)-2*htkd_resyp_xp->GetRMS(1),
904
htkd_resyp_xp->GetMean(1)+2*htkd_resyp_xp->GetRMS(1));
905
alphad = htkd_resyp_xp_1D->GetFunction("pol1")->GetParameter(0);
906
htkd_optalpha->SetBinContent(it+1, alphad);
907
htkd_optalpha->SetBinError(it+1, htkd_resyp_xp_1D->GetFunction("pol1")->GetParError(0));
908
gamd.push_back(-htkd_resyp_xp_1D->GetFunction("pol1")->GetParameter(1));
909
gamde.push_back(htkd_resyp_xp_1D->GetFunction("pol1")->GetParError(1));
910
delete htkd_resyp_xp_1D;
912
// Do a weighted average to find the best fit to the roll
913
double gamu_mean(0.), gamd_mean(0.), gamu_error(0.), gamd_error(0.);
914
for (size_t sample = 0; sample < gamu.size(); sample++) {
915
gamu_mean += gamu[sample]*pow(gamue[sample], -2);
916
gamd_mean += gamd[sample]*pow(gamde[sample], -2);
918
gamu_error += pow(gamue[sample], -2);
919
gamd_error += pow(gamde[sample], -2);
922
gamu_mean /= gamu_error;
923
gamd_mean /= gamd_error;
925
gammau = 1000*gamu_mean;
926
htku_optgamma->SetBinContent(it+1, gammau);
927
htku_optgamma->SetBinError(it+1, 1000./sqrt(gamu_error));
929
gammad = 1000*gamd_mean;
930
htkd_optgamma->SetBinContent(it+1, gammad);
931
htkd_optgamma->SetBinError(it+1, 1000./sqrt(gamd_error));
934
// Scale the histograms to 0 for the next round
935
if ( it < iterations-1 ) {
939
htku_resxpyp->Reset();
940
htkd_resxpyp->Reset();
942
htku_resx_y->Reset();
943
htku_resy_x->Reset();
944
htku_resxp_yp->Reset();
945
htku_resyp_xp->Reset();
947
htkd_resx_y->Reset();
948
htkd_resy_x->Reset();
949
htkd_resxp_yp->Reset();
950
htkd_resyp_xp->Reset();
953
} // End of the fitting iterations
955
// Set the Stat box to be along the top right corner of the TPad in the TCanvas
956
gStyle->SetStatX(.9);
957
gStyle->SetStatY(.9);
959
// Labels of the fits for the plots that include the roll
960
std::vector<std::string> yint_labels;
961
yint_labels.push_back("-x_{U}");
962
yint_labels.push_back("-y_{U}");
963
yint_labels.push_back("-#beta_{U}");
964
yint_labels.push_back("#alpha_{U}");
965
yint_labels.push_back("-x_{D}");
966
yint_labels.push_back("-y_{D}");
967
yint_labels.push_back("-#beta_{D}");
968
yint_labels.push_back("#alpha_{D}");
969
std::vector<std::string> grad_labels;
970
grad_labels.push_back("#gamma_{U}");
971
grad_labels.push_back("-#gamma_{U}");
972
grad_labels.push_back("#gamma_{U}");
973
grad_labels.push_back("-#gamma_{U}");
974
grad_labels.push_back("#gamma_{D}");
975
grad_labels.push_back("-#gamma_{D}");
976
grad_labels.push_back("#gamma_{D}");
977
grad_labels.push_back("-#gamma_{D}");
979
// Plot the graphs and their fit, store them to a root file
980
std::string output_name = run_name+"_alignment.root";
981
TFile* output = new TFile(output_name.c_str(), "RECREATE");
982
for (size_t id = 0; id < res_hists.size(); id++) {
984
gStyle->SetOptFit(1);
985
TF2 *gausxy = new TF2("gausxy", "[0]*TMath::Gaus(x, [1], [2])*TMath::Gaus(y, [3], [4])",
986
-500, 500, -500, 500);
987
gausxy->SetParNames("A", "#mu_{x}", "#sigma_{x}", "#mu_{y}", "#sigma_{y}");
988
TCanvas *cd = new TCanvas("cd", "cd", 1200, 900);
989
res_hists[id]->Draw("COLZ");
990
res_hists[id]->Fit("gausxy");
991
cd->SaveAs(TString(res_hists[id]->GetName())+".png");
994
res_hists[id]->Write();
996
double minx = res_hists_roll[id]->GetXaxis()->GetXmin();
997
double maxx = res_hists_roll[id]->GetXaxis()->GetXmax();
999
TString name_1D = TString(res_hists_roll[id]->GetName())+"_1D";
1000
TH1D *res_hists_1D = new TH1D(name_1D.Data(), res_hists_roll[id]->GetTitle(),
1001
res_hists_roll[id]->GetNbinsX(), minx, maxx);
1002
res_hists_1D->GetXaxis()->SetTitle(res_hists_roll[id]->GetXaxis()->GetTitle());
1003
res_hists_1D->GetYaxis()->SetTitle(res_hists_roll[id]->GetYaxis()->GetTitle());
1005
for (int k = 0; k < res_hists[id]->GetNbinsX(); k++) {
1006
TH1D *hbinsy = res_hists[id]->ProjectionY(Form("bin%d",k+1), k+1, k+1);
1008
double mean = hbinsy->GetMean();
1009
double meanerr = hbinsy->GetMeanError();
1011
res_hists_1D->SetBinContent(k+1, mean);
1012
res_hists_1D->SetBinError(k+1, meanerr);
1015
// Draw the distributions
1016
gStyle->SetOptStat(10);
1017
gStyle->SetOptFit(1);
1018
TCanvas *cd = new TCanvas("cd", "cd", 1200, 900);
1019
res_hists_roll[id]->Draw("COLZ");
1020
cd->SaveAs(TString(res_hists_roll[id]->GetName())+".png");
1023
// Draw the mean RMS and the best fit
1024
cd = new TCanvas("cd", "cd", 1200, 900);
1025
res_hists_1D->Draw("");
1026
res_hists_1D->Fit("pol1", "Q", "",
1027
res_hists_roll[id]->GetMean(1)-2*res_hists_roll[id]->GetRMS(1),
1028
res_hists_roll[id]->GetMean(1)+2*res_hists_roll[id]->GetRMS(1));
1029
res_hists_1D->GetFunction("pol1")->SetParNames(yint_labels[id].c_str(),
1030
grad_labels[id].c_str());
1031
cd->SaveAs(name_1D+".png");
1034
res_hists_roll[id]->Write();
1035
res_hists_1D->Write();
1036
delete res_hists_1D;
1040
// Sensitivity of the fit to the initial parameters
1041
gStyle->SetOptStat(0);
1042
for (size_t id = 0; id < ite_hists.size(); id++) {
1043
double mean = ite_hists[id]->GetBinContent(iterations);
1044
double err = ite_hists[id]->GetBinError(iterations);
1045
ite_hists[id]->SetTitle(TString(ite_hists[id]->GetTitle())+
1046
TString::Format(": %1.3f +/- % 1.3f", mean, err));
1047
TCanvas *c = new TCanvas("c", "c", 1200, 900);
1048
ite_hists[id]->Draw("E");
1049
c->SaveAs(TString(ite_hists[id]->GetName())+".png");
1052
ite_hists[id]->Write();