ATLAS Offline Software
Loading...
Searching...
No Matches
RtCalibrationAnalytic.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <TString.h> // for Form
8
10#include "CLHEP/GenericFunctions/CumulativeChiSquare.hh"
11#include "GaudiKernel/MsgStream.h"
26#include "TGraphErrors.h"
27#include "cmath"
28#include "sstream"
29
30using namespace MuonCalib;
31
32//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
33//:: IMPLEMENTATION OF METHODS DEFINED IN THE CLASS RtCalibrationAnalytic ::
34//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
35
36//*****************************************************************************
37
39 init(0.5 * CLHEP::mm, 1, 5, true, true, true, true, 100, false, false);
40}
41
42RtCalibrationAnalytic::RtCalibrationAnalytic(const std::string &name, const double rt_accuracy, const unsigned int &func_type,
43 const unsigned int &ord, const bool &split, const bool &full_matrix, const bool &fix_min,
44 const bool &fix_max, const int &max_it, bool do_smoothing, bool do_parabolic_extrapolation) :
45 IMdtCalibration(name), m_rt(nullptr) {
46 init(rt_accuracy, func_type, ord, split, full_matrix, fix_min, fix_max, max_it, do_smoothing, do_parabolic_extrapolation);
47}
48
52
53//:::::::::::::::::
54//:: METHOD init ::
55//:::::::::::::::::
56void RtCalibrationAnalytic::init(const double rt_accuracy, const unsigned int &func_type, const unsigned int &ord, const bool &split,
57 const bool &full_matrix, const bool &fix_min, const bool &fix_max, const int &max_it, bool do_smoothing,
58 bool do_parabolic_extrapolation) {
60 // RESET PRIVATE VARIABLES //
62 m_r_max = 15.0 * CLHEP::mm;
64 m_tfile = nullptr;
65 m_cut_evolution = nullptr;
66 m_nb_segment_hits = nullptr;
67 m_CL = nullptr;
68 m_residuals = nullptr;
70 m_full_matrix = full_matrix;
71 m_nb_segments = 0;
73 m_iteration = 0;
74 m_multilayer[0] = false;
75 m_multilayer[1] = false;
76 m_status = 0;
77 m_rt_accuracy = std::abs(rt_accuracy);
79 m_chi2_previous = 1.0e99; // large value to force at least two rounds
80 m_chi2 = 0.0;
81 m_order = ord;
82 m_fix_min = fix_min;
83 m_fix_max = fix_max;
84 m_max_it = std::abs(max_it);
85
86 if (m_order == 0) {
87 throw std::runtime_error(
88 Form("File: %s, Line: %d\nRtCalibrationAnalytic::init - Order of the correction polynomial must be >0!", __FILE__, __LINE__));
89 }
90
91 m_t_length = 1000.0;
92 m_t_mean = 500.0;
93 // default values, correct values will be set when the input r-t
94 // has been given
95
96 m_U = std::vector<CLHEP::HepVector>(m_order);
97 m_A = CLHEP::HepSymMatrix(m_order, 0);
98 m_b = CLHEP::HepVector(m_order, 0);
99 m_alpha = CLHEP::HepVector(m_order, 0);
100
101 // correction function
102 if (func_type < 1 || func_type > 3) {
103 m_base_function = nullptr;
104 throw std::runtime_error(
105 Form("File: %s, Line: %d\nRtCalibrationAnalytic::init - Illegal correction function type!", __FILE__, __LINE__));
106 }
107 switch (func_type) {
108 case 1: m_base_function = std::make_unique<LegendrePolynomial>(); break;
109 case 2: m_base_function = std::make_unique<ChebyshevPolynomial>(); break;
110 case 3:
111 if (m_order < 2) {
112 throw std::runtime_error(
113 Form("File: %s, Line: %d\nRtCalibrationAnalytic::init - Order must be >2 for polygons! It is set to %i by the user.",
114 __FILE__, __LINE__, m_order));
115 }
116 std::vector<double> x(m_order);
117 double bin_width = 2.0 / static_cast<double>(m_order - 1);
118 for (unsigned int k = 0; k < m_order; k++) { x[k] = -1 + k * bin_width; }
119 m_base_function = std::make_unique<PolygonBase>(x);
120 break;
121 }
122
123 // request a chi^2 refit after the quasianalytic pattern recognition //
124 m_tracker.switchOnRefit();
125
126 // monotony of r(t) //
127 m_force_monotony = false;
128
129 // smoothing //
130 m_do_smoothing = do_smoothing;
131
132 // parabolic extrapolation //
133 m_do_parabolic_extrapolation = do_parabolic_extrapolation;
134
135 return;
136}
137
138//*****************************************************************************
139
140//:::::::::::::::::::::
141//:: METHOD t_from_r ::
142//:::::::::::::::::::::
143double RtCalibrationAnalytic::t_from_r(const double r) {
145 // VARIABLES //
147 double precision(0.001); // spatial precision of the inversion
148 double t_max(0.5 * (m_t_length + 2.0 * m_t_mean)); // upper time search limit
149 double t_min(t_max - m_t_length); // lower time search limit
150
152 // SEARCH FOR THE CORRESPONDING DRIFT TIME //
154 while (t_max - t_min > 0.1 && std::abs(m_rt->radius(0.5 * (t_min + t_max)) - r) > precision) {
155 if (m_rt->radius(0.5 * (t_min + t_max)) > r) {
156 t_max = 0.5 * (t_min + t_max);
157 } else {
158 t_min = 0.5 * (t_min + t_max);
159 }
160 }
161
162 return 0.5 * (t_min + t_max);
163}
164
165//*****************************************************************************
166
168// METHOD display_segment //
170void RtCalibrationAnalytic::display_segment(MuonCalibSegment *segment, std::ofstream &outfile) {
172 // VARIABLES //
174 double y_min, y_max, z_min, z_max; // minimum and maximum y and z coordinates
175 Amg::Vector3D null(0.0, 0.0, 0.0); // auxiliary null vector
176
178 // DISPLAY THE SEGMENT //
180
181 // minimum and maximum coordinates //
182 y_min = (segment->mdtHOT()[0])->localPosition().y();
183 y_max = y_min;
184 z_min = (segment->mdtHOT()[0])->localPosition().z();
185 z_max = z_min;
186 for (unsigned int k = 1; k < segment->mdtHitsOnTrack(); k++) {
187 if ((segment->mdtHOT()[k])->localPosition().y() < y_min) { y_min = (segment->mdtHOT()[k])->localPosition().y(); }
188 if ((segment->mdtHOT()[k])->localPosition().y() > y_max) { y_max = (segment->mdtHOT()[k])->localPosition().y(); }
189 if ((segment->mdtHOT()[k])->localPosition().z() < z_min) { z_min = (segment->mdtHOT()[k])->localPosition().z(); }
190 if ((segment->mdtHOT()[k])->localPosition().z() > z_max) { z_max = (segment->mdtHOT()[k])->localPosition().z(); }
191 }
192 for (unsigned int k = 0; k < segment->mdtCloseHits(); k++) {
193 if ((segment->mdtClose()[k])->localPosition().y() < y_min) { y_min = (segment->mdtClose()[k])->localPosition().y(); }
194 if ((segment->mdtClose()[k])->localPosition().y() > y_max) { y_max = (segment->mdtClose()[k])->localPosition().y(); }
195 if ((segment->mdtClose()[k])->localPosition().z() < z_min) { z_min = (segment->mdtClose()[k])->localPosition().z(); }
196 if ((segment->mdtClose()[k])->localPosition().z() > z_max) { z_max = (segment->mdtClose()[k])->localPosition().z(); }
197 }
198
199 // write out the coordinate system //
200 if (y_max - y_min > z_max - z_min) {
201 outfile << "nullptr " << y_min - 30.0 << " " << y_max + 30.0 << " " << 0.5 * (z_min + z_max) - 0.5 * (y_max - y_min) - 30.0 << " "
202 << 0.5 * (z_min + z_max) + 0.5 * (y_max - y_min) + 30.0 << "\n";
203 } else {
204 outfile << "nullptr " << 0.5 * (y_min + y_max) - 0.5 * (z_max - z_min) - 30.0 << " "
205 << 0.5 * (y_min + y_max) + 0.5 * (z_max - z_min) + 30.0 << " " << z_min - 30.0 << " " << z_max + 30.0 << "\n";
206 }
207
208 // write out the hits on track //
209 for (unsigned int k = 0; k < segment->mdtHitsOnTrack(); k++) {
210 // draw a circle for the tube //
211 outfile << "SET PLCI 1\n"
212 << "ARC " << (segment->mdtHOT()[k])->localPosition().y() << " " << (segment->mdtHOT()[k])->localPosition().z() << " 15.0\n";
213
214 // draw a drift circle //
215 outfile << "SET PLCI 3\n"
216 << "ARC " << (segment->mdtHOT()[k])->localPosition().y() << " " << (segment->mdtHOT()[k])->localPosition().z() << " "
217 << (segment->mdtHOT()[k])->driftRadius() << "\n";
218 }
219
220 // write out the close hits //
221 for (unsigned int k = 0; k < segment->mdtCloseHits(); k++) {
222 // draw a circle for the tube //
223 outfile << "SET PLCI 1\n"
224 << "ARC " << (segment->mdtClose()[k])->localPosition().y() << " " << (segment->mdtClose()[k])->localPosition().z()
225 << " 15.0\n";
226
227 // draw a drift circle //
228 outfile << "SET PLCI 2\n"
229 << "ARC " << (segment->mdtClose()[k])->localPosition().y() << " " << (segment->mdtClose()[k])->localPosition().z() << " "
230 << (segment->mdtClose()[k])->driftRadius() << "\n";
231 }
232
233 // write out the reconstructed track //
234 MTStraightLine aux_track(segment->position(), segment->direction(), null, null);
235 outfile << "SET PLCI 4\n"
236 << "LINE " << aux_track.a_x2() * (z_min - 30.0) + aux_track.b_x2() << " " << z_min - 30.0 << " "
237 << aux_track.a_x2() * (z_max + 30.0) + aux_track.b_x2() << " " << z_max + 30.0 << "\n";
238
239 // add a wait statement //
240 outfile << "WAIT\n";
241
242 return;
243}
244
245//*****************************************************************************
246
247//::::::::::::::::::::::::
248//:: METHOD reliability ::
249//::::::::::::::::::::::::
251
252//*****************************************************************************
253
254//::::::::::::::::::::::::::::::::
255//:: METHOD estimatedRtAccuracy ::
256//::::::::::::::::::::::::::::::::
258
259//*****************************************************************************
260
261//:::::::::::::::::::::::::::::
262//:: METHOD numberOfSegments ::
263//:::::::::::::::::::::::::::::
265
266//*****************************************************************************
267
268//:::::::::::::::::::::::::::::::::
269//:: METHOD numberOfSegmentsUsed ::
270//:::::::::::::::::::::::::::::::::
272
273//*****************************************************************************
274
275//::::::::::::::::::::::
276//:: METHOD iteration ::
277//::::::::::::::::::::::
279
280//*****************************************************************************
281
282//:::::::::::::::::::::::::::::::::
283//:: METHOD splitIntoMultilayers ::
284//:::::::::::::::::::::::::::::::::
286
287//*****************************************************************************
288
289//:::::::::::::::::::::::
290//:: METHOD fullMatrix ::
291//:::::::::::::::::::::::
293
294//*****************************************************************************
295
296//:::::::::::::::::::::::
297//:: METHOD smoothing ::
298//:::::::::::::::::::::::
300
301//*****************************************************************************
302
303//:::::::::::::::::::::::::::::::::::::::::
304//:: METHOD switch_on_control_histograms ::
305//:::::::::::::::::::::::::::::::::::::::::
306void RtCalibrationAnalytic::switch_on_control_histograms(const std::string &file_name) {
308 // CREATE THE ROOT FILE AND THE HISTOGRAMS //
311
312 m_tfile = std::make_unique<TFile>(file_name.c_str(), "RECREATE");
313
314 m_cut_evolution = std::make_unique<TH1F>("m_cut_evolution", "CUT EVOLUTION", 11, -0.5, 10.5);
315
316 m_nb_segment_hits = std::make_unique<TH1F>("m_nb_segment_hits", "NUMBER OF HITS ON THE REFITTED SEGMENTS", 11, -0.5, 10.5);
317
318 m_CL = std::make_unique<TH1F>("m_CL", "CONFIDENCE LEVELS OF THE REFITTED SEGMENTS", 100, 0.0, 1.0);
319
320 m_residuals = std::make_unique<TH2F>("m_residuals", "RESIDUALS OF THE REFITTED SEGMENTS", 100, -0.5, 15.0, 300, -1.5, 1.5);
321}
323 m_control_histograms = false;
324 if (m_tfile) {
325 m_tfile->Write();
326 m_tfile.reset();
327 }
328}
329
336void RtCalibrationAnalytic::setEstimateRtAccuracy(const double acc) { m_rt_accuracy = std::abs(acc); }
337void RtCalibrationAnalytic::splitIntoMultilayers(const bool &yes_or_no) { m_split_into_ml = yes_or_no; }
338void RtCalibrationAnalytic::fullMatrix(const bool &yes_or_no) { m_full_matrix = yes_or_no; }
340 std::shared_ptr<const IRtRelation> tmp_rt;
341 std::shared_ptr<const IRtRelation> conv_rt;
342
344 // AUTOCALIBRATION LOOP //
346 while (!converged()) {
347 for (const auto & k : seg) { handleSegment(*k); }
348 if (!analyse()) {
349 MsgStream log(Athena::getMessageSvc(), "RtCalibrationAnalytic");
350 log << MSG::WARNING << "analyseSegments() - analyse failed, segments:" << endmsg;
351 for (unsigned int i = 0; i < seg.size(); i++) {
352 log << MSG::WARNING << i << " " << seg[i]->direction() << " " << seg[i]->position() << endmsg;
353 }
354 return nullptr;
355 }
356
357 const RtCalibrationOutput *rtOut = m_output.get();
358
359 if (!converged()) { setInput(rtOut); }
360 tmp_rt = rtOut->rt();
361
362 std::vector<double> params;
363 params.push_back(tmp_rt->tLower());
364 params.push_back(0.01 * (tmp_rt->tUpper() - tmp_rt->tLower()));
365 for (double t = tmp_rt->tLower(); t <= tmp_rt->tUpper(); t = t + params[1]) { params.push_back(tmp_rt->radius(t)); }
366 conv_rt = std::make_shared<RtRelationLookUp>(params);
367 }
368
369 // parabolic extrapolations for small radii //
371 std::shared_ptr<const RtRelationLookUp> tmprt = performParabolicExtrapolation(true, true, *tmp_rt);
372 m_output = std::make_shared<RtCalibrationOutput>(
373 tmprt, std::make_shared<RtFullInfo>("RtCalibrationAnalyticExt", m_iteration, m_nb_segments_used, 0.0, 0.0, 0.0, 0.0));
374 tmp_rt = tmprt;
375 }
376
378 // SMOOTHING AFTER CONVERGENCE IF REQUESTED //
380 if (!m_do_smoothing) { return getResults(); }
381
382 // maximum number of iterations //
383 int max_smoothing_iterations(static_cast<int>(m_max_it));
384 if (max_smoothing_iterations == 0) { max_smoothing_iterations = 1; }
385
386 // convergence RMS //
387 double convergence_RMS(0.002);
388
389 // variables //
390 int it(0); // iteration
391 double RMS(1.0); // RMS change of r(t)
392
393 // smoothing //
394 //---------------------------------------------------------------------------//
395 //---------------------------------------------------------------------------//
396 while (it < max_smoothing_iterations && RMS > convergence_RMS) {
397 //---------------------------------------------------------------------------//
399
400 // counter //
401 unsigned int counter(0);
402
403 // overwrite drift radii and calculate the average resolution //
404 for (const auto & k : seg) {
405 if (k->mdtHitsOnTrack() < 3) { continue; }
406 double avres(0.0);
407 for (unsigned int h = 0; h < k->mdtHitsOnTrack(); h++) {
408 k->mdtHOT()[h]->setDriftRadius(tmp_rt->radius(k->mdtHOT()[h]->driftTime()),
409 k->mdtHOT()[h]->sigmaDriftRadius());
410 if (k->mdtHOT()[h]->sigmaDriftRadius() < 0.5 * m_r_max) {
411 avres = avres + k->mdtHOT()[h]->sigma2DriftRadius();
412 } else {
413 avres = avres + 0.1;
414 }
415 }
416 avres = avres / static_cast<double>(k->mdtHitsOnTrack());
417 avres = std::sqrt(avres);
418 if (k->mdtHitsOnTrack() > 3) {
419 if (smoothing.addResidualsFromSegment(*k, true, 7.0 * avres)) { counter++; }
420 } else {
421 if (smoothing.addResidualsFromSegment(*k, false, 7.0 * avres)) { counter++; }
422 }
423 }
424
425 // break, do no smoothing if there are not enough segments //
426 if (counter < 1000) {
427 MsgStream log(Athena::getMessageSvc(), "RtCalibrationAnalytic");
428 log << MSG::WARNING << "analyseSegments() - no smoothing applied due to too small number of reconstructed segments" << endmsg;
429 return getResults();
430 }
431
432 // smoothing //
433 RtRelationLookUp smooth_rt(smoothing.performSmoothing(*tmp_rt, m_fix_min, m_fix_max));
434
435 // calculate RMS change //
436 RMS = 0.0;
437 double bin_width(0.01 * (smooth_rt.tUpper() - smooth_rt.tLower()));
438 for (double t = smooth_rt.tLower(); t <= smooth_rt.tUpper(); t = t + bin_width) {
439 RMS = RMS + std::pow(smooth_rt.radius(t) - tmp_rt->radius(t), 2);
440 }
441 RMS = std::sqrt(0.01 * RMS);
442
443 // increase the iterations counter //
444 it++;
445
446 // delete tmp_rt and update it //
447 tmp_rt = std::make_shared<RtRelationLookUp>(smooth_rt);
448
449 //---------------------------------------------------------------------------//
450 }
451 //---------------------------------------------------------------------------//
452 //---------------------------------------------------------------------------//
453
454 m_output = std::make_shared<RtCalibrationOutput>(
455 tmp_rt, std::make_shared<RtFullInfo>("RtCalibrationAnalytic", m_iteration, m_nb_segments_used, 0.0, 0.0, 0.0, 0.0));
456
458 // RETURN THE RESULT AFTER CONVERGENCE //
460 return getResults();
461}
462
463//*****************************************************************************
464
465//::::::::::::::::::::::::::
466//:: METHOD handleSegment ::
467//::::::::::::::::::::::::::
470 // RETURN, IF THE SEGMENT HAD LESS THAN 3 HITS //
472 if (m_control_histograms) { m_cut_evolution->Fill(0.0, 1.0); }
473
475 if (seg.mdtHitsOnTrack() < 3) { return true; }
476
477 if (m_control_histograms) { m_cut_evolution->Fill(1.0, 1.0); }
478
479 if (std::isnan(seg.direction().x()) || std::isnan(seg.direction().y()) || std::isnan(seg.direction().z()) ||
480 std::isnan(seg.position().x()) || std::isnan(seg.position().y()) || std::isnan(seg.position().z()))
481 return true;
482 if (std::abs(seg.direction().y()) > 100) return true;
483
485 // VARIABLES //
487
488 // segment reconstruction and segment selection //
489 double aux_res; // auxiliary resolution
490 double av_res(0.0); // average spatial resolution of the tube hits
491 double chi2_scale_factor; // chi^2 scale factor used to take into
492 // account bad r-t accuracy in the segment selection
493 IMdtSegmentFitter::HitSelection hit_selection[2];
494 hit_selection[0] = IMdtSegmentFitter::HitSelection(seg.mdtHitsOnTrack());
495 hit_selection[1] = IMdtSegmentFitter::HitSelection(seg.mdtHitsOnTrack());
496 // hit selection vectors for refits in the first and second multilayer
497 unsigned int nb_hits_in_ml[2]; // number of hits in the multilayers
498 double x; // reduced time = (r(t)-0.5*m_r_max)/(0.5*m_r_max)
499 std::vector<double> d_track; // signed distances of the track from the anode wires of the tubes
500 std::vector<double> residual_value; // residuals
501 std::vector<MTStraightLine> w; // anode wires
502 Amg::Vector3D null(0.0, 0.0, 0.0); // auxiliary 0 vector
503 Amg::Vector3D xhat(1.0, 0.0, 0.0); // auxiliary unit vector
504
505 // objects needed to calculate the autocalibration matrix and vector //
506 CLHEP::HepVector G; // vector used in the calculation of the autocalibration matrix
507 std::vector<double> zeta; // vector used in the calculation of G
508
510 // PREPARATION FOR THE SEGMENT REFIT //
512
513 // debug display //
514 // display_segment(&seg, display);
515
516 // overwrite the drift radii according to the input r-t relationship, //
517 // calculate the average spatial resolution to define a road width, //
518 // select the hits in the multilayer, if requested //
519 nb_hits_in_ml[0] = 0;
520 nb_hits_in_ml[1] = 0;
521 for (unsigned int k = 0; k < seg.mdtHitsOnTrack(); k++) {
522 // make the resolution at small radii large enough //
523 aux_res = seg.mdtHOT()[k]->sigmaDriftRadius();
524 if (m_rt->radius(seg.mdtHOT()[k]->driftTime()) < 0.5) {
525 if (aux_res < 0.5 - m_rt->radius(seg.mdtHOT()[k]->driftTime())) { aux_res = 0.5 - m_rt->radius(seg.mdtHOT()[k]->driftTime()); }
526 }
527
528 // overwrite radius //
529 seg.mdtHOT()[k]->setDriftRadius(m_rt->radius(seg.mdtHOT()[k]->driftTime()), aux_res);
530 // seg.mdtHOT()[k]->setDriftRadius(m_rt->radius(
531 // seg.mdtHOT()[k]->driftTime()),
532 // seg.mdtHOT()[k]->sigmaDriftRadius());
533
534 // average resolution in the segment //
535 if (seg.mdtHOT()[k]->sigmaDriftRadius() < 0.5 * m_r_max) {
536 av_res = av_res + std::pow(seg.mdtHOT()[k]->sigmaDriftRadius(), 2);
537 } else {
538 av_res = av_res + 0.01;
539 }
540
541 // hit selection //
542 (hit_selection[0])[k] = 0;
543
544 // 1st multilayer, if splitting is requested //
545 if (m_split_into_ml) { (hit_selection[0])[k] = seg.mdtHOT()[k]->identify().mdtMultilayer() == 2; }
546
547 // 2nd multilayer, if splitting is requested //
548 if (m_split_into_ml) { (hit_selection[1])[k] = seg.mdtHOT()[k]->identify().mdtMultilayer() == 1; }
549
550 // reject hits with bad radii or bad resolution //
551 if (seg.mdtHOT()[k]->driftRadius() < 0.0 || seg.mdtHOT()[k]->driftRadius() > m_r_max ||
552 seg.mdtHOT()[k]->sigmaDriftRadius() > 10.0 * m_r_max) {
553 (hit_selection[0])[k] = 1;
554 (hit_selection[1])[k] = 1;
555 }
556
557 // counting of selected segments //
558 nb_hits_in_ml[0] = nb_hits_in_ml[0] + (1 - (hit_selection[0])[k]);
559 nb_hits_in_ml[1] = nb_hits_in_ml[1] + (1 - (hit_selection[1])[k]);
560
561 // check for hits in both multilayers (needed if splitting is requested) //
562 if (m_multilayer[0] == false && seg.mdtHOT()[k]->identify().mdtMultilayer() == 1) { m_multilayer[0] = true; }
563 if (m_multilayer[1] == false && seg.mdtHOT()[k]->identify().mdtMultilayer() == 2) { m_multilayer[1] = true; }
564 }
565
566 // average resolution and chi^2 scale factor //
567 av_res = std::sqrt(av_res / static_cast<double>(seg.mdtHitsOnTrack()));
568 chi2_scale_factor = std::sqrt(av_res * av_res + m_rt_accuracy * m_rt_accuracy) / av_res;
569
571 // FILL THE AUTOCALIBRATION MATRICES //
573
574 // set the road width for the track reconstruction //
575 m_tracker.setRoadWidth(7.0 * std::sqrt(av_res * av_res + m_rt_accuracy * m_rt_accuracy));
576
577 // loop over the multilayers //
578
579 //-----------------------------------------------------------------------------
580 for (int k = 0; k < 1 + m_split_into_ml; k++) {
581 //-----------------------------------------------------------------------------
582
583 if (nb_hits_in_ml[k] < 3) { continue; }
584
585 // refit the segments within the multilayers //
586 MTStraightLine track;
587
588 if (!m_tracker.fit(seg, hit_selection[k], track)) { continue; }
589
590 if (std::isnan(track.a_x1()) || std::isnan(track.a_x2()) || std::isnan(track.b_x1()) || std::isnan(track.b_x2())) { continue; }
591
592 // check the quality of the fit //
593 if (track.chi2PerDegreesOfFreedom() > 5 * chi2_scale_factor) { continue; }
594
595 // check whether there are at least three track hits //
596 if (m_control_histograms) { m_nb_segment_hits->Fill(track.numberOfTrackHits(), 1.0); }
597 if (track.numberOfTrackHits() < 3) { continue; }
598
599 // reject tracks with silly parameters
600 if (std::abs(track.a_x2()) > 8e8) continue;
601
602 // for filling into data class
603 if (m_iteration == 0) {
604 m_track_slope.Insert(track.a_x2());
605 m_track_position.Insert(track.b_x2());
606 }
607
608 // bookkeeping for convergence decision and reliability estimation //
609 m_chi2 = m_chi2 + track.chi2PerDegreesOfFreedom();
611
612 // fill the autocalibration objects //
613 // auxiliary variables //
614 d_track = std::vector<double>(track.numberOfTrackHits());
615 residual_value = std::vector<double>(track.numberOfTrackHits());
616 w = std::vector<MTStraightLine>(track.numberOfTrackHits());
617 G = CLHEP::HepVector(track.numberOfTrackHits());
618 zeta = std::vector<double>(track.numberOfTrackHits());
619
620 // base function values //
621 for (unsigned int l = 0; l < m_order; l++) {
622 m_U[l] = CLHEP::HepVector(track.numberOfTrackHits());
623 for (unsigned int m = 0; m < track.numberOfTrackHits(); m++) {
624 x = (track.trackHits()[m]->driftRadius() - 0.5 * m_r_max) / (0.5 * m_r_max);
625 (m_U[l])[m] = m_base_function->value(l, x);
626 }
627 }
628
629 // get the wire coordinates, track distances, and residuals //
630 for (unsigned int l = 0; l < track.numberOfTrackHits(); l++) {
631 w[l] =
632 MTStraightLine(Amg::Vector3D(0.0, (track.trackHits()[l]->localPosition()).y(), (track.trackHits()[l]->localPosition()).z()),
633 xhat, null, null);
634 d_track[l] = track.signDistFrom(w[l]);
635 residual_value[l] = track.trackHits()[l]->driftRadius() - std::abs(d_track[l]);
636 if (m_control_histograms) { m_residuals->Fill(std::abs(d_track[l]), residual_value[l], 1.0); }
637 }
638
639 // loop over all track hits //
640 for (unsigned int l = 0; l < track.numberOfTrackHits(); l++) {
641 // analytic calculation of G //
642 for (unsigned int m = 0; m < track.numberOfTrackHits(); m++) {
643 zeta[m] = std::sqrt(1.0 + std::pow(track.a_x2(), 2)) * (w[m].positionVector()).z() - track.a_x2() * d_track[m];
644 }
645 for (unsigned int m = 0; m < track.numberOfTrackHits(); m++) {
646 double sum1(0.0), sum2(0.0), sum3(0.0), sum4(0.0);
647 for (unsigned int ll = 0; ll < track.numberOfTrackHits(); ll++) {
648 sum1 = sum1 + (zeta[l] - zeta[ll]) * (zeta[ll] - zeta[m]) /
649 (track.trackHits()[m]->sigma2DriftRadius() * track.trackHits()[ll]->sigma2DriftRadius());
650 sum2 = sum2 + zeta[ll] / track.trackHits()[ll]->sigma2DriftRadius();
651 sum3 = sum3 + 1.0 / track.trackHits()[ll]->sigma2DriftRadius();
652 sum4 = sum4 + std::pow(zeta[ll] / track.trackHits()[ll]->sigmaDriftRadius(), 2);
653 }
654 if (d_track[m] * d_track[l] >= 0.0) {
655 G[m] = (l == m) - m_full_matrix * sum1 / (sum2 * sum2 - sum3 * sum4);
656 } else {
657 G[m] = (l == m) + m_full_matrix * sum1 / (sum2 * sum2 - sum3 * sum4);
658 }
659 }
660 CLHEP::HepSymMatrix A_tmp(m_A);
661 // autocalibration objects //
662 for (unsigned int p = 0; p < m_order; p++) {
663 for (unsigned int pp = p; pp < m_order; pp++) {
664 A_tmp[p][pp] = m_A[p][pp] + (dot(G, m_U[p]) * dot(G, m_U[pp])) / track.trackHits()[l]->sigma2DriftRadius();
665 if (std::isnan(A_tmp[p][pp])) return true;
666 }
667 }
668 m_A = A_tmp;
669 CLHEP::HepVector b_tmp(m_b);
670 for (unsigned int p = 0; p < m_order; p++) {
671 b_tmp[p] = m_b[p] - residual_value[l] * dot(G, m_U[p]) / track.trackHits()[l]->sigma2DriftRadius();
672 if (std::isnan(b_tmp[p])) return true;
673 }
674 m_b = b_tmp;
675 }
676
677 //-----------------------------------------------------------------------------
678 }
679 //-----------------------------------------------------------------------------
680 return true;
681}
682
683//*****************************************************************************
684
685//:::::::::::::::::::::
686//:: METHOD setInput ::
687//:::::::::::::::::::::
690 // VARIABLES //
692 const RtCalibrationOutput *input(dynamic_cast<const RtCalibrationOutput *>(rt_input));
693
695 // CHECK IF THE OUTPUT CLASS IS SUPPORTED //
697 if (input == nullptr) {
698 throw std::runtime_error(
699 Form("File: %s, Line: %d\nRtCalibrationAnalytic::setInput - Calibration input class not supported.", __FILE__, __LINE__));
700 }
701
703 // GET THE INITIAL r-t RELATIONSHIP AND RESET STATUS VARIABLES //
705
706 // get the r-t relationship //
707 m_rt = input->rt();
708 m_r_max = m_rt->radius(m_rt->tUpper());
709
710 // status variables //
711 m_nb_segments = 0;
713 m_chi2 = 0.0;
714 m_A = CLHEP::HepSymMatrix(m_order, 0);
715 m_b = CLHEP::HepVector(m_order, 0);
716 m_alpha = CLHEP::HepVector(m_order, 0);
717
718 // drift-time interval //
719 auto rt_Chebyshev = dynamic_cast<const RtChebyshev*>(m_rt.get());
720 auto rt_LookUp = dynamic_cast<const RtRelationLookUp*>(m_rt.get());
721
722 if (!rt_Chebyshev && !rt_LookUp) {
723 throw std::runtime_error(
724 Form("File: %s, Line: %d\nRtCalibrationAnalytic::setInput - r-t class not supported.", __FILE__, __LINE__));
725 }
726
727 // RtChebyshev //
728 if (rt_Chebyshev) {
729 m_t_length = rt_Chebyshev->tUpper() - rt_Chebyshev->tLower();
730 m_t_mean = 0.5 * (rt_Chebyshev->tLower() + rt_Chebyshev->tUpper());
731 }
732
733 // RtRelationLookUp, dangerous implementation, but the only way right now //
734 if (rt_LookUp) {
735 m_t_length = rt_LookUp->par(1) * (rt_LookUp->nPar() - 2) - rt_LookUp->par(0);
736 m_t_mean = 0.5 * (rt_LookUp->par(1) * (rt_LookUp->nPar() - 2) + rt_LookUp->par(0));
737 }
738}
739
741 if (m_tfile) m_tfile->cd();
742
744 // VARIABLES //
746 int ifail; // flag indicating a failure of the matrix inversion
747 unsigned int nb_points(30); // number of points used to set the new r-t relationship
748 double step; // r step size
749 auto rt_Chebyshev = dynamic_cast<const RtChebyshev*>(m_rt.get());
750 auto rt_LookUp = dynamic_cast<const RtRelationLookUp*>(m_rt.get());
751 double r_corr; // radial correction
752 std::vector<double> rt_param(m_rt->nPar()); // parameters for the new r-t
753 double x; // reduced time
754 RtParabolicExtrapolation rt_extrapolator; // r-t extrapolator
756 // SOLVE THE AUTOCALIBRATION EQUATION //
758 m_alpha = m_A.inverse(ifail) * m_b;
759 if (ifail != 0) {
760 MsgStream log(Athena::getMessageSvc(), "RtCalibrationAnalytic");
761 log << MSG::WARNING << "analyse() - Could not solve the autocalibration equation!" << endmsg;
762 return false;
763 }
764
766 // CALCULATE THE NEW r-t RELATIONSHIP //
768
769 // input r-t is of type RtChebyshev //
770 if (rt_Chebyshev) {
771 // set the number of points //
772 nb_points = std::max(rt_Chebyshev->nDoF(), 30u);
773
774 // r step size //
775 step = m_r_max / static_cast<double>(nb_points);
776
777 // sample points and Chebyshev fitter //
778 std::vector<SamplePoint> x_r(nb_points + 1);
779 BaseFunctionFitter fitter(rt_Chebyshev->nDoF());
780 ChebyshevPolynomial chebyshev;
781
782 // calculate the sample points //
783 for (unsigned int k = 0; k < nb_points + 1; k++) {
784 x_r[k].set_x1(t_from_r(k * step));
785 x_r[k].set_x2(rt_Chebyshev->radius(x_r[k].x1()));
786 x_r[k].set_x1(rt_Chebyshev->getReducedTime(x_r[k].x1()));
787 x_r[k].set_error(1.0);
788
789 r_corr = 0.0;
790 for (unsigned int l = 0; l < m_order; l++) {
791 // r_corr = r_corr+m_alpha[l]*
792 // m_base_function->value(l, x_r[k].x1());
793 r_corr = r_corr + m_alpha[l] * m_base_function->value(l, (x_r[k].x2() - 0.5 * m_r_max) / (0.5 * m_r_max));
794 }
795
796 // do not change the r-t and the endpoints //
797 if (((k == 0 || x_r[k].x2() < 0.5) && m_fix_min) || ((k == nb_points || x_r[k].x2() > 14.1) && m_fix_max)) {
798 r_corr = 0.0;
799 x_r[k].set_error(0.01);
800 }
801 x_r[k].set_x2(x_r[k].x2() + r_corr);
802 }
803
804 // force monotony //
805 if (m_force_monotony) {
806 for (unsigned int k = 0; k < nb_points; k++) {
807 if (x_r[k].x2() > x_r[k + 1].x2()) { x_r[k + 1].set_x2(x_r[k].x2()); }
808 }
809 }
810
812 std::unique_ptr<TGraphErrors> gre = std::make_unique<TGraphErrors>(x_r.size());
813 for (unsigned int i = 0; i < 1; i++) {
814 gre->SetPoint(i, x_r[i].x1(), x_r[i].x2());
815 gre->SetPointError(i, 0, x_r[i].error());
816 }
817 std::ostringstream str_str;
818 str_str << "CorrectionPoints_" << m_iteration;
819 gre->Write(str_str.str().c_str());
820 }
821
822 // create the new r-t relationship //
823 fitter.fit_parameters(x_r, 1, nb_points + 1, chebyshev);
824 rt_param[0] = rt_Chebyshev->tLower();
825 rt_param[1] = rt_Chebyshev->tUpper();
826 for (unsigned int k = 0; k < rt_Chebyshev->nDoF(); k++) { rt_param[k + 2] = fitter.coefficients()[k]; }
827
828 m_rt_new = std::make_unique<RtChebyshev>(rt_param);
829 }
830
831 // input-rt is of type RtRelationLookUp //
832 if (rt_LookUp) {
833 rt_param = rt_LookUp->parameters();
834 unsigned int min_k(2), max_k(rt_param.size());
835 if (m_fix_min) { min_k = 3; }
836 if (m_fix_max) { max_k = rt_param.size() - 1; }
837
838 std::unique_ptr<TGraph> gr;
839 if (m_control_histograms) gr = std::make_unique<TGraph>(max_k - min_k);
840
841 for (unsigned int k = min_k; k < max_k; k++) {
842 x = (rt_param[k] - 0.5 * m_r_max) / (0.5 * m_r_max);
843 r_corr = m_alpha[0];
844 for (unsigned int l = 1; l < m_order; l++) { r_corr = r_corr + m_alpha[l] * m_base_function->value(l, x); }
845 rt_param[k] = rt_param[k] + r_corr;
846 if (m_control_histograms) gr->SetPoint(k - min_k, x, r_corr);
847 if (m_force_monotony && k > 2) {
848 if (rt_param[k] < rt_param[k - 1]) { rt_param[k] = rt_param[k - 1]; }
849 }
850 }
851
852 m_rt_new = std::make_unique<RtRelationLookUp>(rt_param);
854 std::ostringstream str_str;
855 str_str << "CorrectionPoints_" << m_iteration;
856 gr->Write(str_str.str().c_str());
857 }
858 m_r_max = m_rt_new->radius(m_rt_new->tUpper());
859 }
860
862 // DETERMINE THE r-t QUALITY AND CHECK FOR CONVERGENCE //
864
865 // estimate r-t accuracy //
866 m_rt_accuracy = 0.0;
867 double r_corr_max = 0.0;
868
869 for (unsigned int k = 0; k < 100; k++) {
870 r_corr = m_alpha[0];
871 for (unsigned int l = 1; l < m_order; l++) { r_corr = r_corr + m_alpha[l] * m_base_function->value(l, -1.0 + 0.01 * k); }
872 if (std::abs(r_corr) > r_corr_max) { r_corr_max = std::abs(r_corr); }
873 m_rt_accuracy = m_rt_accuracy + r_corr * r_corr;
874 }
875 m_rt_accuracy = std::sqrt(0.01 * m_rt_accuracy);
877
878 // convergence? //
879
880 m_chi2 = m_chi2 / static_cast<double>(m_nb_segments_used);
881 if (((m_chi2 < m_chi2_previous && std::abs(m_chi2 - m_chi2_previous) > 0.01) || std::abs(m_rt_accuracy) > 0.001) &&
883 m_status = 0; // no convergence yet
884 } else {
885 m_status = 1;
886 }
888
889 // reliabilty of convergence //
890 if (m_status != 0) {
893 }
894
896 // STORE THE RESULTS IN THE RtCalibrationOutput //
899
900 m_output = std::make_shared<RtCalibrationOutput>(
901 m_rt_new, std::make_shared<RtFullInfo>("RtCalibrationAnalytic", m_iteration, m_nb_segments_used, 0.0, 0.0, 0.0, 0.0));
902
903 return true;
904}
905bool RtCalibrationAnalytic::converged() const { return (m_status > 0); }
907std::shared_ptr<RtRelationLookUp> RtCalibrationAnalytic::performParabolicExtrapolation(const bool &min, const bool &max,
908 const IRtRelation &in_rt) {
910 // VARIABLES //
912 RtParabolicExtrapolation rt_extrapolator; // r-t extrapolator
913 std::shared_ptr<RtRelationLookUp> rt_low, rt_high; // pointers to the r-t
914 // relationships after
915 // extrapolation
916 std::vector<SamplePoint> add_fit_point; // additional r-t points used if r(0) or
917 // r(t_max) is fixed.
918
920 // EXTRAPOLATE TO LARGE RADII //
922 if (max) {
923 add_fit_point.clear();
924 if (m_fix_max) { add_fit_point.push_back(SamplePoint(in_rt.tUpper(), in_rt.radius(in_rt.tUpper()), 1.0)); }
925 if (in_rt.radius(in_rt.tUpper()) < 16.0) {
926 rt_high = std::make_shared<RtRelationLookUp>(rt_extrapolator.getRtWithParabolicExtrapolation(
927 in_rt, in_rt.radius(in_rt.tUpper()) - 3.0, in_rt.radius(in_rt.tUpper()) - 1.0, in_rt.radius(in_rt.tUpper()),
928 add_fit_point));
929 } else {
930 rt_high = std::make_shared<RtRelationLookUp>(
931 rt_extrapolator.getRtWithParabolicExtrapolation(in_rt, m_r_max - 3.0, m_r_max - 1.0, m_r_max, add_fit_point));
932 }
933 }
934
936 // EXTRAPOLATE TO SMALL RADII //
938 if (min) {
939 add_fit_point.clear();
940 if (m_fix_min) { add_fit_point.push_back(SamplePoint(m_rt_new->tLower(), 0.0, 1.0)); }
941 if (m_fix_max && rt_high) {
942 rt_low =
943 std::make_shared<RtRelationLookUp>(rt_extrapolator.getRtWithParabolicExtrapolation(*rt_high, 1.0, 3.0, 0.0, add_fit_point));
944 } else {
945 rt_low =
946 std::make_shared<RtRelationLookUp>(rt_extrapolator.getRtWithParabolicExtrapolation(in_rt, 1.0, 3.0, 0.0, add_fit_point));
947 }
948 }
949
951 // RETURN RESULTS //
953 if (min && max) { return rt_low; }
954 if (min) { return rt_low; }
955 return rt_high;
956}
#define endmsg
#define gr
#define G(x, y, z)
Definition MD5.cxx:113
#define x
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
This class performs a fit of a linear combination of base functions to a set of sample points.
This class class provides a Chebyshev polynomial of order k.
Interface to pass calibration output during calibration.
IMdtCalibration(const std::string &name)
constructor, string used to identify the instance
virtual std::string name() const
returns name (region) of instance
std::shared_ptr< IMdtCalibrationOutput > MdtCalibOutputPtr
std::vector< std::shared_ptr< MuonCalibSegment > > MuonSegVec
std::vector< unsigned int > HitSelection
generic interface for a rt-relation
Definition IRtRelation.h:19
virtual double radius(double t) const =0
returns drift radius for a given time
virtual double tUpper() const =0
Returns the upper time covered by the r-t.
double b_x2() const
get the intercept of the straight line in the x2-x3 plane
double a_x2() const
get the slope of the straight line in the x2-x3 plane
A MuonCalibSegment is a reconstructed three dimensional track segment in the MuonSpectrometer.
unsigned int mdtHitsOnTrack() const
retrieve the number of MdtCalibHitBase s assigned to this segment
const MdtHitVec & mdtClose() const
retrieve the full set of nearby mdt hits of this segment.
const Amg::Vector3D & direction() const
retrieve local direction of segment (on station level) retrieve the transformation from local chamber...
unsigned int mdtCloseHits() const
retrieve the number of nearby mdt hits.
const MdtHitVec & mdtHOT() const
retrieve the full set of MdtCalibHitBase s assigned to this segment
const Amg::Vector3D & position() const
retrieve local position of segment (on station level)
std::vector< CLHEP::HepVector > m_U
MdtCalibOutputPtr getResults() const
returns the final r-t relationship
void doNotForceMonotony()
do not force r(t) to be monotonically increasing
void setEstimateRtAccuracy(const double acc)
set the estimated r-t accuracy =acc
int numberOfSegmentsUsed() const
get the number of segments which are used in the autocalibration
bool splitIntoMultilayers() const
returns true, if segments are internally restricted to single multilayers; returns false,...
MdtCalibOutputPtr analyseSegments(const MuonSegVec &seg)
perform the full autocalibration including iterations (required since MdtCalibInterfaces-00-01-06)
std::shared_ptr< IRtRelation > m_rt_new
double reliability() const
get the reliability of the r-t: 0: no convergence yet 1: convergence, r-t is reliable 2: convergence,...
void display_segment(MuonCalibSegment *segment, std::ofstream &outfile)
int numberOfSegments() const
get the number of segments which were passed to the algorithm
void doSmoothing()
requires that the r-t relationship will be smoothened using the conventional autocalibration after co...
void noParabolicExtrapolation()
no parabolic extrapolation is done
void switch_off_control_histograms()
the algorithm does not produce controll histograms (this is the default)
double estimatedRtAccuracy() const
get the estimated r-t quality (CLHEP::mm), the accuracy of the input r-t is computed at the end of th...
std::shared_ptr< const IRtRelation > m_rt
std::unique_ptr< BaseFunction > m_base_function
void doParabolicExtrapolation()
requires that parabolic extrapolation will be used for small and large radii
void init(const double rt_accuracy, const unsigned int &func_type, const unsigned int &ord, const bool &split, const bool &full_matrix, const bool &fix_min, const bool &fix_max, const int &max_it, bool do_smoothing, bool do_parabolic_extrapolation)
bool converged() const
returns true, if the autocalibration has converged
QuasianalyticLineReconstruction m_tracker
bool fullMatrix() const
returns true, if the full matrix relating the errors in the r-t relationship to the residuals should ...
void switch_on_control_histograms(const std::string &file_name)
this methods requests control histograms from the algorithms; the algorithm will write them to ROOT f...
RtCalibrationAnalytic(const std::string &name)
Default constructor: r-t accuracy is set to 0.5 mm.
std::shared_ptr< RtCalibrationOutput > m_output
int iteration() const
get the number of the current iteration
void setInput(const IMdtCalibrationOutput *rt_input)
set the r-t relationship, the internal autocalibration objects are reset
void noSmoothing()
do not smoothen the r-t relationship after convergence
bool analyse()
perform the autocalibration with the segments acquired so far
std::shared_ptr< RtRelationLookUp > performParabolicExtrapolation(const bool &min, const bool &max, const IRtRelation &in_rt)
bool handleSegment(MuonCalibSegment &seg)
analyse the segment "seg" (this method was required before MdtCalibInterfaces-00-01-06)
bool smoothing() const
returns true, if the r-t relationship will be smoothened using the conventional autocalibration after...
void forceMonotony()
force r(t) to be monotonically increasing
std::unique_ptr< TH1F > m_nb_segment_hits
Class for communication between event loop and rt calibration algorithm contains only a rt relation f...
std::shared_ptr< const IRtRelation > rt() const
access to private attributes
This class contains the implementation of an r(t) relationship parametrized by a linear combination o...
Definition RtChebyshev.h:29
RtRelationLookUp getRtWithParabolicExtrapolation(const IRtRelation &in_rt, const double r_min=13.0, const double r_max=14.0) const
get an r-t relationship which is equivalent to the input relationship in_rt for r<r_min and has r(t) ...
Equidistant look up table for rt-relations with the time as key.
virtual double radius(double t) const override final
returns drift radius for a given time
virtual double tLower() const override final
return rt range
virtual double tUpper() const override final
Returns the upper time covered by the r-t.
This class provides a sample point for the BaseFunctionFitter.
Definition SamplePoint.h:15
singleton-like access to IMessageSvc via open function and helper
int r
Definition globals.cxx:22
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
Eigen::Matrix< double, 3, 1 > Vector3D
IMessageSvc * getMessageSvc(bool quiet=false)
CscCalcPed - algorithm that finds the Cathode Strip Chamber pedestals from an RDO.
Definition dot.py:1