ATLAS Offline Software
Loading...
Searching...
No Matches
RtCalibrationCurved.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
6
8#include "CLHEP/GenericFunctions/CumulativeChiSquare.hh"
9#include "CLHEP/Matrix/Matrix.h"
10#include "GaudiKernel/MsgStream.h"
28#include "TF1.h"
29#include "TProfile.h"
30#include "sstream"
31
32using namespace MuonCalib;
33
34inline Double_t RtCalibrationCurved_polfun(Double_t *x, Double_t *par) { return par[0] * RtScalePolynomial(x[0]); }
36 init(0.5 * CLHEP::mm, 1, 15, true, false, 15, false, false, false);
37}
38
39RtCalibrationCurved::RtCalibrationCurved(const std::string &name, const double rt_accuracy, const unsigned int &func_type,
40 const unsigned int &ord, const bool &fix_min, const bool &fix_max, const int &max_it,
41 bool do_parabolic_extrapolation, bool do_smoothing, bool do_multilayer_rt_scale) :
43 init(rt_accuracy, func_type, ord, fix_min, fix_max, max_it, do_parabolic_extrapolation, do_smoothing, do_multilayer_rt_scale);
44}
45
50
52
54
56
58
60
61void RtCalibrationCurved::setEstimateRtAccuracy(const double acc) { m_rt_accuracy = std::abs(acc); }
62
63void RtCalibrationCurved::switch_on_control_histograms(const std::string &file_name) {
65 // CREATE THE ROOT FILE AND THE HISTOGRAMS //
68
69 m_tfile = std::make_unique<TFile>(file_name.c_str(), "RECREATE");
70
71 m_cut_evolution = std::make_unique<TH1F>("m_cut_evolution", "CUT EVOLUTION", 11, -0.5, 10.5);
72 m_nb_segment_hits = std::make_unique<TH1F>("m_nb_segment_hits", "NUMBER OF HITS ON THE REFITTED SEGMENTS", 11, -0.5, 10.5);
73 m_pull_initial = std::make_unique<TH1F>("m_pull_initial", "INITIAL PULL DISTRIBUTION", 200, -5.05, 5.05);
75 std::make_unique<TH2F>("m_residuals_initial", "INITIAL OF THE REFITTED SEGMENTS", 100, -0.5, 15.0, 300, -1.5, 1.5);
76 m_residuals_initial_all = std::make_unique<TH2F>("m_residuals_initial_all", "INITIAL OF THE REFITTED SEGMENTS BEFORE CONVERGENCE", 300,
77 -15.0, 15.0, 1000, -5, 5);
78 m_residuals_final = std::make_unique<TH2F>("m_residuals_final", "FINAL OF THE REFITTED SEGMENTS", 100, -0.5, 15.0, 300, -1.5, 1.5);
80 std::make_unique<TH2F>("m_driftTime_final", "FINAL DRIFTTIME OF THE REFITTED SEGMENTS", 300, -15.0, 15.0, 300, -15.0, 15.0);
82 std::make_unique<TH2F>("m_driftTime_initial", "FINAL DRIFTTIME OF THE REFITTED SEGMENTS", 300, -15.0, 15.0, 1300, -100, 1200);
84 std::make_unique<TH2F>("m_adc_resi_initial", "FINAL ADC VS RESIDUAL OF THE REFITTED SEGMENTS", 1350, 0, 1350, 300, -15, 15);
85
86 m_multilayer_rt_difference = std::make_unique<MultilayerRtDifference>(10000, m_tfile.get());
87}
90 if (m_tfile) {
91 m_tfile->Write();
92 m_multilayer_rt_difference = std::make_unique<MultilayerRtDifference>(10000);
93 }
94}
95
102 std::shared_ptr<const IRtRelation> tmp_rt;
103
105 // Initial RESIDUALS //
107 for (const auto & k : seg) {
108 for (unsigned int l = 0; l < k->hitsOnTrack(); l++) {
109 double rr = (k->mdtHOT())[l]->driftRadius();
110 double dd = (k->mdtHOT())[l]->signedDistanceToTrack();
111 if (m_residuals_final) m_residuals_initial_all->Fill(std::abs(dd), std::abs(rr) - std::abs(dd));
112 m_driftTime_initial->Fill(rr, dd);
113 }
114 }
115
117 // AUTOCALIBRATION LOOP //
119 while (!converged()) {
120 for (const auto & k : seg) { handleSegment(*k); }
121 if (!analyse(seg)) {
122 MsgStream log(Athena::getMessageSvc(), "RtCalibrationCurved");
123 log << MSG::WARNING << "analyseSegments() - analyse failed, segments:" << endmsg;
124 for (unsigned int i = 0; i < seg.size(); i++) {
125 log << MSG::WARNING << i << " " << seg[i]->direction() << " " << seg[i]->position() << endmsg;
126 }
127 return nullptr;
128 }
129
130 const RtCalibrationOutput *rtOut = m_output.get();
131
132 if (!converged()) { setInput(rtOut); }
133 tmp_rt = rtOut->rt();
134 }
135
136 // parabolic extrapolations for small radii //
138 std::shared_ptr<RtRelationLookUp> tmprt = performParabolicExtrapolation(true, true, *tmp_rt);
139 m_output = std::make_shared<RtCalibrationOutput>(
140 tmprt, std::make_shared<RtFullInfo>("RtCalibrationCurved", m_iteration, m_nb_segments_used, 0.0, 0.0, 0.0, 0.0));
141
142 tmp_rt = tmprt;
143 }
144
146 // SMOOTHING AFTER CONVERGENCE IF REQUESTED //
148 if (!m_do_smoothing) {
149 // final residuals //
150 double r{0}, d{0}, adc{0};
151 for (const auto & k : seg) {
152 for (unsigned int l = 0; l < k->hitsOnTrack(); l++) {
153 adc = (k->mdtHOT())[l]->adcCount();
154 r = (k->mdtHOT())[l]->driftRadius();
155 d = (k->mdtHOT())[l]->signedDistanceToTrack();
156 if (m_residuals_final) m_residuals_final->Fill(std::abs(d), std::abs(r) - std::abs(d));
157 m_driftTime_final->Fill(r, d);
158 m_adc_vs_residual_final->Fill(adc, std::abs(r) - std::abs(d));
159 }
160 }
161 return getResults();
162 }
163
164 // maximum number of iterations //
165 int max_smoothing_iterations(static_cast<int>(m_max_it));
166 if (max_smoothing_iterations == 0) { max_smoothing_iterations = 1; }
167
168 // convergence RMS //
169 double convergence_RMS(0.002);
170
171 // variables //
172 int it(0); // iteration
173 double RMS(1.0); // RMS change of r(t)
174
175 // smoothing //
176 //---------------------------------------------------------------------------//
177 //---------------------------------------------------------------------------//
178 while (it < max_smoothing_iterations && RMS > convergence_RMS) {
179 //---------------------------------------------------------------------------//
181
182 // counter //
183 unsigned int counter{0};
184 // overwrite drift radii and calculate the average resolution //
185 for (const auto & k : seg) {
186 if (k->mdtHitsOnTrack() < 4) { continue; }
187 double avres(0.0);
188 for (unsigned int h = 0; h < k->mdtHitsOnTrack(); h++) {
189 k->mdtHOT()[h]->setDriftRadius(tmp_rt->radius(k->mdtHOT()[h]->driftTime()),
190 k->mdtHOT()[h]->sigmaDriftRadius());
191 if (k->mdtHOT()[h]->sigmaDriftRadius() < 0.5 * m_r_max) {
192 avres = avres + k->mdtHOT()[h]->sigma2DriftRadius();
193 } else {
194 avres = avres + 0.01;
195 }
196 }
197 avres = avres / static_cast<double>(k->mdtHitsOnTrack());
198 avres = std::sqrt(avres);
199 if (smoothing.addResidualsFromSegment(*k, true, 5.0 * avres)) { counter++; }
200 }
201
202 // break, do no smoothing if there are not enough segments //
203 if (counter < 1000) {
204 MsgStream log(Athena::getMessageSvc(), "RtCalibrationCurved");
205 log << MSG::WARNING << "analyseSegments() - too small number of reconstructed segments!" << endmsg;
206 // final residuals //
207 for (const auto & k : seg) {
208 for (unsigned int l = 0; l < k->hitsOnTrack(); l++) {
209 double r = (k->mdtHOT())[l]->driftRadius();
210 double d = (k->mdtHOT())[l]->signedDistanceToTrack();
211 if (m_residuals_final) m_residuals_final->Fill(d, std::abs(r) - std::abs(d), 1.0);
212 }
213 }
214 return getResults();
215 }
216
217 // smoothing //
218 RtRelationLookUp smooth_rt(smoothing.performSmoothing(*tmp_rt, m_fix_min, m_fix_max));
219
220 // calculate RMS change //
221 RMS = 0.0;
222 double bin_width(0.01 * (smooth_rt.tUpper() - smooth_rt.tLower()));
223 for (double t = smooth_rt.tLower(); t <= smooth_rt.tUpper(); t = t + bin_width) {
224 RMS = RMS + std::pow(smooth_rt.radius(t) - tmp_rt->radius(t), 2);
225 }
226 RMS = std::sqrt(0.01 * RMS);
227
228 // increase the iterations counter //
229 it++;
230
231 // delete tmp_rt and update it //
232 tmp_rt = std::make_shared<RtRelationLookUp>(smooth_rt);
233
234 //---------------------------------------------------------------------------//
235 }
236 //---------------------------------------------------------------------------//
237 //---------------------------------------------------------------------------//
238 m_output = std::make_shared<RtCalibrationOutput>(
239 tmp_rt, std::make_shared<RtFullInfo>("RtCalibrationCurved", m_iteration, m_nb_segments_used, 0.0, 0.0, 0.0, 0.0));
240
242 // FINAL RESIDUALS //
244 for (const auto & k : seg) {
245 for (unsigned int l = 0; l < k->hitsOnTrack(); l++) {
246 double adc = (k->mdtHOT())[l]->adcCount();
247 double r = (k->mdtHOT())[l]->driftRadius();
248 double d = (k->mdtHOT())[l]->signedDistanceToTrack();
249 if (m_residuals_final) m_residuals_final->Fill(d, std::abs(r) - std::abs(d));
250 m_driftTime_final->Fill(r, d);
251 m_adc_vs_residual_final->Fill(adc, std::abs(r) - std::abs(d));
252 }
253 }
254
256 // RETURN THE RESULT AFTER CONVERGENCE //
258 return getResults();
259}
260
261//*****************************************************************************
262
263//::::::::::::::::::::::::::
264//:: METHOD handleSegment ::
265//::::::::::::::::::::::::::
266
269 // RETURN, IF THE SEGMENT HAD LESS THAN 4 HITS //
271 if (m_control_histograms) { m_cut_evolution->Fill(0.0, 1.0); }
272
274 if (seg.mdtHitsOnTrack() < 4) { return true; }
275
276 if (m_control_histograms) { m_cut_evolution->Fill(1.0, 1.0); }
277
278 if (std::isnan(seg.direction().x()) || std::isnan(seg.direction().y()) || std::isnan(seg.direction().z()) ||
279 std::isnan(seg.position().x()) || std::isnan(seg.position().y()) || std::isnan(seg.position().z())) {
280 return true;
281 }
282 if (std::abs(seg.direction().y()) > 100) { return true; }
283
285 // VARIABLES //
287
288 // segment reconstruction and segment selection //
289 double aux_res; // auxiliary resolution
290 double av_res(0.0); // average spatial resolution of the tube hits
291 double chi2_scale_factor; // chi^2 scale factor used to take into
292 // account bad r-t accuracy in the segment
293 // selection
295 // hit selection vectors for refits
296 unsigned int nb_hits_in_ml; // number of hits in the multilayers
297 double x; // reduced time = (r(t)-0.5*m_r_max)/(0.5*m_r_max)
298 std::vector<double> d_track; // signed distances of the track from the anode
299 // wires of the tubes
300 std::vector<MTStraightLine> w; // anode wires
301 Amg::Vector3D null(0.0, 0.0, 0.0); // auxiliary 0 vector
302 Amg::Vector3D xhat(1.0, 0.0, 0.0); // auxiliary unit vector
303
304 // objects needed to calculate the autocalibration matrix and vector //
305 std::vector<CLHEP::HepVector> F; // auxiliary vectors for the calculation of the
306 // track cooeffients matrix
307 CLHEP::HepVector residual_value; // residuals values
308 CLHEP::HepVector weighted_residual; // residual values weighted by the inverse
309 // variance of the radius measurements
310 CLHEP::HepMatrix D; // Jacobian of the residuals (dresiduals/dr)
311 // static ofstream display("display.kumac");
312
314 // PREPARATION FOR THE SEGMENT REFIT //
316
317 // overwrite the drift radii according to the input r-t relationship, //
318 // calculate the average spatial resolution to define a road width, //
319 // select the hits in the chamber //
320 nb_hits_in_ml = 0;
321 for (unsigned int k = 0; k < seg.mdtHitsOnTrack(); k++) {
322 // make the resolution at small radii large enough //
323 aux_res = seg.mdtHOT()[k]->sigmaDriftRadius();
324 if (m_rt->radius(seg.mdtHOT()[k]->driftTime()) < 0.75) {
325 if (aux_res < 0.5 - m_rt->radius(seg.mdtHOT()[k]->driftTime())) { aux_res = 0.5 - m_rt->radius(seg.mdtHOT()[k]->driftTime()); }
326 }
327
328 // overwrite radius //
329 seg.mdtHOT()[k]->setDriftRadius(m_rt->radius(seg.mdtHOT()[k]->driftTime()), aux_res);
330
331 // hit selection //
332 hit_selection[k] = 0;
333
334 // reject hits with bad radii //
335 if (seg.mdtHOT()[k]->driftRadius() < 0.0 || seg.mdtHOT()[k]->driftRadius() > m_r_max ||
336 seg.mdtHOT()[k]->sigmaDriftRadius() > 10.0 * m_r_max) {
337 hit_selection[k] = 1;
338 }
339
340 // average resolution in the segment //
341 if (hit_selection[k] == 0) {
342 if (seg.mdtHOT()[k]->sigmaDriftRadius() < 0.5 * m_r_max) {
343 av_res = av_res + std::pow(seg.mdtHOT()[k]->sigmaDriftRadius(), 2);
344 } else {
345 av_res = av_res + 0.01;
346 }
347 }
348
349 // counting of selected segments //
350 nb_hits_in_ml = nb_hits_in_ml + (1 - hit_selection[k]);
351 }
352
353 // average resolution and chi^2 scale factor //
354 av_res = std::sqrt(av_res / static_cast<double>(seg.mdtHitsOnTrack()));
355 chi2_scale_factor = std::hypot(av_res, m_rt_accuracy) / av_res;
356
358 // FILL THE AUTOCALIBRATION MATRICES //
360
361 // set the road width for the track reconstruction //
362 m_tracker->setRoadWidth(7.0 * std::hypot(av_res, m_rt_accuracy));
363
364 // check whether there are enough hits in the chambers //
365 if (nb_hits_in_ml < 4) { return true; }
366
367 // refit the segments //
368 CurvedLine track;
369
370 if (!m_tracker->fit(seg, hit_selection, track)) { return true; }
371
372 if (std::isnan(track.chi2())) { return true; }
373
374 // check the quality of the fit //
375 if (track.chi2PerDegreesOfFreedom() > 5 * chi2_scale_factor) { return true; }
376
377 // check whether there are at least three track hits //
378 if (m_control_histograms) { m_nb_segment_hits->Fill(track.numberOfTrackHits()); }
379 if (track.numberOfTrackHits() < 4) { return true; }
380
381 // display_segment(&seg, display&(m_tracker->curvedTrack()));
382
383 // reject tracks with silly parameters
384 if (std::abs(track.getTangent(seg.mdtHOT()[0]->localPosition().z()).a_x2()) > 8.0e8) { return true; }
385
386 // bookkeeping for convergence decision and reliability estimation //
387 m_chi2 += track.chi2PerDegreesOfFreedom();
389
390 // fill the autocalibration objects //
391
392 // track coeffient matrix and its inverse //
393 F = std::vector<CLHEP::HepVector>(track.numberOfTrackHits());
394 for (unsigned int h = 0; h < track.numberOfTrackHits(); h++) {
395 const MdtCalibHitBase &hb = *(track.trackHits()[h]);
397
398 F[h] = CLHEP::HepVector(m_M_track.num_row());
399 for (int p = 0; p < F[h].num_row(); p++) {
400 double x = std::sqrt(1.0 + std::pow(track.getTangent((track.trackHits()[h]->localPosition()).z()).a_x2(), 2));
401 if (x) {
402 (F[h])[p] = std::legendre(p, (track.trackHits()[h]->localPosition()).z()) / x;
403 } else {
404 (F[h])[p] = 0.;
405 }
406 }
407 }
408 for (int p = 0; p < m_M_track.num_row(); p++) {
409 for (int q = p; q < m_M_track.num_row(); q++) {
410 m_M_track[p][q] = 0.0;
411 for (unsigned int h = 0; h < track.numberOfTrackHits(); h++) {
412 m_M_track[p][q] = m_M_track[p][q] + (F[h])[p] * (F[h])[q] / (track.trackHits()[h])->sigma2DriftRadius();
413 }
414 m_M_track[q][p] = m_M_track[p][q];
415 }
416 }
417 int ifail;
418 m_M_track_inverse = m_M_track.inverse(ifail);
419 if (ifail != 0) {
420 MsgStream log(Athena::getMessageSvc(), "RtCalibrationCurved");
421 log << MSG::WARNING << "handleSegment() - Could not invert track matrix!" << endmsg;
422 return true;
423 }
424
425 // Jacobian matrix for the residuals //
426 // track distances, residuals, corrections //
427 d_track = std::vector<double>(track.numberOfTrackHits());
428 w = std::vector<MTStraightLine>(track.numberOfTrackHits());
429 residual_value = CLHEP::HepVector(track.numberOfTrackHits());
430 weighted_residual = CLHEP::HepVector(track.numberOfTrackHits());
431 for (unsigned int l = 0; l < m_order; l++) {
432 m_U[l] = CLHEP::HepVector(track.numberOfTrackHits());
433 m_U_weighted[l] = CLHEP::HepVector(track.numberOfTrackHits());
434 }
435 for (unsigned int h = 0; h < track.numberOfTrackHits(); h++) {
436 w[h] = MTStraightLine(Amg::Vector3D(0.0, (track.trackHits()[h]->localPosition()).y(), (track.trackHits()[h]->localPosition()).z()),
437 xhat, null, null);
438 d_track[h] = track.getTangent((track.trackHits()[h]->localPosition()).z()).signDistFrom(w[h]);
439 residual_value[h] = (track.trackHits()[h])->driftRadius() - std::abs(d_track[h]);
441 if (m_iteration == 0) { m_residuals_initial->Fill(std::abs(d_track[h]), residual_value[h], 1.0); }
442 }
443 for (unsigned int l = 0; l < m_order; l++) {
444 x = (track.trackHits()[h]->driftRadius() - 0.5 * m_r_max) / (0.5 * m_r_max);
445 (m_U[l])[h] = m_base_function->value(l, x);
446 }
447 }
448
449 // Jacobian //
450 D = CLHEP::HepMatrix(track.numberOfTrackHits(), track.numberOfTrackHits());
451 for (unsigned int h = 0; h < track.numberOfTrackHits(); h++) {
452 for (unsigned int hp = 0; hp < track.numberOfTrackHits(); hp++) {
453 D[h][hp] = (h == hp) - (2 * (d_track[h] >= 0) - 1) * (2 * (d_track[hp] >= 0) - 1) * dot(F[h], m_M_track_inverse * F[hp]) /
454 (track.trackHits()[hp])->sigma2DriftRadius();
455 }
456 }
457
458 // autocalibration objects //
459 // errors of the residuals //
460 std::vector<double> sigma_residual(track.numberOfTrackHits(), 0.0);
461 for (unsigned int h = 0; h < track.numberOfTrackHits(); h++) {
462 for (unsigned int hp = 0; hp < track.numberOfTrackHits(); hp++) {
463 sigma_residual[h] = sigma_residual[h] + std::pow(D[h][hp] * (track.trackHits()[hp])->sigmaDriftRadius(), 2);
464 }
465 sigma_residual[h] = std::sqrt(sigma_residual[h]);
466 if (sigma_residual[h] < av_res / track.numberOfTrackHits()) { sigma_residual[h] = av_res / std::sqrt(track.numberOfTrackHits()); }
467 }
468
469 // weight residuals and correction functions //
470 for (unsigned int h = 0; h < track.numberOfTrackHits(); h++) {
471 weighted_residual[h] = residual_value[h] / sigma_residual[h];
473 if (m_iteration == 0) { m_pull_initial->Fill(weighted_residual[h], 1.0); }
474 }
475 for (unsigned int l = 0; l < m_order; l++) { (m_U_weighted[l])[h] = (m_U[l])[h] / sigma_residual[h]; }
476 }
477
478 // autocalibration matrix and autocalibration vector //
479 CLHEP::HepSymMatrix A_tmp(m_A);
480
481 // autocalibration objects //
482 for (unsigned int p = 0; p < m_order; p++) {
483 for (unsigned int pp = p; pp < m_order; pp++) {
484 A_tmp[p][pp] = m_A[p][pp] + dot(D * m_U_weighted[p], D * m_U_weighted[pp]);
485 if (std::isnan(A_tmp[p][pp])) { return true; }
486 }
487 }
488
489 CLHEP::HepVector b_tmp(m_b);
490 for (unsigned int p = 0; p < m_order; p++) {
491 b_tmp[p] = m_b[p] + dot(D * m_U_weighted[p], weighted_residual);
492 if (std::isnan(b_tmp[p])) { return true; }
493 }
494
495 m_A = A_tmp;
496 m_b = b_tmp;
497
498 return true;
499}
500
501//*****************************************************************************
502
503//:::::::::::::::::::::
504//:: METHOD setInput ::
505//:::::::::::::::::::::
508 // VARIABLES //
510 const RtCalibrationOutput *input(dynamic_cast<const RtCalibrationOutput *>(rt_input));
511
513 // CHECK IF THE OUTPUT CLASS IS SUPPORTED //
515 if (input == nullptr) {
516 throw std::runtime_error(
517 Form("File: %s, Line: %d\nRtCalibrationCurved::setInput - Calibration input class not supported.", __FILE__, __LINE__));
518 }
519
521 // GET THE INITIAL r-t RELATIONSHIP AND RESET STATUS VARIABLES //
523
524 // get the r-t relationship //
525 m_rt = input->rt();
526
527 // status variables //
528 m_nb_segments = 0;
530 m_chi2 = 0.0;
531 m_A = CLHEP::HepSymMatrix(m_order, 0);
532 m_b = CLHEP::HepVector(m_order, 0);
533 m_alpha = CLHEP::HepVector(m_order, 0);
534
535 // drift-time interval //
536 auto rt_Chebyshev = dynamic_cast<const RtChebyshev*>(m_rt.get());
537 auto rt_LookUp = dynamic_cast<const RtRelationLookUp*>(m_rt.get());
538
539 if (!rt_Chebyshev && !rt_LookUp) {
540 throw std::runtime_error(Form("File: %s, Line: %d\nRtCalibrationCurved::setInput - r-t class not supported.", __FILE__, __LINE__));
541 }
542
543 // RtChebyshev //
544 if (rt_Chebyshev) {
545 m_t_length = rt_Chebyshev->tUpper() - rt_Chebyshev->tLower();
546 m_t_mean = 0.5 * (rt_Chebyshev->tLower() + rt_Chebyshev->tUpper());
547 }
548
549 // RtRelationLookUp, dangerous implementation, but the only way right now //
550 if (rt_LookUp) {
551 m_t_length = rt_LookUp->par(1) * (rt_LookUp->nPar() - 2) - rt_LookUp->par(0);
552 m_t_mean = 0.5 * (rt_LookUp->par(1) * (rt_LookUp->nPar() - 2) + rt_LookUp->par(0));
553 }
554
555 return;
556}
557
558//*****************************************************************************
559
560//::::::::::::::::::::
561//:: METHOD analyse ::
562//::::::::::::::::::::
565 // VARIABLES //
567 int ifail; // flag indicating a failure of the matrix inversion
568 unsigned int nb_points(30); // number of points used to set the new r-t relationship
569 double step; // r step size
570 auto rt_Chebyshev = dynamic_cast<const RtChebyshev*>(m_rt.get());
571 auto rt_LookUp = dynamic_cast<const RtRelationLookUp*>(m_rt.get());
572 double r_corr; // radial correction
573 std::vector<double> rt_param(m_rt->nPar()); // parameters for the new r-t
574 double x; // reduced time
575
577 // SOLVE THE AUTOCALIBRATION EQUATION //
579
580 m_alpha = m_A.inverse(ifail) * m_b;
581 if (ifail != 0) {
582 MsgStream log(Athena::getMessageSvc(), "RtCalibrationCurved");
583 log << MSG::WARNING << "analyse() - Could not solve the autocalibration equation!" << endmsg;
584 return false;
585 }
586
588 // CALCULATE THE NEW r-t RELATIONSHIP //
590
591 // input r-t is of type RtChebyshev //
592 if (rt_Chebyshev) {
593 // set the number of points //
594 if (rt_Chebyshev->nDoF() > 30) { nb_points = rt_Chebyshev->nDoF(); }
595
596 // r step size //
597 step = m_r_max / static_cast<double>(nb_points);
598
599 // sample points and Chebyshev fitter //
600 std::vector<SamplePoint> x_r(nb_points + 1);
601 BaseFunctionFitter fitter(rt_Chebyshev->nDoF());
602 ChebyshevPolynomial chebyshev;
603
604 // calculate the sample points //
605 for (unsigned int k = 0; k < nb_points + 1; k++) {
606 x_r[k].set_x1(t_from_r(k * step));
607 x_r[k].set_x2(rt_Chebyshev->radius(x_r[k].x1()));
608 x_r[k].set_x1(rt_Chebyshev->getReducedTime(x_r[k].x1()));
609 x_r[k].set_error(1.0);
610
611 r_corr = 0.0;
612 for (unsigned int l = 0; l < m_order; l++) {
613 // r_corr = r_corr+m_alpha[l]*
614 // m_base_function->value(l, x_r[k].x1());
615 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));
616 }
617
618 // do not change the r-t and the endpoints //
619 if (((k == 0 || x_r[k].x2() < 0.5) && m_fix_min) || ((k == nb_points || x_r[k].x2() > m_r_max) && m_fix_max)) {
620 r_corr = 0.0;
621 x_r[k].set_error(0.01);
622 }
623 x_r[k].set_x2(x_r[k].x2() - r_corr);
624 }
625
626 // force monotony //
627 if (m_force_monotony) {
628 for (unsigned int k = 0; k < nb_points; k++) {
629 if (x_r[k].x2() > x_r[k + 1].x2()) { x_r[k + 1].set_x2(x_r[k].x2()); }
630 }
631 }
632
633 // create the new r-t relationship //
634 fitter.fit_parameters(x_r, 1, nb_points + 1, chebyshev);
635 rt_param[0] = rt_Chebyshev->tLower();
636 rt_param[1] = rt_Chebyshev->tUpper();
637 for (unsigned int k = 0; k < rt_Chebyshev->nDoF(); k++) { rt_param[k + 2] = fitter.coefficients()[k]; }
638
639 m_rt_new = std::make_shared<RtChebyshev>(rt_param);
640 m_rt_new->SetTmaxDiff(m_rt->GetTmaxDiff());
641 }
642
643 // input-rt is of type RtRelationLookUp //
644 if (rt_LookUp) {
645 rt_param = rt_LookUp->parameters();
646 unsigned int min_k(2), max_k(rt_param.size());
647 if (m_fix_min) { min_k = 3; }
648 if (m_fix_max) { max_k = rt_param.size() - 1; }
649 for (unsigned int k = min_k; k < max_k; k++) {
650 x = (rt_param[k] - 0.5 * m_r_max) / (0.5 * m_r_max);
651 r_corr = m_alpha[0];
652 for (unsigned int l = 1; l < m_order; l++) { r_corr = r_corr + m_alpha[l] * m_base_function->value(l, x); }
653 rt_param[k] = rt_param[k] - r_corr;
654 if (m_force_monotony && k > 2) {
655 if (rt_param[k] < rt_param[k - 1]) { rt_param[k] = rt_param[k - 1]; }
656 }
657 }
658
659 m_rt_new = std::make_shared<RtRelationLookUp>(rt_param);
660 m_rt_new->SetTmaxDiff(m_rt->GetTmaxDiff());
661 }
662
664 // DETERMINE THE r-t QUALITY AND CHECK FOR CONVERGENCE //
666
667 // estimate r-t accuracy //
668 m_rt_accuracy = 0.0;
669 // double m_rt_accuracy_diff = 0.0;
670 double r_corr_max = 0.0;
671
672 for (unsigned int k = 0; k < 100; k++) {
673 r_corr = m_alpha[0];
674 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); }
675 if (std::abs(r_corr) > r_corr_max) { r_corr_max = std::abs(r_corr); }
676 m_rt_accuracy = m_rt_accuracy + r_corr * r_corr;
677 }
678 m_rt_accuracy = std::sqrt(0.01 * m_rt_accuracy);
679 // m_rt_accuracy_diff = m_rt_accuracy_previous - m_rt_accuracy;
681
682 // convergence? //
683 m_chi2 = m_chi2 / static_cast<double>(m_nb_segments_used);
684 if ((m_chi2 <= m_chi2_previous || std::abs(m_chi2 - m_chi2_previous) > 0.01) ||
685 (std::abs(m_rt_accuracy) > 0.001 && m_iteration < m_max_it)) {
686 m_status = 0; // no convergence yet
687 } else {
688 m_status = 1;
689 }
691
692 // reliabilty of convergence //
693 if (m_status != 0) {
694 if (m_nb_segments_used < 0.5 * m_nb_segments) { m_status = 2; }
695 }
696
698 // Set new multilayer rt-difference //
701 m_multilayer_rt_difference->DoFit(m_rt_new.get(), seg);
702 } else {
703 m_multilayer_rt_difference->DoFit(nullptr, {});
704 }
705
707 // STORE THE RESULTS IN THE RtCalibrationOutput //
709
711
712 m_output = std::make_shared<RtCalibrationOutput>(
713 m_rt_new, std::make_shared<RtFullInfo>("RtCalibrationCurved", m_iteration, m_nb_segments_used, 0.0, 0.0, 0.0, 0.0));
714
715 return true;
716}
717bool RtCalibrationCurved::converged() const { return (m_status > 0); }
719
720//*****************************************************************************
721
722//:::::::::::::::::
723//:: METHOD init ::
724//:::::::::::::::::
725void RtCalibrationCurved::init(const double rt_accuracy, const unsigned int &func_type, const unsigned int &ord, const bool &fix_min,
726 const bool &fix_max, const int &max_it, bool do_parabolic_extrapolation, bool do_smoothing,
727 bool do_multilayer_rt_scale) {
729 // RESET PRIVATE VARIABLES //
731 m_rt = nullptr;
732 m_r_max = 15.0 * CLHEP::mm;
733 m_control_histograms = false;
734 m_nb_segments = 0;
736 m_iteration = 0;
737 m_multilayer[0] = false;
738 m_multilayer[1] = false;
739 m_status = 0;
740 m_rt_accuracy = std::abs(rt_accuracy);
741 m_chi2_previous = 1.0e99; // large value to force at least two rounds
742 m_chi2 = 0.0;
743 m_order = ord;
744 m_fix_min = fix_min;
745 m_fix_max = fix_max;
746 m_max_it = std::abs(max_it);
747 m_do_multilayer_rt_scale = do_multilayer_rt_scale;
748 m_multilayer_rt_difference = std::make_unique<MultilayerRtDifference>(10000);
749
750 m_tracker = std::make_unique<CurvedPatRec>();
751
752 if (m_order == 0) {
753 throw std::runtime_error(
754 Form("File: %s, Line: %d\nRtCalibrationCurved::init - Order of the correction polynomial must be >0!", __FILE__, __LINE__));
755 }
756
757 m_t_length = 1000.0;
758 m_t_mean = 500.0;
759 // default values, correct values will be set when the input r-t
760 // has been given
761
762 m_U = std::vector<CLHEP::HepVector>(m_order);
763 m_U_weighted = std::vector<CLHEP::HepVector>(m_order);
764 m_A = CLHEP::HepSymMatrix(m_order, 0);
765 m_b = CLHEP::HepVector(m_order, 0);
766 m_alpha = CLHEP::HepVector(m_order, 0);
767
768 // correction function
769 if (func_type < 1 || func_type > 3) {
770 throw std::runtime_error(
771 Form("File: %s, Line: %d\nRtCalibrationCurved::init - Illegal correction function type!", __FILE__, __LINE__));
772 }
773 switch (func_type) {
774 case 1: m_base_function = std::make_unique<LegendrePolynomial>(); break;
775 case 2: m_base_function = std::make_unique<ChebyshevPolynomial>(); break;
776 case 3:
777 if (m_order < 2) {
778 throw std::runtime_error(
779 Form("File: %s, Line: %d\nRtCalibrationCurved::init - Order must be >2 for polygons! It is set to %i by the user.",
780 __FILE__, __LINE__, m_order));
781 }
782 std::vector<double> x(m_order);
783 double bin_width = 2.0 / static_cast<double>(m_order - 1);
784 for (unsigned int k = 0; k < m_order; k++) { x[k] = -1 + k * bin_width; }
785 m_base_function = std::make_unique<PolygonBase>(x);
786 break;
787 }
788
789 // monotony of r(t) //
790 m_force_monotony = false;
791
792 // parabolic extrapolations //
793 m_do_parabolic_extrapolation = do_parabolic_extrapolation;
794
795 // smoothing //
796 m_do_smoothing = do_smoothing;
797
798 m_M_track = CLHEP::HepSymMatrix(3);
799 m_M_track_inverse = CLHEP::HepSymMatrix(3);
800
801 return;
802}
803double RtCalibrationCurved::t_from_r(const double r) {
805 // VARIABLES //
807 double precision(0.001); // spatial precision of the inversion
808 double t_max(0.5 * (m_t_length + 2.0 * m_t_mean)); // upper time search limit
809 double t_min(t_max - m_t_length); // lower time search limit
810
812 // SEARCH FOR THE CORRESPONDING DRIFT TIME //
814 while (t_max - t_min > 0.1 && std::abs(m_rt->radius(0.5 * (t_min + t_max)) - r) > precision) {
815 if (m_rt->radius(0.5 * (t_min + t_max)) > r) {
816 t_max = 0.5 * (t_min + t_max);
817 } else {
818 t_min = 0.5 * (t_min + t_max);
819 }
820 }
821
822 return 0.5 * (t_min + t_max);
823}
824void RtCalibrationCurved::display_segment(MuonCalibSegment *segment, std::ofstream &outfile, const CurvedLine *curved_segment) {
826 // VARIABLES //
828 double y_min, y_max, z_min, z_max; // minimum and maximum y and z coordinates
829 Amg::Vector3D null(0.0, 0.0, 0.0); // auxiliary null vector
830
832 // DISPLAY THE SEGMENT //
834 // minimum and maximum coordinates //
835 y_min = (segment->mdtHOT()[0])->localPosition().y();
836 y_max = y_min;
837 z_min = (segment->mdtHOT()[0])->localPosition().z();
838 z_max = z_min;
839 for (unsigned int k = 1; k < segment->mdtHitsOnTrack(); k++) {
840 if ((segment->mdtHOT()[k])->localPosition().y() < y_min) { y_min = (segment->mdtHOT()[k])->localPosition().y(); }
841 if ((segment->mdtHOT()[k])->localPosition().y() > y_max) { y_max = (segment->mdtHOT()[k])->localPosition().y(); }
842 if ((segment->mdtHOT()[k])->localPosition().z() < z_min) { z_min = (segment->mdtHOT()[k])->localPosition().z(); }
843 if ((segment->mdtHOT()[k])->localPosition().z() > z_max) { z_max = (segment->mdtHOT()[k])->localPosition().z(); }
844 }
845 for (unsigned int k = 0; k < segment->mdtCloseHits(); k++) {
846 if ((segment->mdtClose()[k])->localPosition().y() < y_min) { y_min = (segment->mdtClose()[k])->localPosition().y(); }
847 if ((segment->mdtClose()[k])->localPosition().y() > y_max) { y_max = (segment->mdtClose()[k])->localPosition().y(); }
848 if ((segment->mdtClose()[k])->localPosition().z() < z_min) { z_min = (segment->mdtClose()[k])->localPosition().z(); }
849 if ((segment->mdtClose()[k])->localPosition().z() > z_max) { z_max = (segment->mdtClose()[k])->localPosition().z(); }
850 }
851
852 // write out the coordinate system //
853 if (y_max - y_min > z_max - z_min) {
854 outfile << "nullptr " << y_min - 30.0 << " " << y_max + 30.0 << " " << 0.5 * (z_min + z_max) - 0.5 * (y_max - y_min) - 30.0 << " "
855 << 0.5 * (z_min + z_max) + 0.5 * (y_max - y_min) + 30.0 << "\n";
856 } else {
857 outfile << "nullptr " << 0.5 * (y_min + y_max) - 0.5 * (z_max - z_min) - 30.0 << " "
858 << 0.5 * (y_min + y_max) + 0.5 * (z_max - z_min) + 30.0 << " " << z_min - 30.0 << " " << z_max + 30.0 << "\n";
859 }
860
861 // write out the hits on track //
862 for (unsigned int k = 0; k < segment->mdtHitsOnTrack(); k++) {
863 // draw a circle for the tube //
864 outfile << "SET PLCI 1\n"
865 << "ARC " << (segment->mdtHOT()[k])->localPosition().y() << " " << (segment->mdtHOT()[k])->localPosition().z() << " 15.0\n";
866
867 // draw a drift circle //
868 outfile << "SET PLCI 3\n"
869 << "ARC " << (segment->mdtHOT()[k])->localPosition().y() << " " << (segment->mdtHOT()[k])->localPosition().z() << " "
870 << (segment->mdtHOT()[k])->driftRadius() << "\n";
871 }
872
873 // write out the close hits //
874 for (unsigned int k = 0; k < segment->mdtCloseHits(); k++) {
875 // draw a circle for the tube //
876 outfile << "SET PLCI 1\n"
877 << "ARC " << (segment->mdtClose()[k])->localPosition().y() << " " << (segment->mdtClose()[k])->localPosition().z()
878 << " 15.0\n";
879
880 // draw a drift circle //
881 outfile << "SET PLCI 2\n"
882 << "ARC " << (segment->mdtClose()[k])->localPosition().y() << " " << (segment->mdtClose()[k])->localPosition().z() << " "
883 << (segment->mdtClose()[k])->driftRadius() << "\n";
884 }
885
886 // write out the reconstructed track //
887 // a straight line is drawn by default //
888 if (curved_segment == nullptr) {
889 MTStraightLine aux_track(segment->position(), segment->direction(), null, null);
890 outfile << "SET PLCI 4\n"
891 << "LINE " << aux_track.a_x2() * (z_min - 30.0) + aux_track.b_x2() << " " << z_min - 30.0 << " "
892 << aux_track.a_x2() * (z_max + 30.0) + aux_track.b_x2() << " " << z_max + 30.0 << "\n";
893 }
894
895 // a curved segment is drawn on demand //
896 if (curved_segment != nullptr) {
897 double step_size((60.0 + z_max - z_min) / 50.0);
898 for (double aux_z = z_min; aux_z <= z_max; aux_z = aux_z + step_size) {
899 outfile << "SET PLCI 4\n"
900 << "LINE " << curved_segment->getPointOnLine(aux_z).y() << " " << aux_z << " "
901 << curved_segment->getPointOnLine(aux_z + step_size).y() << " " << aux_z + step_size << "\n";
902 }
903 }
904
905 // add a wait statement //
906 outfile << "WAIT\n";
907
908 return;
909}
910std::shared_ptr<RtRelationLookUp> RtCalibrationCurved::performParabolicExtrapolation(const bool &min, const bool &max,
911 const IRtRelation &in_rt) {
913 // VARIABLES //
915 RtParabolicExtrapolation rt_extrapolator; // r-t extrapolator
916 std::shared_ptr<RtRelationLookUp> rt_low, rt_high; // pointers to the r-t relationships after extrapolation
917 std::vector<SamplePoint> add_fit_point; // additional r-t points used if r(0) or 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 =
931 std::make_shared<RtRelationLookUp>(rt_extrapolator.getRtWithParabolicExtrapolation(in_rt, 13., 15., 16., 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 != nullptr) {
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) {
954 if (in_rt.hasTmaxDiff()) { rt_low->SetTmaxDiff(in_rt.GetTmaxDiff()); }
955 return rt_low;
956 }
957 if (min) {
958 if (in_rt.hasTmaxDiff()) { rt_low->SetTmaxDiff(in_rt.GetTmaxDiff()); }
959 return rt_low;
960 }
961 if (in_rt.hasTmaxDiff() && rt_high) { rt_high->SetTmaxDiff(in_rt.GetTmaxDiff()); }
962 return rt_high;
963}
const boost::regex rr(r_r)
#define endmsg
#define F(x, y, z)
Definition MD5.cxx:112
Double_t RtCalibrationCurved_polfun(Double_t *x, Double_t *par)
#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.
Amg::Vector3D getPointOnLine(const double loc_z) const
get the point on the line a the local z coordinate "loc_z"
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
double GetTmaxDiff() const
return the difference in total dirft time between the two multilayers (ML1 - ML2)
Definition IRtRelation.h:40
bool hasTmaxDiff() const
Definition IRtRelation.h:42
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
Athena-independent part of the MdtCalibHit.
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::unique_ptr< TH2F > m_residuals_initial_all
std::unique_ptr< TH2F > m_driftTime_initial
bool converged() const
returns true, if the autocalibration has converged
int iteration() const
get the number of the current iteration
virtual MdtCalibOutputPtr getResults() const override
returns the final r-t relationship
void setEstimateRtAccuracy(const double acc)
set the estimated r-t accuracy =acc
std::unique_ptr< MultilayerRtDifference > m_multilayer_rt_difference
void setInput(const IMdtCalibrationOutput *rt_input) override
set the r-t relationship, the internal autocalibration objects are reset
int numberOfSegments() const
get the number of segments which were passed to the algorithm
std::unique_ptr< TH1F > m_pull_initial
bool smoothing() const
returns true, if the r-t relationship will be smoothened using the conventional autocalibration after...
void switch_off_control_histograms()
the algorithm does not produce controll histograms (this is the default)
std::unique_ptr< BaseFunction > m_base_function
bool handleSegment(MuonCalibSegment &seg)
analyse the segment "seg" (this method was required before MdtCalibInterfaces-00-01-06)
std::shared_ptr< RtCalibrationOutput > m_output
std::unique_ptr< TH2F > m_residuals_final
std::unique_ptr< TFile > m_tfile
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...
void noSmoothing()
do not smoothen the r-t relationship after convergence
void doNotForceMonotony()
do not force r(t) to be monotonically increasing
void init(const double rt_accuracy, const unsigned int &func_type, const unsigned int &ord, const bool &fix_min, const bool &fix_max, const int &max_it, bool do_parabolic_extrapolation, bool do_smoothing, bool do_multilayer_rt_scale)
std::vector< CLHEP::HepVector > m_U
std::unique_ptr< TH2F > m_residuals_initial
double reliability() const
get the reliability of the final r-t relationship: 0: no convergence yet 1: convergence,...
bool analyse(const MuonSegVec &seg)
perform the autocalibration with the segments acquired so far
void forceMonotony()
force r(t) to be monotonically increasing (this is default)
std::shared_ptr< RtRelationLookUp > performParabolicExtrapolation(const bool &min, const bool &max, const IRtRelation &in_rt)
std::unique_ptr< TH1F > m_nb_segment_hits
MdtCalibOutputPtr analyseSegments(const MuonSegVec &seg) override
perform the full autocalibration including iterations (required since MdtCalibInterfaces-00-01-06)
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...
std::unique_ptr< TH2F > m_driftTime_final
void doParabolicExtrapolation()
requires that parabolic extrapolation will be used for small and large radii
void doSmoothing()
requires that the r-t relationship will be smoothened using the conventional autocalibration after co...
std::unique_ptr< TH1F > m_cut_evolution
std::unique_ptr< CurvedPatRec > m_tracker
RtCalibrationCurved(const std::string &name)
Default constructor: r-t accuracy is set to 0.5 mm.
int numberOfSegmentsUsed() const
get the number of segments which are used in the autocalibration
void display_segment(MuonCalibSegment *segment, std::ofstream &outfile, const CurvedLine *curved_segment)
std::vector< CLHEP::HepVector > m_U_weighted
std::unique_ptr< TH2F > m_adc_vs_residual_final
std::shared_ptr< const IRtRelation > m_rt
std::shared_ptr< IRtRelation > m_rt_new
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
Eigen::Matrix< double, 3, 1 > Vector3D
IMessageSvc * getMessageSvc(bool quiet=false)
CscCalcPed - algorithm that finds the Cathode Strip Chamber pedestals from an RDO.
float RtScalePolynomial(const float r)
Definition dot.py:1