|
ATLAS Offline Software
|
Go to the documentation of this file.
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());
128 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
130 std::optional<DriftCircleSeed>
found = std::nullopt;
133 found = std::make_optional<DriftCircleSeed>();
168 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
182 const auto&[signTop, signBot] = signs;
188 const double thetaTubes = std::atan2(D.y(), D.z());
189 const double distTubes = std::hypot(D.y(), D.z());
191 <<
", driftRadius: "<<bottomHit->
driftRadius()<<
" - top tube "<<idHelperSvc->toString(topHit->
identify())
198 double theta{thetaTubes - std::asin(std::clamp(R / distTubes, -1., 1.))};
200 double Y0 = bottomPos.y()*seedDir.z() - bottomPos.z()*seedDir.y() + signBot*bottomHit->
driftRadius();
201 double combDriftUncert{std::sqrt(bottomPrd->driftRadiusCov() + topPrd->driftRadiusCov())};
202 std::unique_ptr<CalibratedSpacePoint> calibBottom{}, calibTop{};
208 const auto [linePos, lineDir] =
makeLine(candidateSeed.parameters);
213 R = signBot * calibBottom->driftRadius() - signTop * calibTop->driftRadius();
215 theta = thetaTubes - std::asin(std::clamp(R / distTubes, -1., 1.));
217 Y0 = bottomPos.y()*seedDir.z() - bottomPos.z()*seedDir.y() + signBot*bottomHit->
driftRadius();
229 const Amg::Vector3D seedPos = Y0 / seedDir.z() * Amg::Vector3D::UnitY();
231 assert(std::abs(topPos.y()*seedDir.z() - topPos.z() * seedDir.y() + signTop*topHit->
driftRadius() - Y0) < std::numeric_limits<float>::epsilon() );
232 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Candidate seed theta: "<<theta<<
", tanTheta: "<<(seedDir.y() / seedDir.z())<<
", y0: "<<Y0/seedDir.z());
236 solCandidate.theta = theta;
238 const double denomSquare = 1. -
std::pow(R / distTubes, 2);
239 if (denomSquare < std::numeric_limits<double>::epsilon()){
243 solCandidate.dTheta = combDriftUncert / std::sqrt(denomSquare) / distTubes;
244 solCandidate.dY0 = std::hypot(-bottomPos.y()*seedDir.y() + bottomPos.z()*seedDir.z(), 1.) * solCandidate.dTheta;
250 const double deltaY = std::abs(seen.
Y0 - solCandidate.Y0);
251 const double limitY = std::hypot(seen.
dY0, solCandidate.dY0);
252 const double dTheta = std::abs(seen.
theta - solCandidate.theta);
253 const double limitTh = std::hypot(seen.
dTheta, solCandidate.dTheta);
256 <<
std::format(
" delta theta: {:.2f} {:} {:.2f}", dTheta, dTheta < limitTh ?
'<' :
'>', limitTh) );
257 return deltaY < limitY && dTheta < limitTh;;
259 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Reject due to similarity");
263 unsigned int nMdt{0};
267 bool hadGoodHit{
false};
274 solCandidate.seedHits.emplace_back(testMe);
277 else if (hadGoodHit) {
288 solCandidate.solutionSigns =
driftSigns(seedPos, seedDir, solCandidate.seedHits,
msg());
294 unsigned int nOverlap{0};
296 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Test seed against accepted "<<accepted<<
", updated signs: "<<corridor);
298 for (
unsigned int l = 0;
l < accepted.
seedHits.size(); ++
l){
303 if (nOverlap == corridor.size() && accepted.
seedHits.size() >= solCandidate.seedHits.size()) {
304 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Same set of hits collected within the same corridor");
313 if (hit == bottomHit && calibBottom) {
314 candidateSeed.measurements.emplace_back(std::move(calibBottom));
318 else if (hit == topHit && calibTop) {
319 candidateSeed.measurements.emplace_back(std::move(calibTop));
332 ATH_MSG_VERBOSE(
"In event "<<ctx.eventID().event_number()<<
" found new seed solution "<<
toString(candidateSeed.parameters));
350 const auto [seedPos, seedDir] =
makeLine(candidateSeed.parameters);
356 / testMe->dimension();
360 if (
pull <= bestPull) {
371 return candidateSeed;
383 aux.invCovs.reserve(seed.measurements.size());
384 aux.driftSigns.reserve(seed.measurements.size());
387 for (
const std::unique_ptr<CalibratedSpacePoint>& hit : seed.measurements) {
388 const double invCov = 1./
driftCov(*hit);
390 const int sign =
y0 -
pos.y() * seedDir.z() +
pos.z()* seedDir.y() > 0 ? 1 : -1;
392 aux.centerOfGrav+= invCov *
pos;
393 aux.invCovs.push_back(invCov);
394 aux.driftSigns.push_back(
sign);
399 aux.covNorm = 1./
norm;
400 aux.centerOfGrav *= aux.covNorm;
402 for (
const auto&[covIdx, hit] : Acts::enumerate(seed.measurements)) {
403 const double& invCov = aux.invCovs[covIdx];
404 const int&
sign = aux.driftSigns[covIdx];
406 const double signedCov = invCov *
sign;
408 aux.T_yz += invCov *
pos.y()*
pos.z();
409 aux.T_rz += signedCov *
pos.z() * hit->driftRadius();
410 aux.T_ry += signedCov *
pos.y() * hit->driftRadius();
411 aux.fitY0 += signedCov * aux.covNorm * hit->driftRadius();
413 ATH_MSG_VERBOSE(
"Estimated T_zzyy: "<<aux.T_zzyy<<
", T_yz: "<<aux.T_yz<<
", T_rz: "<<aux.T_rz
414 <<
", T_ry: "<<aux.T_ry<<
", centre "<<
Amg::toString(aux.centerOfGrav)<<
", y0: "<<aux.fitY0
415 <<
", norm: "<<aux.covNorm<<
"/"<<
norm);
424 const double thetaMin = - (auxVars.
T_zzyy - auxVars.
T_ry) / (4* auxVars.
T_yz + auxVars.
T_rz);
426 const double thetaGuess = thetaMin + (theta > thetaMin ? 1. : -1.)*std::sqrt(thetaDet) / (4*auxVars.
T_yz + auxVars.
T_rz);
429 ATH_MSG_VERBOSE(
"Start fast fit seed: "<<theta<<
", guess: "<<thetaGuess
435 bool converged{
false};
438 const double thetaPrime = 0.5*auxVars.
T_zzyy *twoTheta.sn - auxVars.
T_yz * twoTheta.cs
439 - auxVars.
T_rz * thetaCS.cs - auxVars.
T_ry * thetaCS.sn;
445 const double thetaTwoPrime = auxVars.
T_zzyy * twoTheta.cs + 2.* auxVars.
T_yz * twoTheta.sn
446 + auxVars.
T_rz * thetaCS.sn - auxVars.
T_ry * thetaCS.cs;
447 const double update = thetaPrime / thetaTwoPrime;
448 ATH_MSG_VERBOSE(
"Fit iteration #"<<inSeed.
nIter<<
" -- theta: "<<theta<<
", thetaPrime: "<<thetaPrime
450 <<
" --> next theta "<<(theta - thetaPrime / thetaTwoPrime));
473 for (
const auto& [
idx, hit] : Acts::enumerate(seed.measurements)){
475 const double weight = aux.covNorm * signedCov;
479 aux.fitY0Prime+=
weight * velocity;
480 aux.fitY0TwoPrime+=
weight * acceleration;
482 aux.T_vz += signedCov *
pos.z()*velocity;
483 aux.T_vy += signedCov *
pos.y()*velocity;
484 aux.T_az += signedCov *
pos.z()*acceleration;
485 aux.T_ay += signedCov *
pos.y()*acceleration;
487 aux.R_vr += signedCov * hit->driftRadius() * velocity;
488 aux.R_va += signedCov * hit->driftRadius() * acceleration;
489 aux.R_vv += signedCov * velocity * velocity;
492 <<
", T_az: "<<aux.T_az<<
", T_ay: "<<aux.T_ay<<
" --- R_vr: "<<aux.R_vr
493 <<
", R_va: "<<aux.R_va<<
", R_vv: "<<aux.R_vv<<
" -- Y0^{'}: "<<aux.fitY0Prime
494 <<
", Y0^{''}: "<<aux.fitY0TwoPrime);
503 bool converged{
false};
515 cov(0,0) = auxVars.T_zzyy * twoTheta.cs + 2.* auxVars.T_yz * twoTheta.sn
516 + auxVars.T_rz * thetaCS.sn - auxVars.T_ry * thetaCS.cs;
519 cov(1,1) = - auxVars.fitY0Prime *auxVars.fitY0Prime - auxVars.fitY0Prime * auxVars.fitY0TwoPrime
520 - auxVars.T_az * thetaCS.sn - auxVars.T_ay * thetaCS.cs + auxVars.R_vv + auxVars.R_va;
522 grad[0] =0.5*auxVars.T_zzyy *twoTheta.sn - auxVars.T_yz * twoTheta.cs
523 - auxVars.T_rz * thetaCS.cs - auxVars.T_ry * thetaCS.sn;
524 grad[1] = auxVars.fitY0 * auxVars.fitY0Prime - auxVars.R_vr + auxVars.T_vz * thetaCS.sn - auxVars.T_vy * thetaCS.cs;
529 pars[1]<<
" gradient: ("<<(grad[0])<<
", "<<grad[1]<<
"), covariance:"
std::size_t m_upperHitIndex
Explicit hit to pick in the selected top layer.
std::vector< int > driftSigns(const Amg::Vector3D &posInChamber, const Amg::Vector3D &dirInChamber, const std::vector< const SpacePoint * > &uncalibHits, MsgStream &msg)
Calculates whether a segment line travereses the tube measurements on the left (-1) or right (1) side...
double fitY0
Prediced y0 given as the expection value of the radii divided by the inverse covariance sum.
double T_rz
Expectation value of T_{z} * r
double dTheta
: Uncertainty on the slope
const SpacePointBucket * parentBucket() const
Returns the bucket out of which the seed was formed.
const MuonGMR4::SpectrometerSector * msSector() const
bool overlapCorridor
Check whether a new seed candidate shares the same left-right solution with already accepted ones Rej...
unsigned int numGenerated() const
Returns how many seeds have been generated.
SegmentFit::Parameters parameters
Seed parameters.
unsigned int nMdtHitCut
How many drift circle hits needs the seed to contain in order to be valid.
std::array< int, 2 > SignComboType
Sign combinations to draw the 4 lines tangent to 2 drift circles The first two are indicating whether...
unsigned int busyLayerLimit
How many drift circles may be on a layer to be used for seeding.
double T_ry
Expectation value of T_{y} * r
double tanPhi() const
Returns the angle from the phi extension.
std::vector< int > solutionSigns
Vector of radial signs of the valid hits.
double driftCov(const CalibratedSpacePoint &dcHit)
const Config & config() const
Returns the current seed configuration.
Helper to simultaneously calculate sin and cos of the same angle.
MdtSegmentSeedGenerator(const std::string &name, const SegmentSeed *segmentSeed, const Config &configuration)
Standard constructor taking the segmentSeed to start with and then few configuration tunes.
Amg::Vector3D positionInChamber() const
Returns the position of the seed in the sector frame.
SpacePointPerLayerSorter::HitVec HitVec
SeedFitAuxilliaries estimateAuxillaries(const DriftCircleSeed &seed) const
Helper function to estimate the auxillary variables that remain constant during the fit.
Cache of all solutions seen thus far.
bool fastSeedFit
Toggle whether the seed is rapidly refitted.
unsigned int m_nGenSeeds
Counter on how many seeds have been generated.
double nMdtLayHitCut
Hit cut based on the fraction of collected tube layers.
std::vector< size_t > vec
virtual CalibSpacePointPtr calibrate(const EventContext &ctx, const SpacePoint *spacePoint, const Amg::Vector3D &seedPosInChamb, const Amg::Vector3D &seedDirInChamb, const double timeDelay) const =0
Calibrates a single space point.
#define ATH_MSG_VERBOSE(x)
virtual double driftVelocity(const EventContext &ctx, const CalibratedSpacePoint &spacePoint) const =0
Returns the drift velocity for a given drift-circle space point.
bool recalibSeedCircles
Recalibrate the seed drift circles from the initial estimate
std::pair< Amg::Vector3D, Amg::Vector3D > makeLine(const Parameters &pars)
Returns the parsed parameters into an Eigen line parametrization.
HoughMaximum::HitType HoughHitType
std::string toString(const CalibratedSpacePoint::Covariance_t &mat)
Returns the matrix in string.
@ MdtStatusDriftTime
The tube produced a vaild measurement.
bool startWithPattern
Try at the first time the pattern seed as candidate.
std::size_t m_lowerHitIndex
Explicit hit to pick in the selected bottom layer.
Auxillary struct to calculate fit constants.
const xAOD::UncalibratedMeasurement * primaryMeasurement() const
Amg::Vector3D dirFromTangents(const double tanPhi, const double tanTheta)
Constructs a direction vector from tanPhi & tanTheta.
double T_yz
Expectation value of T_{y} * T_{z}.
Configuration switches of the module
constexpr static std::array< SignComboType, 4 > s_signCombos
bool fastSegFitWithT0
Toggle whether an initial t0 fit shall be executed.
double chiSqTermStrip(const Amg::Vector3D &posInChamber, const Amg::Vector3D &dirInChamber, const SpacePoint &measurement, MsgStream &msg)
Calculates the chi2 contribuation to a linear segment line from an uncalibrated strip measurement.
double theta
: Theta of the line
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
virtual double driftAcceleration(const EventContext &ctx, const CalibratedSpacePoint &spacePoint) const =0
Returns the drift acceleration for a given drift-circle space point.
double tanTheta() const
Returns the angular coordinate of the eta transform.
double chiSqTermMdt(const Amg::Vector3D &posInChamber, const Amg::Vector3D &dirInChamber, const SpacePoint &measurement, MsgStream &msg)
Calculates the chi2 contribuation to a linear segment line from an uncalibrated Mdt measurement.
std::ostream & print(std::ostream &ostr) const
std::vector< const SpacePoint * > HitVec
std::array< double, 2 > thetaRange
Cut on the theta angle.
std::optional< DriftCircleSeed > buildSeed(const EventContext &ctx, const HoughHitType &topHit, const HoughHitType &bottomHit, const SignComboType &signs)
Tries to build the seed from the two hits.
std::size_t m_upperLayer
Considered layer to pick the top drift circle from.
double interceptY() const
Returns the intercept coordinate of the eta transform.
const std::vector< HitType > & getHitsInMax() const
Returns the list of assigned hits.
Class to provide easy MsgStream access and capabilities.
HitVec seedHits
Used hits in the seed.
std::vector< int > driftSigns
Vector of drfit signs.
double dY0
: Uncertainty on the intercept
double hitPullCut
Upper cut on the hit chi2 w.r.t.
MsgStream & msg() const
The standard message stream.
void fitDriftCirclesWithT0(const EventContext &ctx, DriftCircleSeed &seed) const
Refine the seed by performing a fast Mdt segment fit with t0 constraint.
double T_zzyy
Expectation value of T_{z}^{2} - T_{y}^{2}.
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
~MdtSegmentSeedGenerator()
std::unique_ptr< CalibratedSpacePoint > CalibSpacePointPtr
const HitLayVec & stripHits() const
Returns the sorted strip hits.
constexpr double sign(const double x)
Returns the sign of a number.
constexpr bool passRangeCut(const std::array< double, 2 > &cutRange, const double value)
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns the IdHelpeSvc.
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
constexpr int toInt(const ParamDefs p)
void moveToNextCandidate()
Prepares the generator to generate the seed from the next pair of drift circles.
unsigned int nIter
Iterations to obtain the seed.
Eigen::Matrix< double, 3, 1 > Vector3D
Amg::Vector3D dirFromAngles(const double phi, const double theta)
Constructs a direction vector from the azimuthal & polar angles.
This header ties the generic definitions in this package.
unsigned int nMaxIter
Maximum number of iterations in the fast segment fit.
const Amg::Vector3D & positionInChamber() const
const SegmentSeed * m_segmentSeed
ISpacePointCalibrator::CalibSpacePointPtr CalibSpacePointPtr
const HitLayVec & mdtHits() const
Returns the sorted Mdt hits.
bool tightenHitCut
Once a seed with even more than initially required hits is found, reject all following seeds with les...
The calibrated Space point is created during the calibration process.
Representation of a segment seed (a fully processed hough maximum) produced by the hough transform.
std::vector< SeedSolution > m_seenSolutions
Vector caching equivalent solutions to avoid double seeding.
std::array< double, 2 > interceptRange
Cut on the intercept range.
const Parameters & parameters() const
Returns the parameter array.
Helper to simultaneously calculate sin and cos of the same angle.
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
Helper struct from a generated Mdt seed.
void fitDriftCircles(DriftCircleSeed &seed) const
Refine the seed by performing a fast Mdt segment fit.
std::size_t m_signComboIndex
Index of the left-right ambiguity between the circles.
double precCutOff
Precision cut off in the fast segment fit.
double driftRadius() const
: Returns the size of the drift radius
const Covariance_t & covariance() const
Amg::Vector3D directionInChamber() const
Returns the direction of the seed in the sector frame.
https://gitlab.cern.ch/atlas/athena/-/blob/master/MuonSpectrometer/MuonReconstruction/MuonRecEvent/Mu...
unsigned int firstLayerFrom2ndMl() const
Returns the layer index with hits from the second multilayer
const ISpacePointCalibrator * calibrator
Pointer to the space point calibrator.
const AmgSymMatrix(2) &SpacePoint
constexpr int pow(int base, int exp) noexcept
SpacePointPerLayerSorter m_hitLayers
SpacePointPerLayerSorter::HitVec HitVec
std::size_t m_lowerLayer
Considered layer to pick the bottom drift circle from.
const Identifier & identify() const
: Identifier of the primary measurement
Amg::Vector3D centerOfGrav
Tube position center weigthed with inverse covariances.
std::optional< DriftCircleSeed > nextSeed(const EventContext &ctx)
returns the next seed in the row
double Y0
Intersecpt of the line.