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;
65 const Config& configuration):
73 return vec.size() > m_cfg.busyLayerLimit;
75 m_cfg.startWithPattern =
false;
101 if (
msgLvl(MSG::VERBOSE)) {
102 std::stringstream sstr{};
103 for (
const auto [layCount, layer] : Acts::enumerate(
m_hitLayers.mdtHits())) {
104 sstr<<
"Mdt-hits in layer "<<layCount<<
": "<<layer.size()<<std::endl;
106 sstr<<
" **** "<<(*hit)<<std::endl;
109 for (
const auto [layCount, layer] : Acts::enumerate(
m_hitLayers.stripHits())) {
110 sstr<<
"Hits in layer "<<layCount<<
": "<<layer.size()<<std::endl;
112 sstr<<
" **** "<<(*hit)<<std::endl;
116 <<
", strip layers: "<<
m_hitLayers.stripHits().size()<<std::endl<<sstr.str()<<std::endl<<std::endl);
147 if (nextLower.size() >
m_cfg.busyLayerLimit) {
170 if (nextLower.size() >
m_cfg.busyLayerLimit) {
181 if (nextUpper.size() >
m_cfg.busyLayerLimit) {
189 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
191 std::optional<DriftCircleSeed> found = std::nullopt;
194 found = std::make_optional<DriftCircleSeed>();
196 found->measurements =
m_cfg.calibrator->calibrate(ctx,
201 found->nMdt = std::ranges::count_if(
m_segmentSeed->getHitsInMax(),
203 return hit->type() == xAOD::UncalibMeasType::MdtDriftCircleType;
220 <<
" ("<<
upper.size()<<
") - ambiguity "
234 Line_t::ParamVector pars{};
235 pars[Acts::toUnderlying(ParamDefs::y0)] = y0;
236 pars[Acts::toUnderlying(ParamDefs::x0)] =
m_segmentSeed->interceptX();
237 if (Acts::abs(
m_segmentSeed->tanAlpha()) > std::numeric_limits<double>::epsilon()) {
240 pars[Acts::toUnderlying(ParamDefs::phi)] = dirFromTan.phi();
241 pars[Acts::toUnderlying(ParamDefs::theta)] = dirFromTan.theta();
243 pars[Acts::toUnderlying(ParamDefs::phi)] = 90._degree;
244 pars[Acts::toUnderlying(ParamDefs::theta)] =
theta;
249 if (solution.theta <
m_cfg.thetaRange[0] ||
250 solution.theta >
m_cfg.thetaRange[1]) {
252 <<(solution.theta / 1._degree)
253 <<
" is out of the valid range ["<<(
m_cfg.thetaRange[0] / 1._degree)
254 <<
"-"<<(
m_cfg.thetaRange[1] / 1._degree)<<
"].");
257 if (solution.y0 <
m_cfg.interceptRange[0] ||
258 solution.y0 >
m_cfg.interceptRange[1]) {
261 <<
" is out of the valid range ["<<
m_cfg.interceptRange[0]
262 <<
"-"<<
m_cfg.interceptRange[1] <<
"].");
268 std::optional<MdtSegmentSeedGenerator::DriftCircleSeed>
276 THROW_EXCEPTION(
"Bad hit detected, despite that should have been captured upstream "
286 static_cast<TangentLine&
>(solCandidate) = LineSeeder_t::constructTangentLine(*topHit, *bottomHit, ambi);
288 solCandidate.theta = LineSeeder_t::makeDirection(*bottomHit, solCandidate.theta).theta();
294 std::unique_ptr<CalibratedSpacePoint> calibBottom{}, calibTop{};
296 const double t0 =
m_segmentSeed->parameters()[Acts::toUnderlying(ParamDefs::t0)];
297 if (
m_cfg.recalibSeedCircles) {
301 calibBottom =
m_cfg.calibrator->calibrate(ctx, bottomHit,
m_line.position(),
m_line.direction(),
t0);
302 calibTop =
m_cfg.calibrator->calibrate(ctx, topHit,
m_line.position(),
m_line.direction(),
t0);
303 static_cast<TangentLine&
>(solCandidate) = LineSeeder_t::constructTangentLine(*calibTop, *calibBottom, ambi);
304 solCandidate.theta = LineSeeder_t::makeDirection(*calibBottom, solCandidate.theta).theta();
306 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Recalibrated segment seed is invalid");
315 const double deltaY = std::abs(seen.y0 - solCandidate.y0);
316 const double limitY = std::hypot(seen.dY0, solCandidate.dY0);
317 const double dTheta = std::abs(seen.theta - solCandidate.theta);
318 const double limitTh = std::hypot(seen.dTheta, solCandidate.dTheta);
320 <<std::format(
" delta Y: {:.2f} {:} {:.2f}", deltaY, deltaY < limitY ?
'<' :
'>', limitY)
321 <<std::format(
" delta theta: {:.2f} {:} {:.2f}", dTheta, dTheta < limitTh ?
'<' :
'>', limitTh) );
322 return deltaY < limitY && dTheta < limitTh;;
324 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Reject due to similarity");
331 const auto finalSeedPars =
constructLinePars(solCandidate.theta,solCandidate.y0);
332 m_line.updateParameters(finalSeedPars);
334 for (
const auto [layerNr, hitsInLayer] : Acts::enumerate(
m_hitLayers.mdtHits())) {
335 ATH_MSG_VERBOSE( __func__<<
"() "<<__LINE__<<
": "<<hitsInLayer.size()<<
" hits in layer "<<(layerNr +1));
336 bool hadGoodHit{
false};
338 using namespace Acts::detail::LineHelper;
339 const double distance = Acts::abs(signedDistance(testMe->localPosition(), testMe->sensorDirection(),
341 const double pull = Acts::abs(distance - testMe->driftRadius()) / std::sqrt(testMe->covariance()[
covIdx]);
343 const auto*
re =
static_cast<const xAOD::MdtDriftCircle*
>(testMe->primaryMeasurement())->readoutElement();
346 <<
" "<<
Amg::toString(testMe->localPosition())<<
", pull: "<<pull<<
", distance: "<<distance);
347 if (pull <
m_cfg.hitPullCut && distance < re->tubeRadius()) {
349 solCandidate.
seedHits.emplace_back(testMe);
352 else if (hadGoodHit) {
358 const unsigned hitCut = std::max(1.*
m_cfg.nMdtHitCut,
361 if (1.*candidateSeed.
nMdt < hitCut) {
362 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Too few hits associated "<<candidateSeed.
nMdt<<
", expect: "<<hitCut<<
" hits.");
366 if (
m_cfg.overlapCorridor) {
368 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Circle solutions for seed "
373 unsigned int nOverlap{0};
374 std::vector<int> corridor = SeedingAux::strawSigns(
m_line, accepted.
seedHits);
375 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Test seed against accepted "<<accepted<<
", updated signs: "<<corridor);
377 for (
unsigned int l = 0; l < accepted.
seedHits.size(); ++l){
382 if (nOverlap == corridor.size() && accepted.
seedHits.size() >= solCandidate.
seedHits.size()) {
383 ATH_MSG_VERBOSE(__func__<<
"() "<<__LINE__<<
": Same set of hits collected within the same corridor");
388 candidateSeed.
parameters[Acts::toUnderlying(ParamDefs::t0)] =
t0;
389 for (
const auto p : { ParamDefs::x0, ParamDefs::theta, ParamDefs::phi, ParamDefs::y0}) {
390 candidateSeed.
parameters[Acts::toUnderlying(p)] = finalSeedPars[Acts::toUnderlying(p)];
396 if (hit == bottomHit && calibBottom) {
397 candidateSeed.
measurements.emplace_back(std::move(calibBottom));
401 else if (hit == topHit && calibTop) {
402 candidateSeed.
measurements.emplace_back(std::move(calibTop));
413 if (
m_cfg.tightenHitCut) {
414 m_cfg.nMdtHitCut = std::max(
m_cfg.nMdtHitCut, candidateSeed.
nMdt);
420 for (
const std::vector<HoughHitType>& hitsInLayer :
m_hitLayers.stripHits()) {
421 HoughHitType bestHitLoc0{
nullptr}, bestHitLoc1{
nullptr};
422 double bestPullLoc0{
m_cfg.hitPullCut}, bestPullLoc1{
m_cfg.hitPullCut};
424 const double pull = std::sqrt(SeedingAux::chi2Term(
m_line, *testMe));
426 <<
" "<<
Amg::toString(testMe->localPosition())<<
", pull: "<<pull<<
".");
427 if (testMe->measuresLoc0() && pull < bestPullLoc0) {
429 bestHitLoc0 = testMe;
431 if (testMe->measuresLoc1() && pull < bestPullLoc1) {
433 bestHitLoc1 = testMe;
440 if (bestHitLoc1 && bestHitLoc1 != bestHitLoc0) {
446 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.
std::ostream & 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)