18 #include "Minuit2/Minuit2Minimizer.h"
19 #include "Math/Functor.h"
30 constexpr
unsigned int NUMPAR=3;
38 constexpr
double R2TSPURIOUS = 50000;
40 constexpr
int WEAK_TOPO_T0ERROR = 10;
42 constexpr
int STRONG_TOPO_T0ERROR = 50;
46 HitCoords(
const double z_coord,
const double t_coord,
47 const double y_coord,
const double w_coord,
72 template <
typename T> constexpr
T sq(
const T a) {
return a *
a;}
74 class FunctionToMinimize :
public ROOT::Math::IMultiGenFunction {
76 explicit FunctionToMinimize(
const int used) :m_used{
used} {}
78 double DoEval(
const double* xx)
const override {
79 const double ang = xx[0];
80 const double b = xx[1];
81 const double t0 = xx[2];
88 if (m_t0Error == WEAK_TOPO_T0ERROR ) {
89 fval += xx[2]*xx[2]/(1.0 *m_t0Error*m_t0Error);
91 for(
int i=0;
i<m_used;++
i) {
96 const double dist = std::abs(
b*cosin +
z*sinus -
y*cosin);
97 const double uppercut =
m_data[
i].rt->tUpper();
98 const double lowercut =
m_data[
i].rt->tLower();
102 fval +=
sq(
t-uppercut)*0.1;
103 }
else if (
t < lowercut) {
104 fval +=
sq(
t-lowercut)*0.1;
106 const double r =
t< lowercut ?
m_data[
i].rt->radius(lowercut) :
t > uppercut ?
m_data[
i].rt->radius(uppercut) :
m_data[
i].rt->radius(
t);
107 fval +=
sq(dist -
r)*
w;
112 ROOT::Math::IBaseFunctionMultiDim* Clone()
const override {
return new FunctionToMinimize(m_used);}
113 unsigned int NDim()
const override {
return 3;}
114 void setT0Error(
const int t0Error){m_t0Error=t0Error;}
115 void addCoords(HitCoords
coord){
119 std::vector<HitCoords>
m_data{};
134 double ta = rtrel->
tLower();
136 if(r<rtrel->
radius(ta) ) {
137 return -1*R2TSPURIOUS;
144 double tm = (ta +
tb) / 2;
145 double rtm = rtrel->
radius(tm);
146 if(std::abs(rtm -
r) < 0.001 ) {
157 if(itr>50)
return -1;
162 return a > 0 ? 1 :
a < 0 ? -1 : 0;
171 declareInterface <IDCSLFitProvider> (
this);
176 return StatusCode::SUCCESS;
190 return StatusCode::SUCCESS;
197 const EventContext& ctx{Gaudi::Hive::currentContext()};
199 if (!calibData.isValid()) {
203 std::array<const MuonCalib::MdtRtRelation*, 2> rtRelations{};
205 unsigned int nRel{0};
206 for (
unsigned int i = 0;
i < dcs.size() ; ++
i) {
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;
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 ){
309 const unsigned int mlIdx = id_helper.multilayer(roto->
identify()) - 1;
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;
330 const double inv_S = 1. /
S;
337 for(HitCoords& coords :
hits) {
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();
390 }
else if ( sinus == 0.0 && cosin < 0.0 ) {
394 ATH_MSG_DEBUG(
"before fit theta "<<theta<<
" sinus "<<sinus<<
" cosin "<< cosin);
396 double d =
line.y0() + Zc*sinus-Yc*cosin;
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);
476 minimum.SetFixedVariable(0,
"a",
variable[0]);
477 minimum.SetFixedVariable(1,
"b",
variable[1]);
482 minimum.SetFunction(minFunct);
487 const double *
results = minimum.X();
488 const double *
errors = minimum.Errors();
496 double dtheta = aErr;
504 }
else if ( sinus == 0.0 && cosin < 0.0 ) {
507 ang = std::atan2(sinus, cosin);
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);
525 for(
int it2=0; it2<3; 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];
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.;
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());
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;
638 result.setT0Shift(t0,t0Err);
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");