197 const EventContext& ctx{Gaudi::Hive::currentContext()};
203 std::array<const MuonCalib::MdtRtRelation*, 2> rtRelations{};
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();
212 if (nRel == 2)
break;
217 unsigned int N = dcs_keep.size();
219 result.setT0Shift(-99999,-99999);
226 ATH_MSG_ERROR(
"MdtSegmentT0Fitter.cxx:fit with t0 <bad HitSelection>");
231 for(
unsigned int i=0;i<N;++i){
249 dcs_new.reserve(dcs.size());
252 int n_elements = dcs.size();
253 for(
int i=0; i< n_elements; ++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());
257 DriftCircle dc_keep(ds->position(), ds->rot()->driftRadius(), ds->dr(), ds->drPrecise(), ds->driftState(), ds->id(), ds->rot(), ds->index());
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;
267 double tUp = rtInfo->
rt()->
tUpper();
268 double tLow = rtInfo->
rt()->
tLower();
270 if(t<tLow) chi2p +=
sq(t-tLow)*0.1;
271 else if(t>tUp) chi2p +=
sq(t-tUp)*0.1;
275 if(chi2p>0)
ATH_MSG_DEBUG(
"NO Minuit Fit TOO few hits Chi2 penalty " << chi2p);
283 if(oldrefit) iok = 1;
295 ATH_MSG_DEBUG(
" in MdtSegmentT0Fitter::fit with N dcs "<< N <<
" hit selection size " <<
selection.size());
299 double Zc{0.}, Yc{0.}, S{0.}, Sz{0.}, Sy{0};
301 std::vector<HitCoords> hits{};
303 FunctionToMinimize minFunct(
used);
307 for(
const DCOnTrack& keep_me : dcs_keep ){
312 const double newerror =
m_scaleErrors ? keep_me.drPrecise() : keep_me.dr();
313 const double w = newerror >0. ?
sq(1./newerror) : 0.;
314 hits.emplace_back(keep_me.x(), roto->
driftTime(), keep_me.y(), w, std::abs(roto->
driftRadius()), rtInfo->
rt());
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;
330 const double inv_S = 1. / S;
337 for(HitCoords& coords : hits) {
347 double min_tlower{std::numeric_limits<float>::max()}, max_tupper{-std::numeric_limits<float>::max()};
351 double min_t0 = 1e10;
353 for(HitCoords& coords : hits) {
354 if(coords.rejected)
continue;
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;
361 min_tlower = std::min(min_tlower, coords.t - tl);
362 max_tupper = std::max(max_tupper, coords.t - th);
365 ATH_MSG_DEBUG(
" z "<<coords.z <<
" y "<<coords.y<<
" r "<<coords.r
366 <<
" t "<<coords.t<<
" t0 "<<tee0<<
" tLower "<<tl<<
" tUpper "<<th);
369 if(tee0 < min_t0 && std::abs(r2tval) < R2TSPURIOUS) min_t0 = tee0;
371 minFunct.addCoords(coords);
377 st0 = st0/selcount - t0seed*t0seed;
378 st0 = st0 > 0. ? std::sqrt(st0) : 0.;
380 ATH_MSG_DEBUG(
" t0seed "<<t0seed<<
" sigma "<<st0<<
" min_t0 "<<min_t0);
383 const double theta = line.phi();
384 double cosin = std::cos(
theta);
385 double sinus = std::sin(
theta);
390 }
else if ( sinus == 0.0 && cosin < 0.0 ) {
396 double d = line.y0() + Zc*sinus-Yc*cosin;
399 ATH_MSG_DEBUG(
" line x y "<<line.position().x()<<
" "<<line.position().y());
406 int nml1p{0}, nml2p{0}, nml1n{0}, nml2n{0};
408 for(
const DCOnTrack& keep_me : dcs_keep){
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);
420 int t0Error = STRONG_TOPO_T0ERROR;
421 if (nml1p+nml2p < 2 || nml1n+nml2n < 2) t0Error = WEAK_TOPO_T0ERROR;
423 minFunct.setT0Error(t0Error);
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();
432 dcs_new.reserve(dcs.size());
433 for(
int i=0; it!=it_end; ++it, ++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() );
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;
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;
450 if(chi2p>0)
ATH_MSG_DEBUG(
" Rejected weak topology Chi2 penalty " << chi2p);
458 ATH_MSG_DEBUG(
"positive radii ML1 " << nml1p <<
" ML2 " << nml2p <<
" negative radii ML1 " << nml1n <<
" ML " << nml2n <<
" used hits " <<
used <<
" t0 Error " << t0Error);
460 constexpr std::array<Double_t,3> step{0.01 , 0.01 , 0.1 };
462 std::array<Double_t,3> variable{
theta,d,0};
464 if(t0Seed > -999.) variable[2] = t0Seed;
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);
473 minimum.SetVariable(0,
"a",variable[0], step[0]);
474 minimum.SetVariable(1,
"b",variable[1], step[1]);
476 minimum.SetFixedVariable(0,
"a", variable[0]);
477 minimum.SetFixedVariable(1,
"b", variable[1]);
480 minimum.SetVariable(2,
"t0",variable[2], step[2]);
482 minimum.SetFunction(minFunct);
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());
494 double aret=results[0];
495 double aErr=errors[0];
496 double dtheta = aErr;
497 double tana = std::tan(aret);
499 cosin = std::cos(ang);
500 sinus = std::sin(ang);
504 }
else if ( sinus == 0.0 && cosin < 0.0 ) {
507 ang = std::atan2(sinus, cosin);
509 double bErr=errors[1];
510 double t0=results[2];
511 double t0Err=errors[2];
512 double dy0 = cosin * bErr - b * sinus * aErr;
514 const double del_t = std::abs(hits[0].rt->radius((
t0+t0Err)) - hits[0].rt->radius(
t0)) ;
519 ATH_MSG_DEBUG(
"Errors: a "<<aErr<<
" b "<<dy0 <<
" t0 "<<t0Err);
522 if(
msg().level() <=MSG::DEBUG) {
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)<<
" ";
533 result.clusters().clear();
534 result.emptyTubes().clear();
536 ATH_MSG_DEBUG(
"after fit theta "<<ang<<
" sinus "<<sinus<<
" cosin "<< cosin);
539 unsigned int nhits(0);
545 for(
const HitCoords& coords : hits){
548 const double uppercut = coords.rt->tUpper();
549 const double lowercut = coords.rt->tLower();
551 double rad = coords.rt->radius(coords.t-
t0);
552 if(coords.t-
t0<lowercut) rad = coords.rt->radius(lowercut);
553 if(coords.t-
t0>uppercut) rad = coords.rt->radius(uppercut);
558 double drad = 1.0/std::sqrt(coords.w) ;
560 double yl = (coords.y - tana*coords.z - b);
565 double dth = -(sinus*coords.y + cosin*coords.z)*dtheta;
566 double residuals = std::abs(yl)/std::sqrt(1+tana*tana) - rad;
571 double errorResiduals = std::hypot(dth, dy0, del_t);
574 std::array<double,3> deriv{};
576 double dd = coords.z * sinus + b *cosin - coords.y * cosin;
577 deriv[0] =
sign(dd) * (coords.z * cosin - b * sinus + coords.y * sinus);
579 deriv[1] =
sign(dd) * cosin ;
582 deriv[2] = -1* coords.rt->driftVelocity(coords.t-
t0);
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];
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]);
600 covsq = covsq > 0. ? std::sqrt(covsq) : 0.;
605 DCOnTrack dc_new(dc_newrad, residuals, covsq);
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);
610 if(!coords.rejected) {
613 chi2 +=
sq(residuals)*coords.w;
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);
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;
625 result.dcs().push_back( dc_new );
628 double oldshift =
result.t0Shift();
635 result.set(
chi2, nhits-NUMPAR, dtheta, -1.*dy0 );
637 if(
t0==0.)
t0=0.00001;
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");