9 #include <GaudiKernel/PhysicalConstants.h>
31 constexpr
double detCutOff = 1.e-8;
35 using namespace SegmentFit;
83 ATH_MSG_DEBUG(
"Somehow a measurement is on the narrow ridge of validity. Let's try if the time can be fitted now ");
98 fitResult.
nPhiMeas+= hit->measuresPhi();
99 fitResult.
nDoF+= hit->measuresPhi();
100 fitResult.
nDoF+= hit->measuresEta();
103 fitResult.
nTimeMeas+=hit->measuresTime();
105 if (!fitResult.
nDoF) {
157 line.hessian[idxThetaSq] = -
Amg::Vector3D{phi.cs*theta.sn,phi.sn*theta.sn, theta.cs};
170 if (resObj.
projDirLenSq < std::numeric_limits<float>::epsilon()) {
190 const double lineDist = resObj.
projDir.cross(hitDir).dot(hitMinSeg);
191 const double resVal = (lineDist - hit.
driftRadius());
213 const double partialDist = resObj.
partProjDir[param].cross(hitDir).dot(hitMinSeg);
225 const double partialDist = - resObj.
projDir.cross(hitDir).dot(
line.gradient[param]);
246 for (
int param1 = param; param1>=0; --param1) {
250 const int lineIdx = vecIdxFromSymMat<nLinePars>(param, param1);
251 const int resIdx = vecIdxFromSymMat<toInt(ParamDefs::nPars)>(param, param1);
256 const double partSqLineProject =
line.hessian[lineIdx].dot(hitDir);
263 const double partialSqDist = projDirPartSq.cross(hitDir).dot(hitMinSeg);
279 const double partialSqDist = - resObj.
partProjDir[param].cross(hitDir).dot(
line.gradient[param1]);
299 const double planeOffSet = normal.dot(hitPos);
301 const double normDot = normal.dot(
line.dir);
302 if (std::abs(normDot) < std::numeric_limits<double>::epsilon()){
315 const double travelledDist = (planeOffSet -
line.pos.dot(normal)) / normDot;
319 residual.residual.block<2,1>(0,0) = (planeIsect - hitPos).block<2,1>(0,0);
321 for (
unsigned fitPar = 0; fitPar <
line.gradient.size(); ++fitPar) {
325 const double partialDist = - travelledDist / normDot * normal.dot(
line.gradient[fitPar]);
326 residual.gradient[fitPar].block<2,1>(0,0) = (travelledDist *
line.gradient[fitPar] + partialDist *
line.dir).block<2,1>(0,0);
330 residual.gradient[fitPar].block<2,1>(0,0) = (
line.gradient[fitPar] -
line.gradient[fitPar].dot(normal) / normDot *
line.dir).block<2,1>(0,0);
343 for (
int param1 = param; param1>=0; --param1) {
344 const int lineIdx = vecIdxFromSymMat<nLinePars>(param, param1);
345 const int resIdx = vecIdxFromSymMat<toInt(ParamDefs::nPars)>(param, param1);
348 residual.hessian[resIdx].block<2,1>(0,0) =(
349 travelledDist *
line.hessian[lineIdx] - travelledDist *(normal.dot(
line.hessian[lineIdx])) / normDot *
line.dir
350 - normal.dot(
line.gradient[param1]) / normDot *
residual.gradient[param]
351 - normal.dot(
line.gradient[param]) / normDot *
residual.gradient[param1]).block<2,1>(0,0);
353 const double gradientDisplace = normal.dot(
line.gradient[param1]);
354 if (gradientDisplace > std::numeric_limits<float>::epsilon()){
355 residual.hessian[resIdx].block<2,1>(0,0) = gradientDisplace*( normal.dot(
line.gradient[param]) /
std::pow(normDot,2)*
line.dir
356 -
line.gradient[param] / normDot ).block<2,1>(0,0);
374 std::stringstream hitStream{};
375 const auto [startPos, startDir] =
makeLine(startPars);
376 for (
const HitType& hit : calibHits) {
382 hitStream<<
", channel dir: "<<
Amg::toString(hit->directionInChamber())<<std::endl;
385 <<
", plane location: "<<
Amg::toString(localToGlobal)<<std::endl<<hitStream.str());
392 fitResult.calibMeasurements = std::move(calibHits);
398 const auto [segPos, segDir] =
makeLine(startPars);
409 unsigned int noChangeIter{0};
411 ATH_MSG_DEBUG(
"Iteration: "<<fitResult.nIter<<
" parameters: "<<
toString(fitResult.segmentPars)<<
", chi2: "<<fitResult.chi2);
425 for (
HitType& hit : fitResult.calibMeasurements) {
431 ATH_MSG_DEBUG(
"Update chi2 from measurement "<<(hit->spacePoint() ? idHelperSvc->toString(hit->spacePoint()->identify())
435 switch (hit->type()) {
439 const double dSign = (hit->driftRadius() > 0 ? 1. : -1.);
443 hit->setDriftRadius(dSign*hit->driftRadius());
447 if (!fitResult.timeFit) {
463 if (!fitResult.timeFit || !hit->measuresTime()) {
469 const double totFlightDist = (localToGlobal * planeIsect).
mag() * c_inv;
474 ATH_MSG_VERBOSE(
"Partial derivative of "<<idHelperSvc->toString(hit->spacePoint()->identify())
476 <<
" "<<std::endl<<
toString(hit->covariance())<<std::endl<<
" w.r.t "
484 const auto &measurement = *hit->spacePoint()->primaryMeasurement();
485 ATH_MSG_WARNING(
"MdtSegmentFitter() - Unsupported measurment type" <<
typeid(measurement).
name());
489 ATH_MSG_VERBOSE(
"Update derivatives for hit "<< (hit->spacePoint() ? idHelperSvc->toString(hit->spacePoint()->identify()) :
"beamspot"));
495 for (
int k =1;
k < 5 - (!fitResult.timeFit); ++
k){
496 for (
int l = 0;
l<
k; ++
l){
497 hessian(
l,
k) = hessian(
k,
l);
502 fitResult.converged =
true;
503 ATH_MSG_VERBOSE(
"Fit converged after "<<fitResult.nIter<<
" iterations with "<<fitResult.chi2);
509 if (!fitResult.nPhiMeas && !fitResult.timeFit) {
510 paramUpdate = updateParameters<2>(fitResult.segmentPars, prevPars, gradient, prevGrad, hessian);
511 }
else if (!fitResult.nPhiMeas && fitResult.timeFit) {
519 paramUpdate = updateParameters<3>(fitResult.segmentPars, prevPars, gradient, prevGrad, hessian);
525 }
else if (fitResult.nPhiMeas && !fitResult.timeFit) {
526 paramUpdate = updateParameters<4>(fitResult.segmentPars, prevPars, gradient, prevGrad, hessian);
527 }
else if (fitResult.nPhiMeas && fitResult.timeFit) {
528 paramUpdate = updateParameters<5>(fitResult.segmentPars, prevPars, gradient, prevGrad, hessian);
532 fitResult.converged =
true;
543 fitResult.nDoF-=fitResult.timeFit;
546 const auto [segPos, segDir] = fitResult.makeLine();
549 std::optional<double> toF = fitResult.timeFit ? std::make_optional<double>((localToGlobal * segPos).
mag() * c_inv) : std::nullopt;
551 std::ranges::stable_sort(fitResult.calibMeasurements, [](
const HitType&
a,
const HitType&
b){
552 return a->positionInChamber().z() < b->positionInChamber().z();
557 for (
const HitType& hit : fitResult.calibMeasurements) {
558 hit->setDriftRadius(std::abs(hit->driftRadius()));
562 if (!fitResult.nPhiMeas&& !fitResult.timeFit) {
563 blockCovariance<2>(std::move(hessian), fitResult.segmentParErrs);
564 }
else if (!fitResult.nPhiMeas && fitResult.timeFit) {
567 blockCovariance<3>(std::move(hessian), fitResult.segmentParErrs);
570 }
else if (fitResult.nPhiMeas) {
571 blockCovariance<4>(std::move(hessian), fitResult.segmentParErrs);
572 }
else if (fitResult.nPhiMeas && fitResult.timeFit) {
573 blockCovariance<5>(std::move(hessian), fitResult.segmentParErrs);
581 double&
chi2,
int startPar)
const {
585 for (
int p = startPar;
p >=0 ; --
p) {
586 gradient[
p] +=2.*covRes.dot(fitMeas.
gradient[
p]);
587 for (
int k=
p;
k>=0; --
k) {
590 const int symMatIdx = vecIdxFromSymMat<ResidualWithPartials::nPars>(
p,
k);
596 <<
toString(gradient)<<
", Hessian:\n"<<hessian<<
", measurement covariance\n"<<
toString(invCov));
599 template <
unsigned int nDim>
603 covariance.setIdentity();
604 AmgSymMatrix(nDim) miniHessian = hessian.block<nDim, nDim>(0,0);
605 if (std::abs(miniHessian.determinant()) <= detCutOff) {
606 ATH_MSG_VERBOSE(
"Boeser mini hessian ("<<miniHessian.determinant()<<
")\n"<<miniHessian<<
"\n\n"<<hessian);
609 ATH_MSG_VERBOSE(
"Hessian matrix: \n"<<hessian<<
",\nblock Hessian:\n"<<miniHessian<<
",\n determinant: "<<miniHessian.determinant());
610 covariance.block<nDim,nDim>(0,0) = miniHessian.inverse();
614 template <
unsigned int nDim>
620 AmgSymMatrix(nDim) miniHessian = currentHessian.block<nDim, nDim>(0,0);
622 <<
", hessian ("<<miniHessian.determinant()<<
")"<<std::endl<<miniHessian);
624 double changeMag{0.};
625 if (std::abs(miniHessian.determinant()) > detCutOff) {
626 prevPars.block<nDim,1>(0,0) = currPars.block<nDim,1>(0,0);
628 const AmgVector(nDim) updateMe = miniHessian.inverse()* currGrad.block<nDim, 1>(0,0);
629 changeMag = std::sqrt(updateMe.dot(updateMe));
630 currPars.block<nDim,1>(0,0) -= updateMe;
631 prevGrad.block<nDim,1>(0,0) = currGrad.block<nDim,1>(0,0);
632 ATH_MSG_DEBUG(
"Hessian inverse:\n"<<miniHessian.inverse()<<
"\n\nUpdate the parameters by -"
635 const AmgVector(nDim) gradDiff = (currGrad - prevGrad).block<nDim,1>(0,0);
636 const double gradDiffMag = gradDiff.mag2();
637 double denom = (gradDiffMag > std::numeric_limits<float>::epsilon() ? gradDiffMag : 1.);
638 const double gamma = std::abs((currPars - prevPars).block<nDim,1>(0,0).
dot(gradDiff))
640 ATH_MSG_VERBOSE(
"Hessian determinant invalid. Try deepest descent - \nprev parameters: "
642 prevPars.block<nDim, 1>(0,0) = currPars.block<nDim, 1>(0,0);
643 currPars.block<nDim, 1>(0,0) -=
gamma* currGrad.block<nDim, 1>(0,0);
644 prevGrad.block<nDim, 1>(0,0) = currGrad.block<nDim,1>(0,0);
645 changeMag = std::abs(
gamma) * currGrad.block<nDim, 1>(0,0).
mag();
648 unsigned int nOutOfBound{0};
649 for (
unsigned int p = 0;
p< nDim; ++
p) {
650 double& parValue{currPars[
p]};
651 if constexpr(nDim == 3) {