195 {
199 const EventContext& ctx{Gaudi::Hive::currentContext()};
200 SG::ReadCondHandle<MuonCalib::MdtCalibDataContainer> calibData{
m_calibDbKey, ctx};
203 return false;
204 }
205 std::array<const MuonCalib::MdtRtRelation*, 2> rtRelations{};
206 {
207 unsigned int nRel{0};
208 for (
unsigned int i = 0;
i < dcs.size() ; ++
i) {
209 const Identifier
id = dcs[
i].rot()->identify();
210 const int mlIdx = id_helper.
multilayer(
id) -1;
211 if (rtRelations[mlIdx]) continue;
212 rtRelations[mlIdx] = calibData->getCalibData(id, msgStream())->rtRelation.get();
213 ++nRel;
214 if (nRel == 2) break;
215 }
216 }
218
219 unsigned int N = dcs_keep.size();
220
221 result.setT0Shift(-99999,-99999);
222
223 if(N<2) {
224 return false;
225 }
228 ATH_MSG_ERROR(
"MdtSegmentT0Fitter.cxx:fit with t0 <bad HitSelection>");
229 return false;
230 }
232 int used=0;
233 for(
unsigned int i=0;
i<
N;++
i){
235 }
236 if(used < 2){
238 return false;
239 }
241
244
245
246
247
248
249
251 dcs_new.reserve(dcs.size());
252
253 double chi2p = 0.;
254 int n_elements = dcs.size();
255 for(
int i=0;
i< n_elements; ++
i ){
256 const DriftCircle*
ds = & dcs[
i];
257 if(std::abs(
ds->r()-
ds->rot()->driftRadius())>
m_dRTol)
ATH_MSG_DEBUG(
"Different radii on dc " <<
ds->r() <<
" rot " <<
ds->rot()->driftRadius());
258
259 DriftCircle dc_keep(
ds->position(),
ds->rot()->driftRadius(),
ds->dr(),
ds->drPrecise(),
ds->driftState(),
ds->id(),
ds->rot(),
ds->index());
260 DCOnTrack dc_new(dc_keep, 0., 0.);
261
262 dc_new.state(dcs[i].state());
263 dcs_new.push_back( dc_new );
265 double t =
ds->rot()->driftTime();
266 const unsigned int mlIdx = id_helper.
multilayer(
ds->rot()->identify()) - 1;
267 const MuonCalib::MdtRtRelation *rtInfo = rtRelations[mlIdx];
268
269 double tUp = rtInfo->
rt()->
tUpper();
270 double tLow = rtInfo->
rt()->
tLower();
271
272 if(t<tLow) chi2p +=
sq(t-tLow)*0.1;
273 else if(t>tUp) chi2p +=
sq(t-tUp)*0.1;
274 }
275 }
276
277 if(chi2p>0)
ATH_MSG_DEBUG(
"NO Minuit Fit TOO few hits Chi2 penalty " << chi2p);
278
280
282
284 int iok = 0;
285 if(oldrefit) iok = 1;
287 return oldrefit;
288
289 }
290
292
293
295
296
297 ATH_MSG_DEBUG(
" in MdtSegmentT0Fitter::fit with N dcs "<< N <<
" hit selection size " <<
selection.size());
299
300
301 double Zc{0.}, Yc{0.},
S{0.}, Sz{0.}, Sy{0};
302
303 std::vector<HitCoords>
hits{};
305 FunctionToMinimize minFunct(used);
306
307 {
308 unsigned int ii{0};
309 for(const DCOnTrack& keep_me : dcs_keep ){
310 const Muon::MdtDriftCircleOnTrack *roto = keep_me.rot();
312 const MuonCalib::MdtRtRelation *rtInfo = rtRelations[mlIdx];
313
314 const double newerror =
m_scaleErrors ? keep_me.drPrecise() : keep_me.dr();
315 const double w = newerror >0. ?
sq(1./newerror) : 0.;
317 HitCoords& coords =
hits.back();
318 coords.dr = keep_me.dr();
320 ATH_MSG_DEBUG(
"DC: (" << coords.y <<
"," << coords.z <<
") R = " << coords.r <<
" W " << coords.w
321 <<" t " <<coords.t<< " id: "<<keep_me.id()<<" sel " <<coords.rejected);
322 if (!coords.rejected) {
324 Sz+= coords.z* coords.w;
325 Sy+= coords.y * coords.w;
326 }
327 ++ii;
328 }
329 }
330
332 const double inv_S = 1. /
S;
334 Yc = Sy*inv_S;
335
337
339 for(HitCoords& coords : hits) {
340 coords.y -= Yc;
342 }
343
344 int selcount{0};
345
346
347
348
349 double min_tlower{std::numeric_limits<float>::max()}, max_tupper{-std::numeric_limits<float>::max()};
350
351 double t0seed=0;
352 double st0 = 0;
353 double min_t0 = 1e10;
354
355 for(HitCoords& coords : hits) {
356 if(coords.rejected) continue;
357
358 double r2tval = r2t_ext(coords.rt, coords.r) ;
359 const double tl = coords.rt->
tLower();
360 const double th = coords.rt->
tUpper();
361 const double tee0 = coords.t - r2tval;
362
363 min_tlower = std::min(min_tlower, coords.t - tl);
364 max_tupper = std::max(max_tupper, coords.t - th);
365
366
367 ATH_MSG_DEBUG(
" z "<<coords.z <<
" y "<<coords.y<<
" r "<<coords.r
368 <<" t "<<coords.t<<" t0 "<<tee0<<" tLower "<<tl<<" tUpper "<<th);
369 t0seed += tee0;
371 if(tee0 < min_t0 && std::abs(r2tval) < R2TSPURIOUS) min_t0 = tee0;
372
373 minFunct.addCoords(coords);
374
375 selcount++;
376
377 }
378 t0seed /= selcount;
379 st0 = st0/selcount - t0seed*t0seed;
380 st0 = st0 > 0. ? std::sqrt(st0) : 0.;
381
382 ATH_MSG_DEBUG(
" t0seed "<<t0seed<<
" sigma "<<st0<<
" min_t0 "<<min_t0);
383
384
386 double cosin = std::cos(
theta);
387 double sinus = std::sin(
theta);
388
389 if ( sinus < 0.0 ) {
390 sinus = -sinus;
391 cosin = -cosin;
392 } else if ( sinus == 0.0 && cosin < 0.0 ) {
393 cosin = -cosin;
394 }
395
397
398 double d =
line.y0() +
Zc*sinus-Yc*cosin;
399
400
405
406
407
408 int nml1p{0}, nml2p{0}, nml1n{0}, nml2n{0};
409 int ii{-1};
410 for(const DCOnTrack& keep_me : dcs_keep){
411 ++ii;
412 const HitCoords& coords =
hits[ii];
413 if(coords.rejected) continue;
414 const double sdist =
d*cosin + coords.z*sinus - coords.y*cosin;
415 nml1p+=(keep_me.id().ml()==0&&sdist > 0);
416 nml1n+=(keep_me.id().ml()==0&&sdist < 0);
417 nml2p+=(keep_me.id().ml()==1&&sdist > 0);
418 nml2n+=(keep_me.id().ml()==1&&sdist < 0);
419 }
420
421
422 int t0Error = STRONG_TOPO_T0ERROR;
423 if (nml1p+nml2p < 2 || nml1n+nml2n < 2) t0Error = WEAK_TOPO_T0ERROR;
424
425 minFunct.setT0Error(t0Error);
426
427
429 ATH_MSG_DEBUG(
"Combination rejected for positive radii ML1 " << nml1p <<
" ML2 " << nml2p <<
" negative radii ML1 " << nml1n <<
" ML " << nml2n <<
" used hits " << used <<
" t0 Error " << t0Error);
430 DCOnTrackVec::const_iterator
it = dcs.begin();
431 DCOnTrackVec::const_iterator it_end = dcs.end();
432 double chi2p = 0.;
434 dcs_new.reserve(dcs.size());
435 for(
int i=0;
it!=it_end; ++
it, ++
i ){
436 const DriftCircle*
ds = & dcs[
i];
437 if(std::abs(
ds->r()-
ds->rot()->driftRadius())>
m_dRTol)
ATH_MSG_DEBUG(
"Different radii on dc " <<
ds->r() <<
" rot " <<
ds->rot()->driftRadius());
438 DriftCircle dc_keep(
ds->position(),
ds->rot()->driftRadius(),
ds->dr(),
ds->drPrecise(),
ds->driftState(),
ds->id(),
ds->rot(),
ds->index() );
439 DCOnTrack dc_new(dc_keep, 0., 0.);
440 dc_new.state(dcs[i].state());
441 dcs_new.push_back( std::move(dc_new) );
443 double t =
ds->rot()->driftTime();
444 const unsigned int mlIdx = id_helper.
multilayer(
ds->rot()->identify()) - 1;
445 const MuonCalib::MdtRtRelation *rtInfo = rtRelations[mlIdx];
446 double tUp = rtInfo->
rt()->
tUpper();
447 double tLow = rtInfo->
rt()->
tLower();
448 if(t<tLow) chi2p +=
sq(t-tLow)*0.1;
449 if(t>tUp) chi2p +=
sq(t-tUp)*0.1;
450 }
451 }
452 if(chi2p>0)
ATH_MSG_DEBUG(
" Rejected weak topology Chi2 penalty " << chi2p);
455
457 return oldrefit;
458 }
459
460 ATH_MSG_DEBUG(
"positive radii ML1 " << nml1p <<
" ML2 " << nml2p <<
" negative radii ML1 " << nml1n <<
" ML " << nml2n <<
" used hits " << used <<
" t0 Error " << t0Error);
461
462 constexpr std::array<Double_t,3>
step{0.01 , 0.01 , 0.1 };
463
465
466 if(t0Seed > -999.)
variable[2] = t0Seed;
467
468 ROOT::Minuit2::Minuit2Minimizer minimum("algoName");
469 minimum.SetMaxFunctionCalls(10000);
470 minimum.SetTolerance(0.001);
471 minimum.SetPrintLevel(-1);
472 if(
msgLvl(MSG::VERBOSE)) minimum.SetPrintLevel(1);
473
475 minimum.SetVariable(0,"a",variable[0], step[0]);
476 minimum.SetVariable(1,"b",variable[1], step[1]);
477 } else {
478 minimum.SetFixedVariable(0,"a", variable[0]);
479 minimum.SetFixedVariable(1,"b", variable[1]);
480 }
481
482 minimum.SetVariable(2,"t0",variable[2], step[2]);
483
484 minimum.SetFunction(minFunct);
485
486
487
488
489
490 {
491
492 CxxUtils::FPControl ctl;
493 ctl.disable (CxxUtils::FPControl::Exc::divbyzero);
494 ctl.disable (CxxUtils::FPControl::Exc::invalid);
495
496
497
498 const bool minuit_succedded = minimum.Minimize();
499 const int minuitStatus = minimum.Status();
500 if (!minuit_succedded || minuitStatus != 0) {
501 ATH_MSG_DEBUG(
"Minuit fit failed with status " << minuitStatus);
502 return false;
503 }
504
505 }
506
507 const double *
results = minimum.X();
508 const double *
errors = minimum.Errors();
509 ATH_MSG_DEBUG(
"Minimum: f(" << results[0] <<
"+-" << errors[0] <<
"," << results[1]<<
"+-" << errors[1]<<
"," << results[2] <<
"+-" << errors[2]<<
"): " << minimum.MinValue());
510
512
513
516 double dtheta = aErr;
517 double tana = std::tan(aret);
518 double ang = aret;
519 cosin = std::cos(ang);
520 sinus = std::sin(ang);
521 if ( sinus < 0.0 ) {
522 sinus = -sinus;
523 cosin = -cosin;
524 } else if ( sinus == 0.0 && cosin < 0.0 ) {
525 cosin = -cosin;
526 }
527 ang = std::atan2(sinus, cosin);
532 double dy0 = cosin * bErr -
b * sinus * aErr;
533
534 const double del_t = std::abs(hits[0].rt->radius((
t0+t0Err)) - hits[0].rt->radius(
t0)) ;
535
536
539 ATH_MSG_DEBUG(
"Errors: a "<<aErr<<
" b "<<dy0 <<
" t0 "<<t0Err);
540
543 msg() << MSG::DEBUG <<
"COVAR ";
544 for(int it1=0; it1<3; it1++) {
545 for(int it2=0; it2<3; it2++) {
546 msg() << MSG::DEBUG <<minimum.CovMatrix(it1,it2)<<
" ";
547 }
549 }
550 }
551
553 result.clusters().clear();
554 result.emptyTubes().clear();
555
556 ATH_MSG_DEBUG(
"after fit theta "<<ang<<
" sinus "<<sinus<<
" cosin "<< cosin);
557
559 unsigned int nhits(0);
560
561
562
565 for(const HitCoords& coords : hits){
567 const DCOnTrack& keep_me{dcs_keep[
i]};
568 const double uppercut = coords.rt->
tUpper();
569 const double lowercut = coords.rt->
tLower();
570
572 if(coords.t-
t0<lowercut)
rad = coords.rt->
radius(lowercut);
573 if(coords.t-
t0>uppercut)
rad = coords.rt->
radius(uppercut);
574 if (coords.w==0) {
576 continue;
577 }
578 double drad = 1.0/std::sqrt(coords.w) ;
579
580 double yl = (coords.y - tana*coords.z -
b);
581
583
584
585 double dth = -(sinus*coords.y + cosin*coords.z)*dtheta;
586 double residuals = std::abs(yl)/std::sqrt(1+tana*tana) -
rad;
587
589
590
591 double errorResiduals = std::hypot(dth, dy0, del_t);
592
593
594 std::array<double,3> deriv{};
595
596 double dd = coords.z * sinus +
b *cosin - coords.y * cosin;
597 deriv[0] =
sign(dd) * (coords.z * cosin -
b * sinus + coords.y * sinus);
598
599 deriv[1] =
sign(dd) * cosin ;
600
601
603
604 double covsq=0;
605 for(
int rr=0;
rr<3;
rr++) {
606 for(
int cc=0;
cc<3;
cc++) {
607 covsq += deriv[
rr]*minimum.CovMatrix(
rr,cc)* deriv[
cc];
608 }
609 }
611 if( covsq < 0. &&
msgLvl(MSG::DEBUG)){
612 for(
int rr=0;
rr<3;
rr++) {
613 for(
int cc=0;
cc<3;
cc++) {
614 double dot = deriv[
rr]*minimum.CovMatrix(
rr,cc)* deriv[
cc];
615 ATH_MSG_DEBUG(
" adding term " << dot <<
" dev1 " << deriv[
rr] <<
" cov " << minimum.CovMatrix(
rr,cc) <<
" dev2 " << deriv[cc]);
616 }
617 }
618 }
619
620 covsq = covsq > 0. ? std::sqrt(covsq) : 0.;
621 const DriftCircle*
ds = & keep_me;
623
624 DriftCircle dc_newrad(keep_me.position(), rad, drad,
ds->driftState(), keep_me.id(),
ds->rot(), keep_me.index() );
625 DCOnTrack dc_new(dc_newrad, residuals, covsq);
626 dc_new.state(keep_me.state());
627
628 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);
629
630 if(!coords.rejected) {
631 ++nhits;
633 chi2 +=
sq(residuals)*coords.w;
634 } else {
636 }
637 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);
638
639 if (coords.t-
t0> uppercut ) {
640 chi2 +=
sq(coords.t-
t0-uppercut)*0.1;
641 }
else if (coords.t-
t0 < lowercut ) {
642 chi2 +=
sq(coords.t-
t0-lowercut)*0.1;
643 }
644 }
645 result.dcs().push_back( dc_new );
646 }
647
648 double oldshift =
result.t0Shift();
650
651 if(nhits==NUMPAR) {
652 nhits++;
654 }
655 result.set(
chi2, nhits-NUMPAR, dtheta, -1.*dy0 );
656 result.line().set( LocVec2D( Zc - sinus*d, Yc + cosin*d ), ang );
657 if(
t0==0.)
t0=0.00001;
659
660 ATH_MSG_DEBUG(
"Minuit Fit complete: Chi2 " <<
chi2 <<
" angle " <<
result.line().phi() <<
" nhits "<< nhits <<
" t0result " <<
t0);
661 ATH_MSG_DEBUG(
"Minuit Fit complete: Chi2 " <<
chi2 <<
" angle " <<
result.line().phi() <<
" nhits "<<nhits<<
" numpar "<<NUMPAR <<
" per dof " <<
chi2/(nhits-NUMPAR));
662 ATH_MSG_DEBUG(
"Fit complete: Chi2 " <<
chi2 <<
" nhits "<<nhits<<
" numpar "<<NUMPAR <<
" per dof " <<
chi2/(nhits-NUMPAR)<<(
chi2/(nhits-NUMPAR) > 5 ?
" NOT ":
" ")<<
"GOOD");
664
665 return true;
666 }
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
@ Zc
Z -> cc, nC = 1 (partial containment).
std::vector< DCOnTrack > DCOnTrackVec
dot(G, fn, nodesToHighlight=[])