11 #include <Acts/Utilities/Enumerate.hpp>
13 #include <Acts/Utilities/Enumerate.hpp>
18 using namespace SegmentFit;
19 using namespace SegmentFitHelpers;
23 return std::visit([](
const auto&
cov) ->
double{
28 return cutRange[0] <=
value &&
value <= cutRange[1];
32 ostr<<
"two circle solution with ";
34 ostr<<
"y0: "<<Y0<<
" pm "<<dY0;
43 const Config& configuration):
46 m_segmentSeed{segmentSeed} {
48 if (m_hitLayers.mdtHits().empty())
return;
50 if (std::ranges::find_if(m_hitLayers.mdtHits(), [
this](
const HitVec&
vec){
51 return vec.size() > m_cfg.busyLayerLimit;
52 }) != m_hitLayers.mdtHits().end()) {
53 m_cfg.startWithPattern =
false;
56 m_upperLayer = m_hitLayers.mdtHits().size()-1;
59 while (m_lowerLayer < m_upperLayer && m_hitLayers.mdtHits()[m_lowerLayer].size() >m_cfg.busyLayerLimit){
63 while (m_lowerLayer < m_upperLayer && m_hitLayers.mdtHits()[m_upperLayer].size() > m_cfg.busyLayerLimit) {
68 std::stringstream sstr{};
69 for (
const auto [layCount,
layer] : Acts::enumerate(m_hitLayers.mdtHits())) {
70 sstr<<
"Mdt-hits in layer "<<layCount<<
": "<<
layer.size()<<std::endl;
72 sstr<<
" **** "<<hit->msSector()->idHelperSvc()->toString(hit->identify())<<
" "
73 <<
Amg::toString(hit->positionInChamber())<<
", driftRadius: "<<hit->driftRadius()<<std::endl;
76 for (
const auto [layCount,
layer] : Acts::enumerate(m_hitLayers.stripHits())) {
77 sstr<<
"Hits in layer "<<layCount<<
": "<<
layer.size()<<std::endl;
79 sstr<<
" **** "<<hit->msSector()->idHelperSvc()->toString(hit->identify())<<
" "
80 <<
Amg::toString(hit->positionInChamber())<<
", driftRadius: "<<hit->driftRadius()<<std::endl;
83 ATH_MSG_VERBOSE(
"SeedGenerator - sorting of hits done. Mdt layers: "<<m_hitLayers.mdtHits().size()
84 <<
", strip layers: "<<m_hitLayers.stripHits().size()<<std::endl<<sstr.str()<<std::endl<<std::endl);
128 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
130 std::optional<DriftCircleSeed>
found = std::nullopt;
133 found = std::make_optional<DriftCircleSeed>();
142 return hit->type() == xAOD::UncalibMeasType::MdtDriftCircleType;
171 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
185 const auto&[signTop, signBot] = signs;
191 const double thetaTubes = std::atan2(D.y(), D.z());
192 const double distTubes = std::hypot(D.y(), D.z());
194 <<
", driftRadius: "<<bottomHit->
driftRadius()<<
" - top tube "<<idHelperSvc->toString(topHit->
identify())
201 double theta{thetaTubes - std::asin(std::clamp(R / distTubes, -1., 1.))};
203 double Y0 = bottomPos.y()*seedDir.z() - bottomPos.z()*seedDir.y() + signBot*bottomHit->
driftRadius();
204 double combDriftUncert{std::sqrt(bottomPrd->driftRadiusCov() + topPrd->driftRadiusCov())};
205 std::unique_ptr<CalibratedSpacePoint> calibBottom{}, calibTop{};
211 const auto [linePos, lineDir] =
makeLine(candidateSeed.parameters);
216 R = signBot * calibBottom->driftRadius() - signTop * calibTop->driftRadius();
218 theta = thetaTubes - std::asin(std::clamp(R / distTubes, -1., 1.));
220 Y0 = bottomPos.y()*seedDir.z() - bottomPos.z()*seedDir.y() + signBot*bottomHit->
driftRadius();
232 const Amg::Vector3D seedPos = Y0 / seedDir.z() * Amg::Vector3D::UnitY();
234 assert(std::abs(topPos.y()*seedDir.z() - topPos.z() * seedDir.y() + signTop*topHit->
driftRadius() - Y0) < std::numeric_limits<float>::epsilon() );
235 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Candidate seed theta: "<<theta<<
", tanTheta: "<<(seedDir.y() / seedDir.z())<<
", y0: "<<Y0/seedDir.z());
239 solCandidate.theta = theta;
241 const double denomSquare = 1. -
std::pow(R / distTubes, 2);
242 if (denomSquare < std::numeric_limits<double>::epsilon()){
246 solCandidate.dTheta = combDriftUncert / std::sqrt(denomSquare) / distTubes;
247 solCandidate.dY0 = std::hypot(-bottomPos.y()*seedDir.y() + bottomPos.z()*seedDir.z(), 1.) * solCandidate.dTheta;
253 const double deltaY = std::abs(seen.
Y0 - solCandidate.Y0);
254 const double limitY = std::hypot(seen.
dY0, solCandidate.dY0);
255 const double dTheta = std::abs(seen.
theta - solCandidate.theta);
256 const double limitTh = std::hypot(seen.
dTheta, solCandidate.dTheta);
259 <<
std::format(
" delta theta: {:.2f} {:} {:.2f}", dTheta, dTheta < limitTh ?
'<' :
'>', limitTh) );
260 return deltaY < limitY && dTheta < limitTh;;
262 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Reject due to similarity");
267 ATH_MSG_VERBOSE( __func__<<
"() "<<__LINE__<<
": "<<hitsInLayer.size()<<
" hits in layer "<<(layerNr +1));
268 bool hadGoodHit{
false};
271 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Test hit "<<idHelperSvc->toString(testMe->identify())
275 solCandidate.seedHits.emplace_back(testMe);
276 ++candidateSeed.nMdt;
278 else if (hadGoodHit) {
286 if (1.*candidateSeed.nMdt < hitCut) {
287 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Too few hits associated "<<candidateSeed.nMdt<<
", expect: "<<hitCut<<
" hits.");
292 solCandidate.solutionSigns =
driftSigns(seedPos, seedDir, solCandidate.seedHits,
msg());
293 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Circle solutions for seed "
294 <<idHelperSvc->toStringChamber(bottomHit->
identify())<<
" - "<<solCandidate);
298 unsigned int nOverlap{0};
300 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Test seed against accepted "<<accepted<<
", updated signs: "<<corridor);
302 for (
unsigned int l = 0;
l < accepted.
seedHits.size(); ++
l){
307 if (nOverlap == corridor.size() && accepted.
seedHits.size() >= solCandidate.seedHits.size()) {
308 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Same set of hits collected within the same corridor");
317 if (hit == bottomHit && calibBottom) {
318 candidateSeed.measurements.emplace_back(std::move(calibBottom));
322 else if (hit == topHit && calibTop) {
323 candidateSeed.measurements.emplace_back(std::move(calibTop));
336 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": In event "<<ctx.eventID().event_number()<<
" found new seed solution "<<
toString(candidateSeed.parameters));
354 const auto [seedPos, seedDir] =
makeLine(candidateSeed.parameters);
360 / testMe->dimension();
361 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Test hit "<<idHelperSvc->toString(testMe->identify())
364 if (
pull <= bestPull) {
375 return candidateSeed;
387 aux.invCovs.reserve(seed.measurements.size());
388 aux.driftSigns.reserve(seed.measurements.size());
391 for (
const std::unique_ptr<CalibratedSpacePoint>& hit : seed.measurements) {
392 const double invCov = 1./
driftCov(*hit);
394 const int sign =
y0 -
pos.y() * seedDir.z() +
pos.z()* seedDir.y() > 0 ? 1 : -1;
396 aux.centerOfGrav+= invCov *
pos;
397 aux.invCovs.push_back(invCov);
398 aux.driftSigns.push_back(
sign);
403 aux.covNorm = 1./
norm;
404 aux.centerOfGrav *= aux.covNorm;
406 for (
const auto [covIdx, hit] : Acts::enumerate(seed.measurements)) {
407 const double& invCov = aux.invCovs[covIdx];
408 const int&
sign = aux.driftSigns[covIdx];
410 const double signedCov = invCov *
sign;
412 aux.T_yz += invCov *
pos.y()*
pos.z();
413 aux.T_rz += signedCov *
pos.z() * hit->driftRadius();
414 aux.T_ry += signedCov *
pos.y() * hit->driftRadius();
415 aux.fitY0 += signedCov * aux.covNorm * hit->driftRadius();
417 ATH_MSG_VERBOSE(
"Estimated T_zzyy: "<<aux.T_zzyy<<
", T_yz: "<<aux.T_yz<<
", T_rz: "<<aux.T_rz
418 <<
", T_ry: "<<aux.T_ry<<
", centre "<<
Amg::toString(aux.centerOfGrav)<<
", y0: "<<aux.fitY0
419 <<
", norm: "<<aux.covNorm<<
"/"<<
norm);
428 const double thetaGuess = std::atan2( 2.*(auxVars.
T_yz - auxVars.
T_rz), auxVars.
T_zzyy) / 2.;
430 ATH_MSG_VERBOSE(
"Start fast fit seed: "<<theta<<
", guess: "<<thetaGuess
436 bool converged{
false};
439 const double thetaPrime = 0.5*auxVars.
T_zzyy *twoTheta.sn - auxVars.
T_yz * twoTheta.cs
440 - auxVars.
T_rz * thetaCS.cs - auxVars.
T_ry * thetaCS.sn;
446 const double thetaTwoPrime = auxVars.
T_zzyy * twoTheta.cs + 2.* auxVars.
T_yz * twoTheta.sn
447 + auxVars.
T_rz * thetaCS.sn - auxVars.
T_ry * thetaCS.cs;
448 const double update = thetaPrime / thetaTwoPrime;
449 ATH_MSG_VERBOSE(
"Fit iteration #"<<inSeed.
nIter<<
" -- theta: "<<theta<<
", thetaPrime: "<<thetaPrime
450 <<
", thetaTwoPrime: "<<thetaTwoPrime<<
" -- "<<
std::format(
"{:.8f}", update)
451 <<
" --> next theta "<<(theta - thetaPrime / thetaTwoPrime));
474 for (
const auto [
idx, hit] : Acts::enumerate(seed.measurements)){
476 const double weight = aux.covNorm * signedCov;
480 aux.fitY0Prime+=
weight * velocity;
481 aux.fitY0TwoPrime+=
weight * acceleration;
483 aux.T_vz += signedCov *
pos.z()*velocity;
484 aux.T_vy += signedCov *
pos.y()*velocity;
485 aux.T_az += signedCov *
pos.z()*acceleration;
486 aux.T_ay += signedCov *
pos.y()*acceleration;
488 aux.R_vr += signedCov * hit->driftRadius() * velocity;
489 aux.R_va += signedCov * hit->driftRadius() * acceleration;
490 aux.R_vv += signedCov * velocity * velocity;
493 <<
", T_az: "<<aux.T_az<<
", T_ay: "<<aux.T_ay<<
" --- R_vr: "<<aux.R_vr
494 <<
", R_va: "<<aux.R_va<<
", R_vv: "<<aux.R_vv<<
" -- Y0^{'}: "<<aux.fitY0Prime
495 <<
", Y0^{''}: "<<aux.fitY0TwoPrime);
504 bool converged{
false};
516 cov(0,0) = auxVars.T_zzyy * twoTheta.cs + 2.* auxVars.T_yz * twoTheta.sn
517 + auxVars.T_rz * thetaCS.sn - auxVars.T_ry * thetaCS.cs;
520 cov(1,1) = - auxVars.fitY0Prime *auxVars.fitY0Prime - auxVars.fitY0Prime * auxVars.fitY0TwoPrime
521 - auxVars.T_az * thetaCS.sn - auxVars.T_ay * thetaCS.cs + auxVars.R_vv + auxVars.R_va;
523 grad[0] =0.5*auxVars.T_zzyy *twoTheta.sn - auxVars.T_yz * twoTheta.cs
524 - auxVars.T_rz * thetaCS.cs - auxVars.T_ry * thetaCS.sn;
525 grad[1] = auxVars.fitY0 * auxVars.fitY0Prime - auxVars.R_vr + auxVars.T_vz * thetaCS.sn - auxVars.T_vy * thetaCS.cs;
530 pars[1]<<
" gradient: ("<<(grad[0])<<
", "<<grad[1]<<
"), covariance:"
532 <<
", "<<update[1]<<
").");