193 {
197 const EventContext& ctx{Gaudi::Hive::currentContext()};
198 SG::ReadCondHandle<MuonCalib::MdtCalibDataContainer> calibData{
m_calibDbKey, ctx};
201 return false;
202 }
203 std::array<const MuonCalib::MdtRtRelation*, 2> rtRelations{};
204 {
205 unsigned int nRel{0};
206 for (
unsigned int i = 0;
i < dcs.size() ; ++
i) {
207 const Identifier
id = dcs[
i].rot()->identify();
208 const int mlIdx = id_helper.
multilayer(
id) -1;
209 if (rtRelations[mlIdx]) continue;
210 rtRelations[mlIdx] = calibData->getCalibData(id, msgStream())->rtRelation.get();
211 ++nRel;
212 if (nRel == 2) break;
213 }
214 }
216
217 unsigned int N = dcs_keep.size();
218
219 result.setT0Shift(-99999,-99999);
220
221 if(N<2) {
222 return false;
223 }
226 ATH_MSG_ERROR(
"MdtSegmentT0Fitter.cxx:fit with t0 <bad HitSelection>");
227 return false;
228 }
230 int used=0;
231 for(
unsigned int i=0;
i<
N;++
i){
233 }
234 if(used < 2){
236 return false;
237 }
239
242
243
244
245
246
247
249 dcs_new.reserve(dcs.size());
250
251 double chi2p = 0.;
252 int n_elements = dcs.size();
253 for(
int i=0;
i< n_elements; ++
i ){
254 const DriftCircle*
ds = & dcs[
i];
255 if(std::abs(
ds->r()-
ds->rot()->driftRadius())>
m_dRTol)
ATH_MSG_DEBUG(
"Different radii on dc " <<
ds->r() <<
" rot " <<
ds->rot()->driftRadius());
256
257 DriftCircle dc_keep(
ds->position(),
ds->rot()->driftRadius(),
ds->dr(),
ds->drPrecise(),
ds->driftState(),
ds->id(),
ds->rot(),
ds->index());
258 DCOnTrack dc_new(dc_keep, 0., 0.);
259
260 dc_new.state(dcs[i].state());
261 dcs_new.push_back( dc_new );
263 double t =
ds->rot()->driftTime();
264 const unsigned int mlIdx = id_helper.
multilayer(
ds->rot()->identify()) - 1;
265 const MuonCalib::MdtRtRelation *rtInfo = rtRelations[mlIdx];
266
267 double tUp = rtInfo->
rt()->
tUpper();
268 double tLow = rtInfo->
rt()->
tLower();
269
270 if(t<tLow) chi2p +=
sq(t-tLow)*0.1;
271 else if(t>tUp) chi2p +=
sq(t-tUp)*0.1;
272 }
273 }
274
275 if(chi2p>0)
ATH_MSG_DEBUG(
"NO Minuit Fit TOO few hits Chi2 penalty " << chi2p);
276
278
280
282 int iok = 0;
283 if(oldrefit) iok = 1;
285 return oldrefit;
286
287 }
288
290
291
293
294
295 ATH_MSG_DEBUG(
" in MdtSegmentT0Fitter::fit with N dcs "<< N <<
" hit selection size " <<
selection.size());
297
298
299 double Zc{0.}, Yc{0.},
S{0.}, Sz{0.}, Sy{0};
300
301 std::vector<HitCoords>
hits{};
303 FunctionToMinimize minFunct(used);
304
305 {
306 unsigned int ii{0};
307 for(const DCOnTrack& keep_me : dcs_keep ){
308 const Muon::MdtDriftCircleOnTrack *roto = keep_me.rot();
310 const MuonCalib::MdtRtRelation *rtInfo = rtRelations[mlIdx];
311
312 const double newerror =
m_scaleErrors ? keep_me.drPrecise() : keep_me.dr();
313 const double w = newerror >0. ?
sq(1./newerror) : 0.;
315 HitCoords& coords =
hits.back();
316 coords.dr = keep_me.dr();
318 ATH_MSG_DEBUG(
"DC: (" << coords.y <<
"," << coords.z <<
") R = " << coords.r <<
" W " << coords.w
319 <<" t " <<coords.t<< " id: "<<keep_me.id()<<" sel " <<coords.rejected);
320 if (!coords.rejected) {
322 Sz+= coords.z* coords.w;
323 Sy+= coords.y * coords.w;
324 }
325 ++ii;
326 }
327 }
328
330 const double inv_S = 1. /
S;
331 Zc = Sz*inv_S;
332 Yc = Sy*inv_S;
333
335
337 for(HitCoords& coords : hits) {
338 coords.y -= Yc;
339 coords.z -= Zc;
340 }
341
342 int selcount{0};
343
344
345
346
347 double min_tlower{std::numeric_limits<float>::max()}, max_tupper{-std::numeric_limits<float>::max()};
348
349 double t0seed=0;
350 double st0 = 0;
351 double min_t0 = 1e10;
352
353 for(HitCoords& coords : hits) {
354 if(coords.rejected) continue;
355
356 double r2tval = r2t_ext(coords.rt, coords.r) ;
357 const double tl = coords.rt->
tLower();
358 const double th = coords.rt->
tUpper();
359 const double tee0 = coords.t - r2tval;
360
361 min_tlower = std::min(min_tlower, coords.t - tl);
362 max_tupper = std::max(max_tupper, coords.t - th);
363
364
365 ATH_MSG_DEBUG(
" z "<<coords.z <<
" y "<<coords.y<<
" r "<<coords.r
366 <<" t "<<coords.t<<" t0 "<<tee0<<" tLower "<<tl<<" tUpper "<<th);
367 t0seed += tee0;
369 if(tee0 < min_t0 && std::abs(r2tval) < R2TSPURIOUS) min_t0 = tee0;
370
371 minFunct.addCoords(coords);
372
373 selcount++;
374
375 }
376 t0seed /= selcount;
377 st0 = st0/selcount - t0seed*t0seed;
378 st0 = st0 > 0. ? std::sqrt(st0) : 0.;
379
380 ATH_MSG_DEBUG(
" t0seed "<<t0seed<<
" sigma "<<st0<<
" min_t0 "<<min_t0);
381
382
384 double cosin = std::cos(
theta);
385 double sinus = std::sin(
theta);
386
387 if ( sinus < 0.0 ) {
388 sinus = -sinus;
389 cosin = -cosin;
390 } else if ( sinus == 0.0 && cosin < 0.0 ) {
391 cosin = -cosin;
392 }
393
395
396 double d =
line.y0() + Zc*sinus-Yc*cosin;
397
398
403
404
405
406 int nml1p{0}, nml2p{0}, nml1n{0}, nml2n{0};
407 int ii{-1};
408 for(const DCOnTrack& keep_me : dcs_keep){
409 ++ii;
410 const HitCoords& coords =
hits[ii];
411 if(coords.rejected) continue;
412 const double sdist =
d*cosin + coords.z*sinus - coords.y*cosin;
413 nml1p+=(keep_me.id().ml()==0&&sdist > 0);
414 nml1n+=(keep_me.id().ml()==0&&sdist < 0);
415 nml2p+=(keep_me.id().ml()==1&&sdist > 0);
416 nml2n+=(keep_me.id().ml()==1&&sdist < 0);
417 }
418
419
420 int t0Error = STRONG_TOPO_T0ERROR;
421 if (nml1p+nml2p < 2 || nml1n+nml2n < 2) t0Error = WEAK_TOPO_T0ERROR;
422
423 minFunct.setT0Error(t0Error);
424
425
427 ATH_MSG_DEBUG(
"Combination rejected for positive radii ML1 " << nml1p <<
" ML2 " << nml2p <<
" negative radii ML1 " << nml1n <<
" ML " << nml2n <<
" used hits " << used <<
" t0 Error " << t0Error);
428 DCOnTrackVec::const_iterator
it = dcs.begin();
429 DCOnTrackVec::const_iterator it_end = dcs.end();
430 double chi2p = 0.;
432 dcs_new.reserve(dcs.size());
433 for(
int i=0;
it!=it_end; ++
it, ++
i ){
434 const DriftCircle*
ds = & dcs[
i];
435 if(std::abs(
ds->r()-
ds->rot()->driftRadius())>
m_dRTol)
ATH_MSG_DEBUG(
"Different radii on dc " <<
ds->r() <<
" rot " <<
ds->rot()->driftRadius());
436 DriftCircle dc_keep(
ds->position(),
ds->rot()->driftRadius(),
ds->dr(),
ds->drPrecise(),
ds->driftState(),
ds->id(),
ds->rot(),
ds->index() );
437 DCOnTrack dc_new(dc_keep, 0., 0.);
438 dc_new.state(dcs[i].state());
439 dcs_new.push_back( std::move(dc_new) );
441 double t =
ds->rot()->driftTime();
442 const unsigned int mlIdx = id_helper.
multilayer(
ds->rot()->identify()) - 1;
443 const MuonCalib::MdtRtRelation *rtInfo = rtRelations[mlIdx];
444 double tUp = rtInfo->
rt()->
tUpper();
445 double tLow = rtInfo->
rt()->
tLower();
446 if(t<tLow) chi2p +=
sq(t-tLow)*0.1;
447 if(t>tUp) chi2p +=
sq(t-tUp)*0.1;
448 }
449 }
450 if(chi2p>0)
ATH_MSG_DEBUG(
" Rejected weak topology Chi2 penalty " << chi2p);
453
455 return oldrefit;
456 }
457
458 ATH_MSG_DEBUG(
"positive radii ML1 " << nml1p <<
" ML2 " << nml2p <<
" negative radii ML1 " << nml1n <<
" ML " << nml2n <<
" used hits " << used <<
" t0 Error " << t0Error);
459
460 constexpr std::array<Double_t,3>
step{0.01 , 0.01 , 0.1 };
461
463
464 if(t0Seed > -999.)
variable[2] = t0Seed;
465
466 ROOT::Minuit2::Minuit2Minimizer minimum("algoName");
467 minimum.SetMaxFunctionCalls(10000);
468 minimum.SetTolerance(0.001);
469 minimum.SetPrintLevel(-1);
470 if(
msgLvl(MSG::VERBOSE)) minimum.SetPrintLevel(1);
471
473 minimum.SetVariable(0,"a",variable[0], step[0]);
474 minimum.SetVariable(1,"b",variable[1], step[1]);
475 } else {
476 minimum.SetFixedVariable(0,"a", variable[0]);
477 minimum.SetFixedVariable(1,"b", variable[1]);
478 }
479
480 minimum.SetVariable(2,"t0",variable[2], step[2]);
481
482 minimum.SetFunction(minFunct);
483
484
485 minimum.Minimize();
486
487 const double *
results = minimum.X();
488 const double *
errors = minimum.Errors();
489 ATH_MSG_DEBUG(
"Minimum: f(" << results[0] <<
"+-" << errors[0] <<
"," << results[1]<<
"+-" << errors[1]<<
"," << results[2] <<
"+-" << errors[2]<<
"): " << minimum.MinValue());
490
492
493
496 double dtheta = aErr;
497 double tana = std::tan(aret);
498 double ang = aret;
499 cosin = std::cos(ang);
500 sinus = std::sin(ang);
501 if ( sinus < 0.0 ) {
502 sinus = -sinus;
503 cosin = -cosin;
504 } else if ( sinus == 0.0 && cosin < 0.0 ) {
505 cosin = -cosin;
506 }
507 ang = std::atan2(sinus, cosin);
512 double dy0 = cosin * bErr -
b * sinus * aErr;
513
514 const double del_t = std::abs(hits[0].rt->radius((
t0+t0Err)) - hits[0].rt->radius(
t0)) ;
515
516
519 ATH_MSG_DEBUG(
"Errors: a "<<aErr<<
" b "<<dy0 <<
" t0 "<<t0Err);
520
523 msg() << MSG::DEBUG <<
"COVAR ";
524 for(int it1=0; it1<3; it1++) {
525 for(int it2=0; it2<3; it2++) {
526 msg() << MSG::DEBUG <<minimum.CovMatrix(it1,it2)<<
" ";
527 }
529 }
530 }
531
533 result.clusters().clear();
534 result.emptyTubes().clear();
535
536 ATH_MSG_DEBUG(
"after fit theta "<<ang<<
" sinus "<<sinus<<
" cosin "<< cosin);
537
539 unsigned int nhits(0);
540
541
542
545 for(const HitCoords& coords : hits){
547 const DCOnTrack& keep_me{dcs_keep[
i]};
548 const double uppercut = coords.rt->
tUpper();
549 const double lowercut = coords.rt->
tLower();
550
552 if(coords.t-
t0<lowercut)
rad = coords.rt->
radius(lowercut);
553 if(coords.t-
t0>uppercut)
rad = coords.rt->
radius(uppercut);
554 if (coords.w==0) {
556 continue;
557 }
558 double drad = 1.0/std::sqrt(coords.w) ;
559
560 double yl = (coords.y - tana*coords.z -
b);
561
563
564
565 double dth = -(sinus*coords.y + cosin*coords.z)*dtheta;
566 double residuals = std::abs(yl)/std::sqrt(1+tana*tana) -
rad;
567
569
570
571 double errorResiduals = std::hypot(dth, dy0, del_t);
572
573
574 std::array<double,3> deriv{};
575
576 double dd = coords.z * sinus +
b *cosin - coords.y * cosin;
577 deriv[0] =
sign(dd) * (coords.z * cosin -
b * sinus + coords.y * sinus);
578
579 deriv[1] =
sign(dd) * cosin ;
580
581
583
584 double covsq=0;
585 for(
int rr=0;
rr<3;
rr++) {
586 for(
int cc=0;
cc<3;
cc++) {
587 covsq += deriv[
rr]*minimum.CovMatrix(
rr,cc)* deriv[
cc];
588 }
589 }
591 if( covsq < 0. &&
msgLvl(MSG::DEBUG)){
592 for(
int rr=0;
rr<3;
rr++) {
593 for(
int cc=0;
cc<3;
cc++) {
594 double dot = deriv[
rr]*minimum.CovMatrix(
rr,cc)* deriv[
cc];
595 ATH_MSG_DEBUG(
" adding term " << dot <<
" dev1 " << deriv[
rr] <<
" cov " << minimum.CovMatrix(
rr,cc) <<
" dev2 " << deriv[cc]);
596 }
597 }
598 }
599
600 covsq = covsq > 0. ? std::sqrt(covsq) : 0.;
601 const DriftCircle*
ds = & keep_me;
603
604 DriftCircle dc_newrad(keep_me.position(), rad, drad,
ds->driftState(), keep_me.id(),
ds->rot(), keep_me.index() );
605 DCOnTrack dc_new(dc_newrad, residuals, covsq);
606 dc_new.state(keep_me.state());
607
608 ATH_MSG_DEBUG(
"T0 Segment hit res "<<residuals<<
" eres "<<errorResiduals<<
" covsq "<<covsq<<
" ri " << coords.r<<
" ro "<<rad<<
" drad "<<drad <<
" sel "<<
selection[i]<<
" inv error " << coords.w);
609
610 if(!coords.rejected) {
611 ++nhits;
613 chi2 +=
sq(residuals)*coords.w;
614 } else {
616 }
617 ATH_MSG_DEBUG(
"T0 Segment hit res "<<residuals<<
" eres "<<errorResiduals<<
" covsq "<<covsq<<
" ri " << coords.r<<
" radius after t0 "<<rad<<
" radius error "<< drad <<
" original error " << coords.dr);
618
619 if (coords.t-
t0> uppercut ) {
620 chi2 +=
sq(coords.t-
t0-uppercut)*0.1;
621 }
else if (coords.t-
t0 < lowercut ) {
622 chi2 +=
sq(coords.t-
t0-lowercut)*0.1;
623 }
624 }
625 result.dcs().push_back( dc_new );
626 }
627
628 double oldshift =
result.t0Shift();
630
631 if(nhits==NUMPAR) {
632 nhits++;
634 }
635 result.set(
chi2, nhits-NUMPAR, dtheta, -1.*dy0 );
636 result.line().set( LocVec2D( Zc - sinus*d, Yc + cosin*d ), ang );
637 if(
t0==0.)
t0=0.00001;
639
640 ATH_MSG_DEBUG(
"Minuit Fit complete: Chi2 " <<
chi2 <<
" angle " <<
result.line().phi() <<
" nhits "<< nhits <<
" t0result " <<
t0);
641 ATH_MSG_DEBUG(
"Minuit Fit complete: Chi2 " <<
chi2 <<
" angle " <<
result.line().phi() <<
" nhits "<<nhits<<
" numpar "<<NUMPAR <<
" per dof " <<
chi2/(nhits-NUMPAR));
642 ATH_MSG_DEBUG(
"Fit complete: Chi2 " <<
chi2 <<
" nhits "<<nhits<<
" numpar "<<NUMPAR <<
" per dof " <<
chi2/(nhits-NUMPAR)<<(
chi2/(nhits-NUMPAR) > 5 ?
" NOT ":
" ")<<
"GOOD");
644
645 return true;
646 }
const boost::regex rr(r_r)
Scalar theta() const
theta method
#define ATH_MSG_WARNING(x)
bool msgLvl(const MSG::Level lvl) const
int multilayer(const Identifier &id) const
Access to components of the ID.
virtual double tLower() const =0
Returns the lower time covered by the r-t.
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.
virtual double driftVelocity(double t) const =0
Returns the drift velocity for a given time.
const IRtRelation * rt() const
rt relation
double driftRadius() const
Returns the value of the drift radius.
double driftTime() const
Returns the value of the drift time used to obtain the drift radius.
virtual bool fit(Segment &result, const Line &line, const DCOnTrackVec &dcs, double t0Seed=-99999.) const
Gaudi::Property< bool > m_rejectWeakTopologies
Gaudi::Property< bool > m_floatDir
Gaudi::Property< int > m_minHits
Gaudi::Property< bool > m_scaleErrors
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Gaudi::Property< bool > m_propagateErrors
Gaudi::Property< float > m_dRTol
SG::ReadCondHandleKey< MuonCalib::MdtCalibDataContainer > m_calibDbKey
Identifier identify() const
return the identifier -extends MeasurementBase
double chi2(TH1 *h0, TH1 *h1)
const std::string selection
std::vector< DCOnTrack > DCOnTrackVec
dot(G, fn, nodesToHighlight=[])