10#include <Acts/Utilities/Enumerate.hpp>
11#include <Acts/Definitions/Units.hpp>
12#include <Acts/Utilities/UnitVectors.hpp>
18using namespace Acts::UnitLiterals;
22 constexpr auto covIdx = Acts::toUnderlying(AxisDefs::etaCov);
30 return Muon::MdtDriftCircleStatus::MdtStatusUnDefined;
34 return dcStatus(dc) == Muon::MdtDriftCircleStatus::MdtStatusDriftTime;
40 while(++hitIdx < hits.size() && !
isGoodDC(*hits[hitIdx])) {
42 return hitIdx < hits.size() &&
isGoodDC(*hits[hitIdx]);
53 ostr<<
"two circle solution with ";
54 ostr<<
"theta: "<<(
theta / 1._degree) <<
" pm "<<(dTheta / 1._degree)<<
", ";
55 ostr<<
"y0: "<<y0<<
" pm "<<dY0;
64 const Config& configuration):
72 return vec.size() > m_cfg.busyLayerLimit;
74 m_cfg.startWithPattern =
false;
100 if (
msgLvl(MSG::VERBOSE)) {
101 std::stringstream sstr{};
102 for (
const auto [layCount, layer] : Acts::enumerate(
m_hitLayers.mdtHits())) {
103 sstr<<
"Mdt-hits in layer "<<layCount<<
": "<<layer.size()<<std::endl;
105 sstr<<
" **** "<<(*hit)<<std::endl;
108 for (
const auto [layCount, layer] : Acts::enumerate(
m_hitLayers.stripHits())) {
109 sstr<<
"Hits in layer "<<layCount<<
": "<<layer.size()<<std::endl;
111 sstr<<
" **** "<<(*hit)<<std::endl;
115 <<
", strip layers: "<<
m_hitLayers.stripHits().size()<<std::endl<<sstr.str()<<std::endl<<std::endl);
146 if (nextLower.size() >
m_cfg.busyLayerLimit) {
169 if (nextLower.size() >
m_cfg.busyLayerLimit) {
180 if (nextUpper.size() >
m_cfg.busyLayerLimit) {
188 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
190 std::optional<DriftCircleSeed> found = std::nullopt;
193 found = std::make_optional<DriftCircleSeed>();
195 found->measurements =
m_cfg.calibrator->calibrate(ctx,
200 found->nMdt = std::ranges::count_if(
m_segmentSeed->getHitsInMax(),
202 return hit->type() == xAOD::UncalibMeasType::MdtDriftCircleType;
219 <<
" ("<<
upper.size()<<
") - ambiguity "
233 Line_t::ParamVector pars{};
234 pars[Acts::toUnderlying(ParamDefs::y0)] = y0;
235 pars[Acts::toUnderlying(ParamDefs::x0)] =
m_segmentSeed->interceptX();
236 if (Acts::abs(
m_segmentSeed->tanAlpha()) > std::numeric_limits<double>::epsilon()) {
239 pars[Acts::toUnderlying(ParamDefs::phi)] = dirFromTan.phi();
240 pars[Acts::toUnderlying(ParamDefs::theta)] = dirFromTan.theta();
242 pars[Acts::toUnderlying(ParamDefs::phi)] = 90._degree;
243 pars[Acts::toUnderlying(ParamDefs::theta)] =
theta;
248 if (solution.theta <
m_cfg.thetaRange[0] ||
249 solution.theta >
m_cfg.thetaRange[1]) {
251 <<(solution.theta / 1._degree)
252 <<
" is out of the valid range ["<<(
m_cfg.thetaRange[0] / 1._degree)
253 <<
"-"<<(
m_cfg.thetaRange[1] / 1._degree)<<
"].");
256 if (solution.y0 <
m_cfg.interceptRange[0] ||
257 solution.y0 >
m_cfg.interceptRange[1]) {
260 <<
" is out of the valid range ["<<
m_cfg.interceptRange[0]
261 <<
"-"<<
m_cfg.interceptRange[1] <<
"].");
267 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
275 THROW_EXCEPTION(
"Bad hit detected, despite that should have been captured upstream "
285 static_cast<TangentLine&
>(solCandidate) = LineSeeder_t::constructTangentLine(*topHit, *bottomHit, ambi);
287 solCandidate.theta = LineSeeder_t::makeDirection(*bottomHit, solCandidate.theta).theta();
293 std::unique_ptr<CalibratedSpacePoint> calibBottom{}, calibTop{};
295 const double t0 =
m_segmentSeed->parameters()[Acts::toUnderlying(ParamDefs::t0)];
296 if (
m_cfg.recalibSeedCircles) {
300 calibBottom =
m_cfg.calibrator->calibrate(ctx, bottomHit,
m_line.position(),
m_line.direction(),
t0);
301 calibTop =
m_cfg.calibrator->calibrate(ctx, topHit,
m_line.position(),
m_line.direction(),
t0);
302 static_cast<TangentLine&
>(solCandidate) = LineSeeder_t::constructTangentLine(*calibTop, *calibBottom, ambi);
303 solCandidate.theta = LineSeeder_t::makeDirection(*calibBottom, solCandidate.theta).theta();
305 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Recalibrated segment seed is invalid");
314 const double deltaY = std::abs(seen.y0 - solCandidate.y0);
315 const double limitY = std::hypot(seen.dY0, solCandidate.dY0);
316 const double dTheta = std::abs(seen.theta - solCandidate.theta);
317 const double limitTh = std::hypot(seen.dTheta, solCandidate.dTheta);
319 <<std::format(
" delta Y: {:.2f} {:} {:.2f}", deltaY, deltaY < limitY ?
'<' :
'>', limitY)
320 <<std::format(
" delta theta: {:.2f} {:} {:.2f}", dTheta, dTheta < limitTh ?
'<' :
'>', limitTh) );
321 return deltaY < limitY && dTheta < limitTh;;
323 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Reject due to similarity");
330 const auto finalSeedPars =
constructLinePars(solCandidate.theta,solCandidate.y0);
331 m_line.updateParameters(finalSeedPars);
333 for (
const auto [layerNr, hitsInLayer] : Acts::enumerate(
m_hitLayers.mdtHits())) {
334 ATH_MSG_VERBOSE( __func__<<
"() "<<__LINE__<<
": "<<hitsInLayer.size()<<
" hits in layer "<<(layerNr +1));
335 bool hadGoodHit{
false};
337 using namespace Acts::detail::LineHelper;
338 const double distance = Acts::abs(signedDistance(testMe->localPosition(), testMe->sensorDirection(),
340 const double pull = Acts::abs(distance - testMe->driftRadius()) / std::sqrt(testMe->covariance()[
covIdx]);
342 const auto*
re =
static_cast<const xAOD::MdtDriftCircle*
>(testMe->primaryMeasurement())->readoutElement();
345 <<
" "<<
Amg::toString(testMe->localPosition())<<
", pull: "<<pull<<
", distance: "<<distance);
346 if (pull <
m_cfg.hitPullCut && distance < re->tubeRadius()) {
348 solCandidate.
seedHits.emplace_back(testMe);
351 else if (hadGoodHit) {
357 const unsigned hitCut = std::max(1.*
m_cfg.nMdtHitCut,
360 if (1.*candidateSeed.
nMdt < hitCut) {
361 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Too few hits associated "<<candidateSeed.
nMdt<<
", expect: "<<hitCut<<
" hits.");
365 if (
m_cfg.overlapCorridor) {
367 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Circle solutions for seed "
372 unsigned int nOverlap{0};
373 std::vector<int> corridor = SeedingAux::strawSigns(
m_line, accepted.
seedHits);
374 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Test seed against accepted "<<accepted<<
", updated signs: "<<corridor);
376 for (
unsigned int l = 0; l < accepted.
seedHits.size(); ++l){
381 if (nOverlap == corridor.size() && accepted.
seedHits.size() >= solCandidate.
seedHits.size()) {
382 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Same set of hits collected within the same corridor");
387 candidateSeed.
parameters[Acts::toUnderlying(ParamDefs::t0)] =
t0;
388 for (
const auto p : { ParamDefs::x0, ParamDefs::theta, ParamDefs::phi, ParamDefs::y0}) {
389 candidateSeed.
parameters[Acts::toUnderlying(p)] = finalSeedPars[Acts::toUnderlying(p)];
395 if (hit == bottomHit && calibBottom) {
396 candidateSeed.
measurements.emplace_back(std::move(calibBottom));
400 else if (hit == topHit && calibTop) {
401 candidateSeed.
measurements.emplace_back(std::move(calibTop));
412 if (
m_cfg.tightenHitCut) {
413 m_cfg.nMdtHitCut = std::max(
m_cfg.nMdtHitCut, candidateSeed.
nMdt);
419 for (
const std::vector<HoughHitType>& hitsInLayer :
m_hitLayers.stripHits()) {
420 HoughHitType bestHitLoc0{
nullptr}, bestHitLoc1{
nullptr};
421 double bestPullLoc0{
m_cfg.hitPullCut}, bestPullLoc1{
m_cfg.hitPullCut};
423 const double pull = std::sqrt(SeedingAux::chi2Term(
m_line, *testMe));
425 <<
" "<<
Amg::toString(testMe->localPosition())<<
", pull: "<<pull<<
".");
426 if (testMe->measuresLoc0() && pull < bestPullLoc0) {
428 bestHitLoc0 = testMe;
430 if (testMe->measuresLoc1() && pull < bestPullLoc1) {
432 bestHitLoc1 = testMe;
439 if (bestHitLoc1 && bestHitLoc1 != bestHitLoc0) {
445 return candidateSeed;
const boost::regex re(r_e)
Scalar theta() const
theta method
#define ATH_MSG_VERBOSE(x)
std::vector< size_t > vec
bool msgLvl(const MSG::Level lvl) const
Test the output level.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
const Muon::IMuonIdHelperSvc * idHelperSvc() const
Returns the IdHelpeSvc.
LineSeeder_t::TangentAmbi TangentAmbi
SpacePointPerLayerSplitter::HitVec HitVec
std::size_t m_signComboIndex
Index of the left-right ambiguity between the circles.
Line_t m_line
Line to instantiate the seed parameters.
bool isValidLine(const TangentLine &solution) const
Checks whether the intercept and the angle are witihn the allowed ranges.
LineSeeder_t::TwoCircleTangentPars TangentLine
unsigned int numGenerated() const
Returns how many seeds have been generated.
const SegmentSeed * m_segmentSeed
~MdtSegmentSeedGenerator()
std::size_t m_upperLayer
Considered layer to pick the top drift circle from.
std::size_t m_lowerHitIndex
Explicit hit to pick in the selected bottom layer.
std::size_t m_lowerLayer
Considered layer to pick the bottom drift circle from.
std::vector< SeedSolution > m_seenSolutions
Vector caching equivalent solutions to avoid double seeding.
static constexpr std::array< TangentAmbi, 4 > s_signCombos
std::optional< DriftCircleSeed > buildSeed(const EventContext &ctx, const HoughHitType &topHit, const HoughHitType &bottomHit, const TangentAmbi ambi)
Tries to build the seed from the two hits.
const Config & config() const
Returns the current seed configuration.
MdtSegmentSeedGenerator(const std::string &name, const SegmentSeed *segmentSeed, const Config &configuration)
Standard constructor taking the segmentSeed to start with and then few configuration tunes.
Line_t::ParamVector constructLinePars(const double theta, const double y0) const
Construct the 3D-Line parameters from the estimates theta & y0 from the tangent line.
void moveToNextCandidate()
Prepares the generator to generate the seed from the next pair of drift circles.
unsigned int m_nGenSeeds
Counter on how many seeds have been generated.
std::size_t m_upperHitIndex
Explicit hit to pick in the selected top layer.
SpacePointPerLayerSplitter m_hitLayers
std::optional< DriftCircleSeed > nextSeed(const EventContext &ctx)
returns the next seed in the row
Representation of a segment seed (a fully processed hough maximum) produced by the hough transform.
std::vector< HitVec > HitLayVec
std::vector< const SpacePoint * > HitVec
The muon space point is the combination of two uncalibrated measurements one of them measures the eta...
const Identifier & identify() const
: Identifier of the primary measurement
const xAOD::UncalibratedMeasurement * primaryMeasurement() const
const MuonGMR4::SpectrometerSector * msSector() const
Interface for Helper service that creates muon Identifiers and can be used to print Identifiers.
virtual std::string toStringChamber(const Identifier &id) const =0
print all fields up to chamber to string
virtual std::string toString(const Identifier &id) const =0
print all fields to string
virtual xAOD::UncalibMeasType type() const =0
Returns the type of the measurement type as a simple enumeration.
std::string toString(const Translation3D &translation, int precision=4)
GeoPrimitvesToStringConverter.
Eigen::Matrix< double, 3, 1 > Vector3D
SpacePointPerLayerSplitter::HitLayVec HitLayerVec
Muon::MdtDriftCircleStatus dcStatus(const SpacePoint &dc)
bool moveToNextHit(const HitVec &hits, std::size_t &hitIdx)
Move to the next space point with valid drift radius.
SpacePointPerLayerSplitter::HitVec HitVec
bool isGoodDC(const SpacePoint &dc)
Returns whether the Mdt measurement has a valid space point.
std::string toString(const Parameters &pars)
Dumps the parameters into a string with labels in front of each number.
bool firstGoodHit(const HitVec &hits, std::size_t &hitIdx)
Find the first good hit in a layer.
const SpacePoint * HoughHitType
MdtDriftCircleStatus
Enum to represent the 'status' of Mdt measurements e.g.
MdtDriftCircle_v1 MdtDriftCircle
UncalibratedMeasurement_v1 UncalibratedMeasurement
Define the version of the uncalibrated measurement class.
Helper to simultaneously calculate sin and cos of the same angle.
Configuration switches of the module.
Helper struct from a generated Mdt seed.
std::vector< std::unique_ptr< CalibratedSpacePoint > > measurements
List of calibrated measurements.
Parameters parameters
Seed parameters.
unsigned int nMdt
number of Mdt hits on the seed
const SpacePointBucket * parentBucket
Pointer to the parent bucket.
Cache of all solutions seen thus far.
void print(std::ostream &ostr) const
std::vector< int > solutionSigns
Vector of radial signs of the valid hits.
HitVec seedHits
Used hits in the seed.
#define THROW_EXCEPTION(MESSAGE)