1
/* This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus
3
* MAUS is free software: you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation, either version 3 of the License, or
6
* (at your option) any later version.
8
* MAUS is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with MAUS. If not, see <http://www.gnu.org/licenses/>.
25
#include "TVirtualPad.h"
31
#include "TRefArray.h"
35
#include "src/common_cpp/Plotting/SciFi/TrackerDataAnalyserMomentum.hh"
36
#include "src/common_cpp/DataStructure/Spill.hh"
37
#include "src/common_cpp/DataStructure/Data.hh"
38
#include "src/common_cpp/DataStructure/MCEvent.hh"
39
#include "src/common_cpp/DataStructure/ReconEvent.hh"
40
#include "src/common_cpp/DataStructure/SciFiEvent.hh"
41
#include "src/common_cpp/DataStructure/SciFiSpacePoint.hh"
42
#include "src/common_cpp/DataStructure/SciFiStraightPRTrack.hh"
43
#include "src/common_cpp/DataStructure/SciFiHelicalPRTrack.hh"
44
#include "src/common_cpp/DataStructure/ThreeVector.hh"
45
#include "src/common_cpp/Recon/SciFi/SimpleLine.hh"
46
#include "src/common_cpp/Recon/SciFi/SimpleCircle.hh"
50
TrackerDataAnalyserMomentum::TrackerDataAnalyserMomentum()
86
TrackerDataAnalyserMomentum::~TrackerDataAnalyserMomentum() {
87
if (_out_file) delete _out_file;
88
if (_tree) delete _tree;
89
if (_t1_pt_res) delete _t1_pt_res;
90
if (_t1_pz_res) delete _t1_pz_res;
91
if (_t1_pz_res_log) delete _t1_pz_res_log;
92
if (_t2_pt_res) delete _t2_pt_res;
93
if (_t2_pz_res) delete _t2_pz_res;
94
if (_t2_pz_res_log) delete _t2_pz_res_log;
95
if (_t1_pt_res_pt) delete _t1_pz_res_pt;
96
if (_t1_pz_res_pt) delete _t1_pt_res_pt;
97
if (_t2_pt_res_pt) delete _t2_pz_res_pt;
98
if (_t2_pz_res_pt) delete _t2_pt_res_pt;
99
if (_t1_pz_resol) delete _t1_pz_resol;
100
if (_t2_pz_resol) delete _t2_pz_resol;
101
if (_cResiduals) delete _cResiduals;
102
if (_cGraphs) delete _cGraphs;
103
if (_cResolutions) delete _cResolutions;
106
void TrackerDataAnalyserMomentum::setUp() {
107
// Set up the output ROOT file
108
_out_file = new TFile("momentum_analysis_output.root", "recreate");
110
// Set up the output tree
111
_tree = new TTree("tree", "Momentum Residual Data");
112
_tree->Branch("spill_num", &_spill_num, "spill_num/I");
113
_tree->Branch("tracker_num", &_tracker_num, "tracker_num/I");
114
_tree->Branch("charge", &_charge, "charge/I");
115
_tree->Branch("num_points", &_num_points, "num_points/I");
116
_tree->Branch("n_bad_tracks", &_n_bad_tracks, "n_bad_tracks/I");
117
_tree->Branch("mc_track_id", &_mc_track_id, "mc_track_id/I");
118
_tree->Branch("mc_pid", &_mc_pid, "mc_pid/I");
119
_tree->Branch("n_matched", &_n_matched, "n_matched/I");
120
_tree->Branch("n_mismatched", &_n_mismatched, "n_mismatched/I");
121
_tree->Branch("n_missed", &_n_missed, "n_missed/I");
122
_tree->Branch("pt_rec", &_pt_rec, "pt_rec/D");
123
_tree->Branch("pz_rec", &_pz_rec, "pz_rec/D");
124
_tree->Branch("pt_mc", &_pt_mc, "pt_mc/D");
125
_tree->Branch("pz_mc", &_pz_mc, "pz_mc/D");
127
// Set up the residual histograms
128
int res_n_bins = 100;
130
_t1_pt_res = new TH1D("t1_pt_res", "T1 p_{t} Residual", res_n_bins, -5, 5);
131
_t1_pt_res->GetXaxis()->SetTitle("p_{T}^{MC} - p_{T} (MeV/c)");
133
_t1_pz_res = new TH1D("t1_pz_res", "T1 p_{z} Residual", res_n_bins, -30, 30);
134
_t1_pz_res->GetXaxis()->SetTitle("p_{z}^{MC} - p_{z} (MeV/c)");
136
_t1_pz_res_log = new TH1D("t1_pz_res_log", "T1 p_{z} Residual", res_n_bins, -500, 500);
137
_t1_pz_res_log->GetXaxis()->SetTitle("p_{z}^{MC} - p_{z} (MeV/c)");
139
_t2_pt_res = new TH1D("t2_pt_res", "T2 p_{t} Residual", res_n_bins, -5, 5);
140
_t2_pt_res->GetXaxis()->SetTitle("p_{T}^{MC} - p_{T} (MeV/c)");
142
_t2_pz_res = new TH1D("t2_pz_res", "T2 p_{z} Residual", res_n_bins, -30, 30);
143
_t2_pz_res->GetXaxis()->SetTitle("p_{z}^{MC} - p_{z} (MeV/c)");
145
_t2_pz_res_log = new TH1D("t2_pz_res_log", "T2 p_{z} Residual", res_n_bins, -500, 500);
146
_t2_pz_res_log->GetXaxis()->SetTitle("p_{z}^{MC} - p_{z} (MeV/c)");
148
// Set up the residual graphs
149
_t1_pz_res_pt = new TGraph();
150
_t2_pz_res_pt = new TGraph();
153
gStyle->SetOptStat(111111);
154
gStyle->SetLabelSize(0.05, "XYZ");
155
gStyle->SetTitleOffset(1.15, "X");
156
gStyle->SetStatW(0.3);
157
gStyle->SetStatH(0.2);
160
void TrackerDataAnalyserMomentum::accumulate(Spill* spill) {
161
if (spill != NULL && spill->GetDaqEventType() == "physics_event") {
162
_spill_num = spill->GetSpillNumber();
164
// Loop over MC events in the spill
165
for (size_t iMevt = 0; iMevt < spill->GetMCEvents()->size(); ++iMevt) {
166
MCEvent *mc_evt = (*spill->GetMCEvents())[iMevt];
167
SciFiEvent *evt = (*spill->GetReconEvents())[iMevt]->GetSciFiEvent();
168
calc_pat_rec_efficiency(mc_evt, evt);
171
std::cout << "Not a usable spill" << std::endl;
175
void TrackerDataAnalyserMomentum::calc_pat_rec_efficiency(MCEvent *mc_evt, SciFiEvent* evt) {
176
std::vector<SciFiHelicalPRTrack*> htrks = evt->helicalprtracks();
178
// Create the lookup bridge between MC and Recon
180
lkup.make_hits_map(mc_evt);
182
// Reset tracks counters
185
// Loop over helical pattern recognition tracks in event
186
for (size_t iTrk = 0; iTrk < htrks.size(); ++iTrk) {
187
SciFiHelicalPRTrack* trk = htrks[iTrk];
190
if ((trk->get_R() != 0.0) & (trk->get_dsdz() != 0.0)) {
191
_num_points = trk->get_num_points();
192
std::vector< std::vector<int> > spoint_mc_tids; // Vector of MC track ids for each spoint
194
// Calc recon momentum
195
_pt_rec = 1.2 * trk->get_R();
196
_pz_rec = _pt_rec / trk->get_dsdz();
199
// Loop over seed spacepoints associated with the track
200
std::vector<SciFiSpacePoint*> spnts = trk->get_spacepoints_pointers();
201
for ( size_t k = 0; k < spnts.size(); ++k ) {
202
std::map<int, int> track_id_counter; // Map of track id to freq for each spoint
203
std::vector<SciFiCluster*> clusters = spnts[k]->get_channels_pointers();
205
// Loop over clusters
206
for ( size_t l = 0; l < clusters.size(); ++l ) {
207
std::vector<SciFiDigit*> digits = clusters[l]->get_digits_pointers();
210
for ( size_t m = 0; m < digits.size(); ++m ) {
211
// Perform the digits to hits lookup
212
std::vector<SciFiHit*> hits;
213
if (!lkup.get_hits(digits[m], hits)) {
214
std::cerr << "Lookup failed\n";
219
for ( size_t n = 0; n < hits.size(); ++n ) {
220
int track_id = hits[n]->GetTrackId();
221
if (track_id_counter.count(track_id))
222
track_id_counter[track_id] = track_id_counter[track_id] + 1;
224
track_id_counter[track_id] = 1;
225
} // ~Loop over MC hits
226
} // ~Loop over digits
227
} // ~// Loop over clusters
229
// Find the track_ids for this spacepoint
230
std::map<int, int>::iterator mit1;
231
std::vector<int> mc_tracks_ids;
232
for ( mit1 = track_id_counter.begin(); mit1 != track_id_counter.end(); ++mit1 ) {
233
mc_tracks_ids.push_back(mit1->first);
235
spoint_mc_tids.push_back(mc_tracks_ids);
236
} // ~Loop over seed spacepoints
238
// Is there a track id associated with 3 or more spoints?
241
bool success = find_mc_tid(spoint_mc_tids, track_id, counter);
242
// If we have not found a common track id, abort for this track
244
std::cerr << "Malformed track, skipping\n";
248
// If we have found a common track id amoung the spoints, fill the tree
249
_mc_track_id = track_id;
250
_n_matched = counter;
251
_n_mismatched = spoint_mc_tids.size() - counter;
252
_n_missed = 5 - counter; // TODO: improve
254
// Calc the MC track momentum using hits only with this track id
258
for ( size_t k = 0; k < spnts.size(); ++k ) {
260
bool success = find_mc_spoint_momentum(track_id, spnts[k], lkup, mom_mc);
261
if (!success) continue;
262
_pt_mc += sqrt(mom_mc.x()*mom_mc.x() + mom_mc.y()*mom_mc.y());
263
_pz_mc += mom_mc.z();
269
// Fill the vectors and tree with the extracted recon and MC momenta
270
if (trk->get_tracker() == 0) {
271
_t1_pt_res->Fill(_pt_mc - _pt_rec);
272
_t1_pz_res->Fill(_pz_mc + trk->get_charge()*_pz_rec);
273
_t1_pz_res_log->Fill(_pz_mc + trk->get_charge()*_pz_rec);
274
_vec_t1_pt_mc.push_back(_pt_mc);
275
_vec_t1_pt_res.push_back(_pt_mc - _pt_rec);
276
_vec_t1_pz.push_back(_pz_rec);
277
_vec_t1_pz_res.push_back(_pz_mc + trk->get_charge()*_pz_rec);
278
} else if (trk->get_tracker() == 1) {
279
_t2_pt_res->Fill(_pt_mc - _pt_rec);
280
_t2_pz_res->Fill(_pz_mc - trk->get_charge()*_pz_rec);
281
_t2_pz_res_log->Fill(_pz_mc - trk->get_charge()*_pz_rec);
282
_vec_t2_ptMc.push_back(_pt_mc);
283
_vec_t2_pt_res.push_back(_pt_mc - _pt_rec);
284
_vec_t2_pz.push_back(_pz_rec);
285
_vec_t2_pz_res.push_back(_pz_mc - trk->get_charge()*_pz_rec);
287
_tracker_num = trk->get_tracker();
288
_charge = trk->get_charge();
291
std::cout << "Bad track, skipping" << std::endl;
296
bool TrackerDataAnalyserMomentum::find_mc_spoint_momentum(const int track_id,
297
const SciFiSpacePoint* sp, SciFiLookup &lkup, ThreeVector &mom) {
299
std::vector<SciFiCluster*> clusters = sp->get_channels_pointers();
300
std::vector<SciFiCluster*>::iterator clus_it;
301
for (clus_it = clusters.begin(); clus_it != clusters.end(); ++clus_it) {
302
std::vector<SciFiDigit*> digits = (*clus_it)->get_digits_pointers();
303
std::vector<SciFiDigit*>::iterator dig_it;
304
for (dig_it = digits.begin(); dig_it != digits.end(); ++dig_it) {
305
std::vector<SciFiHit*> hits;
306
if (!lkup.get_hits((*dig_it), hits)) {
307
std::cerr << "Lookup failed\n";
310
std::vector<SciFiHit*>::iterator hit_it;
311
for (hit_it = hits.begin(); hit_it != hits.end(); ++hit_it) {
312
if (track_id == (*hit_it)->GetTrackId()) {
313
mom = (*hit_it)->GetMomentum();
322
bool TrackerDataAnalyserMomentum::find_mc_tid(const std::vector< std::vector<int> > &spoint_mc_tids,
323
int &tid, int &counter) {
325
std::map<int, int> track_id_counter; // Map of track id to freq for each spoint
327
for ( size_t i = 0; i < spoint_mc_tids.size(); ++i ) {
328
for ( size_t j = 0; j < spoint_mc_tids[i].size(); ++j ) {
329
int current_tid = spoint_mc_tids[i][j];
330
if (track_id_counter.count(current_tid))
331
track_id_counter[current_tid] = track_id_counter[current_tid] + 1;
333
track_id_counter[current_tid] = 1;
337
std::map<int, int>::iterator mit1;
339
for ( mit1 = track_id_counter.begin(); mit1 != track_id_counter.end(); ++mit1 ) {
340
if ( mit1->second > 2 && tid == 0 ) {
342
counter = mit1->second;
343
} else if ( mit1->second > 2 && tid != 0 ) {
344
tid = -1; // A malformed track, cannot asscoiate with an mc track id
352
void TrackerDataAnalyserMomentum::make_all() {
353
make_residual_histograms();
354
make_residual_graphs();
355
make_pz_resolutions();
356
make_resolution_graphs();
359
void TrackerDataAnalyserMomentum::make_pz_resolutions() {
360
int nPoints = 9; // The number of MC momentum intervals used in the plots
361
std::vector<TCut> vCuts(nPoints); // The cuts defining the pt_mc intervals
362
std::vector<double> vPtMc(nPoints); // The centre of the pt_mc intervals
363
std::vector<double> vPtMcErr(nPoints); // The width of the intervals
364
std::vector<double> vPzRes_t1(nPoints); // The resulatant pz resolutions
365
std::vector<double> vPzResErr_t1(nPoints); // The errors assocaited with the pz res
366
std::vector<double> vPzRes_t2(nPoints); // The resulatant pz resolutions
367
std::vector<double> vPzResErr_t2(nPoints); // The errors assocaited with the pz res
370
vCuts[0] = "pt_mc>=0&&pt_mc<10";
371
vCuts[1] = "pt_mc>=10&&pt_mc<20";
372
vCuts[2] = "pt_mc>=20&&pt_mc<30";
373
vCuts[3] = "pt_mc>=30&&pt_mc<40";
374
vCuts[4] = "pt_mc>=40&&pt_mc<50";
375
vCuts[5] = "pt_mc>=50&&pt_mc<60";
376
vCuts[6] = "pt_mc>=60&&pt_mc<70";
377
vCuts[7] = "pt_mc>=70&&pt_mc<80";
378
vCuts[8] = "pt_mc>=80&&pt_mc<90";
379
// vCuts[9] = "pt_mc>=90&&pt_mc<100";
381
// The central MC momentum
393
// The error associated with the MC momentum (just the interval half width)
403
// vPtMcErr[9] = 5.0;
405
// Cuts for to select each tracker
406
TCut cutT1 = "tracker_num==0";
407
TCut cutT2 = "tracker_num==1";
409
// Form the reconstructed pz TCut
410
TCut tcut_pzrec = formTCut("TMath::Abs(pz_rec)", "<", _cutPzRec);
412
// Loop over the mometum intervals and calculate the resolution for each
413
for (int i = 0; i < nPoints; ++i) {
414
TCut input_cut = vCuts[i]&&cutT1&&tcut_pzrec;
415
calc_pz_resolution(0, input_cut, vPzRes_t1[i], vPzResErr_t1[i]);
417
for (int i = 0; i < nPoints; ++i) {
418
TCut input_cut = vCuts[i]&&cutT2&&tcut_pzrec;
419
calc_pz_resolution(1, input_cut, vPzRes_t2[i], vPzResErr_t2[i]);
422
// Create the resultant resolution plots
423
_t1_pz_resol = new TGraphErrors(nPoints, &vPtMc[0], &vPzRes_t1[0],
424
&vPtMcErr[0], &vPzResErr_t1[0]);
425
_t2_pz_resol = new TGraphErrors(nPoints, &vPtMc[0], &vPzRes_t2[0],
426
&vPtMcErr[0], &vPzResErr_t2[0]);
429
void TrackerDataAnalyserMomentum::make_residual_histograms() {
430
_cResiduals = new TCanvas("cResiduals", "Mometum Residuals");
431
_cResiduals->Divide(3, 2);
433
_t1_pt_res->UseCurrentStyle();
436
_t1_pz_res->UseCurrentStyle();
438
TVirtualPad* pad = _cResiduals->cd(3);
440
_t1_pz_res_log->UseCurrentStyle();
441
_t1_pz_res_log->Draw();
443
_t2_pt_res->UseCurrentStyle();
446
_t2_pz_res->UseCurrentStyle();
448
pad = _cResiduals->cd(6);
450
_t2_pz_res_log->UseCurrentStyle();
451
_t2_pz_res_log->Draw();
454
void TrackerDataAnalyserMomentum::make_residual_graphs() {
455
_cGraphs = new TCanvas("cGraphs", "Mometum Graphs");
456
_cGraphs->Divide(2, 2);
459
_t1_pt_res_pt = new TGraph(_vec_t1_pt_mc.size(), &_vec_t1_pt_mc[0], &_vec_t1_pt_res[0]);
460
_t1_pt_res_pt->SetName("t1_pt_res_pt");
461
_t1_pt_res_pt->SetTitle("T1 p_{t} res vs. p_{t}^{MC}");
462
_t1_pt_res_pt->GetXaxis()->SetTitle("p_{t}^{MC} (MeV/c)");
463
_t1_pt_res_pt->GetYaxis()->SetTitle("p_{t}^{MC} - p_{t} (MeV/c)");
464
_t1_pt_res_pt->GetYaxis()->SetTitleOffset(1.4);
465
_t1_pt_res_pt->Draw("AP");
468
_t1_pz_res_pt = new TGraph(_vec_t1_pt_mc.size(), &_vec_t1_pt_mc[0], &_vec_t1_pz_res[0]);
469
_t1_pz_res_pt->SetName("t1_pz_res_pt");
470
_t1_pz_res_pt->SetTitle("T1 p_{z} res vs. p_{t}^{MC}");
471
_t1_pz_res_pt->GetXaxis()->SetTitle("p_{t}^{MC} (MeV/c)");
472
_t1_pz_res_pt->GetYaxis()->SetTitle("p_{z}^{MC} - p_{z} (MeV/c)");
473
_t1_pz_res_pt->GetYaxis()->SetTitleOffset(1.4);
474
_t1_pz_res_pt->GetYaxis()->SetRangeUser(-200, 200);
475
_t1_pz_res_pt->Draw("AP");
478
_t2_pt_res_pt = new TGraph(_vec_t2_ptMc.size(), &_vec_t2_ptMc[0], &_vec_t2_pt_res[0]);
479
_t2_pt_res_pt->SetName("t2_pt_res_pt");
480
_t2_pt_res_pt->SetTitle("T2 p_{t} res vs. p_{t}^{MC}");
481
_t2_pt_res_pt->GetXaxis()->SetTitle("p_{t}^{MC} (MeV/c)");
482
_t2_pt_res_pt->GetYaxis()->SetTitle("p_{t}^{MC} - p_{t} (MeV/c)");
483
_t2_pt_res_pt->GetYaxis()->SetTitleOffset(1.4);
484
_t2_pt_res_pt->Draw("AP");
487
_t2_pz_res_pt = new TGraph(_vec_t2_ptMc.size(), &_vec_t2_ptMc[0], &_vec_t2_pz_res[0]);
488
_t2_pz_res_pt->SetName("t2_pz_res_pt");
489
_t2_pz_res_pt->SetTitle("T2 p_{z} res vs. p_{t}^{MC}");
490
_t2_pz_res_pt->GetXaxis()->SetTitle("p_{t}^{MC} (MeV/c)");
491
_t2_pz_res_pt->GetYaxis()->SetTitle("p_{z}^{MC} - p_{z} (MeV/c)");
492
_t2_pz_res_pt->GetYaxis()->SetTitleOffset(1.4);
493
_t2_pz_res_pt->GetYaxis()->SetRangeUser(-200, 200);
494
_t2_pz_res_pt->Draw("AP");
497
void TrackerDataAnalyserMomentum::make_resolution_graphs() {
498
_cResolutions = new TCanvas("cResolutions", "Mometum Resolution Graphs");
499
_cResolutions->Divide(2);
501
_cResolutions->cd(1);
502
_t1_pz_resol->SetName("t1_pz_resol");
503
_t1_pz_resol->SetTitle("T1 p_{z} Resolution");
504
_t1_pz_resol->GetXaxis()->SetTitle("p_{t}^{MC} (MeV/c)");
505
_t1_pz_resol->GetYaxis()->SetTitle("p_{z} Resolution (MeV/c)");
506
_t1_pz_resol->Draw("AP");
508
_cResolutions->cd(2);
509
_t2_pz_resol->SetName("t2_pz_resol");
510
_t2_pz_resol->SetTitle("T2 p_{z} Resolution");
511
_t2_pz_resol->GetXaxis()->SetTitle("p_{t}^{MC} (MeV/c)");
512
_t2_pz_resol->GetYaxis()->SetTitle("p_{z} Resolution (MeV/c)");
513
_t2_pz_resol->Draw("AP");
516
void TrackerDataAnalyserMomentum::calc_pz_resolution(const int trker, const TCut cut,
517
double &res, double &res_err) {
520
// Create a histogram of the pz residual for the pt_mc interval defined by the input cut
522
_tree->Draw("pz_mc+charge*pz_rec>>h1", cut);
523
} else if (trker == 1) {
524
_tree->Draw("pz_mc-charge*pz_rec>>h1", cut);
526
// Pull the histogram from the current pad
527
TH1 *h1 = reinterpret_cast<TH1*>(gPad->GetPrimitive("h1"));
528
// Fit a gaussian to the histogram
530
TF1 *fit1 = h1->GetFunction("gaus");
531
// Extract the sigma of the gaussian fit (equivalent to the pz resolution for this interval)
532
res = fit1->GetParameter(2);
533
res_err = fit1->GetParError(2);
534
// Scale gets messed up unless histogram is deleted each time
537
std::cerr << "Tree pointer invalid" << std::endl;
541
bool TrackerDataAnalyserMomentum::save_graphics(std::string save_type) {
542
if ( (save_type == "eps") || (save_type == "pdf") || (save_type == "png") ) {
544
std::string save_name = "mom_res_histos.";
545
save_name += save_type;
546
_cResiduals->Print(save_name.c_str());
549
std::string save_name = "mom_residual_graphs.";
550
save_name += save_type;
551
_cGraphs->Print(save_name.c_str());
554
std::string save_name = "mom_resolution_graphs.";
555
save_name += save_type;
556
_cResolutions->Print(save_name.c_str());
564
void TrackerDataAnalyserMomentum::save_root() {
567
if (_tree) _tree->Write();
569
if (_t1_pt_res) _t1_pt_res->Write();
570
if (_t1_pz_res) _t1_pz_res->Write();
571
if (_t1_pz_res_log) _t1_pz_res_log->Write();
572
if (_t1_pt_res_pt) _t1_pt_res_pt->Write();
573
if (_t1_pz_res_pt) _t1_pz_res_pt->Write();
575
if (_t2_pt_res) _t2_pt_res->Write();
576
if (_t2_pz_res) _t2_pz_res->Write();
577
if (_t2_pz_res_log) _t2_pz_res_log->Write();
578
if (_t2_pt_res_pt) _t2_pt_res_pt->Write();
579
if (_t2_pz_res_pt) _t2_pz_res_pt->Write();
581
if (_t1_pz_resol) _t1_pz_resol->Write();
582
if (_t2_pz_resol) _t2_pz_resol->Write();
584
if (_cResiduals) _cResiduals->Write();
585
if (_cGraphs) _cGraphs->Write();
586
if (_cResolutions) _cResolutions->Write();
591
std::cerr << "Invalid ROOT file pointer provided" << std::endl;
595
TCut TrackerDataAnalyserMomentum::formTCut(const std::string &var, const std::string &op,
598
std::stringstream ss1;
600
ss1 << var << op << value;