199 const EventContext& ctx{Gaudi::Hive::currentContext()};
205 std::array<const MuonCalib::MdtRtRelation*, 2> rtRelations{};
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();
214 if (nRel == 2)
break;
219 unsigned int N = dcs_keep.size();
221 result.setT0Shift(-99999,-99999);
228 ATH_MSG_ERROR(
"MdtSegmentT0Fitter.cxx:fit with t0 <bad HitSelection>");
233 for(
unsigned int i=0;i<N;++i){
251 dcs_new.reserve(dcs.size());
254 int n_elements = dcs.size();
255 for(
int i=0; i< n_elements; ++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());
259 DriftCircle dc_keep(ds->position(), ds->rot()->driftRadius(), ds->dr(), ds->drPrecise(), ds->driftState(), ds->id(), ds->rot(), ds->index());
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;
269 double tUp = rtInfo->
rt()->
tUpper();
270 double tLow = rtInfo->
rt()->
tLower();
272 if(t<tLow) chi2p +=
sq(t-tLow)*0.1;
273 else if(t>tUp) chi2p +=
sq(t-tUp)*0.1;
277 if(chi2p>0)
ATH_MSG_DEBUG(
"NO Minuit Fit TOO few hits Chi2 penalty " << chi2p);
281 chi2p += result.chi2();
283 result.set(chi2p, result.ndof(), result.dtheta(), result.dy0());
285 if(oldrefit) iok = 1;
286 ATH_MSG_DEBUG(
" chi2 total " << result.chi2() <<
" angle " << result.line().phi() <<
" y0 " << result.line().y0() <<
" nhits "<<
selection.size() <<
" refit ok " << iok);
297 ATH_MSG_DEBUG(
" in MdtSegmentT0Fitter::fit with N dcs "<< N <<
" hit selection size " <<
selection.size());
298 ATH_MSG_DEBUG(
"in fit "<<result.hasT0Shift()<<
" " <<result.t0Shift());
301 double Zc{0.}, Yc{0.}, S{0.}, Sz{0.}, Sy{0};
303 std::vector<HitCoords> hits{};
305 FunctionToMinimize minFunct(
used);
309 for(
const DCOnTrack& keep_me : dcs_keep ){
314 const double newerror =
m_scaleErrors ? keep_me.drPrecise() : keep_me.dr();
315 const double w = newerror >0. ?
sq(1./newerror) : 0.;
316 hits.emplace_back(keep_me.x(), roto->
driftTime(), keep_me.y(), w, std::abs(roto->
driftRadius()), rtInfo->
rt());
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;
332 const double inv_S = 1. / S;
339 for(HitCoords& coords : hits) {
349 double min_tlower{std::numeric_limits<float>::max()}, max_tupper{-std::numeric_limits<float>::max()};
353 double min_t0 = 1e10;
355 for(HitCoords& coords : hits) {
356 if(coords.rejected)
continue;
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;
363 min_tlower = std::min(min_tlower, coords.t - tl);
364 max_tupper = std::max(max_tupper, coords.t - th);
367 ATH_MSG_DEBUG(
" z "<<coords.z <<
" y "<<coords.y<<
" r "<<coords.r
368 <<
" t "<<coords.t<<
" t0 "<<tee0<<
" tLower "<<tl<<
" tUpper "<<th);
371 if(tee0 < min_t0 && std::abs(r2tval) < R2TSPURIOUS) min_t0 = tee0;
373 minFunct.addCoords(coords);
379 st0 = st0/selcount - t0seed*t0seed;
380 st0 = st0 > 0. ? std::sqrt(st0) : 0.;
382 ATH_MSG_DEBUG(
" t0seed "<<t0seed<<
" sigma "<<st0<<
" min_t0 "<<min_t0);
385 const double theta = line.phi();
386 double cosin = std::cos(
theta);
387 double sinus = std::sin(
theta);
392 }
else if ( sinus == 0.0 && cosin < 0.0 ) {
398 double d = line.y0() + Zc*sinus-Yc*cosin;
401 ATH_MSG_DEBUG(
" line x y "<<line.position().x()<<
" "<<line.position().y());
408 int nml1p{0}, nml2p{0}, nml1n{0}, nml2n{0};
410 for(
const DCOnTrack& keep_me : dcs_keep){
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);
422 int t0Error = STRONG_TOPO_T0ERROR;
423 if (nml1p+nml2p < 2 || nml1n+nml2n < 2) t0Error = WEAK_TOPO_T0ERROR;
425 minFunct.setT0Error(t0Error);
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();
434 dcs_new.reserve(dcs.size());
435 for(
int i=0; it!=it_end; ++it, ++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() );
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;
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;
452 if(chi2p>0)
ATH_MSG_DEBUG(
" Rejected weak topology Chi2 penalty " << chi2p);
454 chi2p += result.chi2();
456 result.set( chi2p, result.ndof(), result.dtheta(), result.dy0() );
460 ATH_MSG_DEBUG(
"positive radii ML1 " << nml1p <<
" ML2 " << nml2p <<
" negative radii ML1 " << nml1n <<
" ML " << nml2n <<
" used hits " <<
used <<
" t0 Error " << t0Error);
462 constexpr std::array<Double_t,3> step{0.01 , 0.01 , 0.1 };
464 std::array<Double_t,3> variable{
theta,d,0};
466 if(t0Seed > -999.) variable[2] = t0Seed;
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);
475 minimum.SetVariable(0,
"a",variable[0], step[0]);
476 minimum.SetVariable(1,
"b",variable[1], step[1]);
478 minimum.SetFixedVariable(0,
"a", variable[0]);
479 minimum.SetFixedVariable(1,
"b", variable[1]);
482 minimum.SetVariable(2,
"t0",variable[2], step[2]);
484 minimum.SetFunction(minFunct);
492 CxxUtils::FPControl ctl;
493 ctl.disable (CxxUtils::FPControl::Exc::divbyzero);
494 ctl.disable (CxxUtils::FPControl::Exc::invalid);
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);
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());
514 double aret=results[0];
515 double aErr=errors[0];
516 double dtheta = aErr;
517 double tana = std::tan(aret);
519 cosin = std::cos(ang);
520 sinus = std::sin(ang);
524 }
else if ( sinus == 0.0 && cosin < 0.0 ) {
527 ang = std::atan2(sinus, cosin);
529 double bErr=errors[1];
530 double t0=results[2];
531 double t0Err=errors[2];
532 double dy0 = cosin * bErr - b * sinus * aErr;
534 const double del_t = std::abs(hits[0].rt->radius((
t0+t0Err)) - hits[0].rt->radius(
t0)) ;
539 ATH_MSG_DEBUG(
"Errors: a "<<aErr<<
" b "<<dy0 <<
" t0 "<<t0Err);
542 if(
msg().level() <=MSG::DEBUG) {
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)<<
" ";
552 result.dcs().clear();
553 result.clusters().clear();
554 result.emptyTubes().clear();
556 ATH_MSG_DEBUG(
"after fit theta "<<ang<<
" sinus "<<sinus<<
" cosin "<< cosin);
559 unsigned int nhits(0);
565 for(
const HitCoords& coords : hits){
568 const double uppercut = coords.rt->tUpper();
569 const double lowercut = coords.rt->tLower();
571 double rad = coords.rt->radius(coords.t-
t0);
572 if(coords.t-
t0<lowercut) rad = coords.rt->radius(lowercut);
573 if(coords.t-
t0>uppercut) rad = coords.rt->radius(uppercut);
578 double drad = 1.0/std::sqrt(coords.w) ;
580 double yl = (coords.y - tana*coords.z - b);
585 double dth = -(sinus*coords.y + cosin*coords.z)*dtheta;
586 double residuals = std::abs(yl)/std::sqrt(1+tana*tana) - rad;
591 double errorResiduals = std::hypot(dth, dy0, del_t);
594 std::array<double,3> deriv{};
596 double dd = coords.z * sinus + b *cosin - coords.y * cosin;
597 deriv[0] =
sign(dd) * (coords.z * cosin - b * sinus + coords.y * sinus);
599 deriv[1] =
sign(dd) * cosin ;
602 deriv[2] = -1* coords.rt->driftVelocity(coords.t-
t0);
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];
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]);
620 covsq = covsq > 0. ? std::sqrt(covsq) : 0.;
625 DCOnTrack dc_new(dc_newrad, residuals, covsq);
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);
630 if(!coords.rejected) {
633 chi2 +=
sq(residuals)*coords.w;
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);
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;
645 result.dcs().push_back( dc_new );
648 double oldshift = result.t0Shift();
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;
658 result.setT0Shift(
t0,t0Err);
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");