1#include "Tracking/Reco/SeedFinderProcessor.h"
8#include "Acts/Definitions/TrackParametrization.hpp"
9#include "Acts/Utilities/Intersection.hpp"
11#include "Tracking/Sim/TrackingUtils.h"
47 truth_matching_tool_ = std::make_shared<tracking::sim::TruthMatchingTool>();
58 parameters.
get<std::string>(
"input_hits_collection",
"TaggerSimHits");
62 parameters.
get<std::string>(
"tagger_trks_collection",
"TaggerTracks");
65 parameters.
get<std::vector<double>>(
"perigee_location", {-700, 0., 0.});
66 pmin_ = parameters.
get<
double>(
"pmin", 0.05 * Acts::UnitConstants::GeV);
67 pmax_ = parameters.
get<
double>(
"pmax", 8 * Acts::UnitConstants::GeV);
68 d0max_ = parameters.
get<
double>(
"d0max", -15. * Acts::UnitConstants::mm);
69 d0min_ = parameters.
get<
double>(
"d0min", -45. * Acts::UnitConstants::mm);
70 z0max_ = parameters.
get<
double>(
"z0max", 60. * Acts::UnitConstants::mm);
71 phicut_ = parameters.
get<
double>(
"phicut", 0.1);
74 loc1cut_ = parameters.
get<
double>(
"loc1cut", 0.3);
76 parameters.
get<std::vector<std::string>>(
"strategies", {
"0,1,2,3,4"});
79 parameters.
get<
bool>(
"prefilter_unconstrained",
false);
82 EXCEPTION_RAISE(
"BadConf",
83 "use_target_constraint needs a tagger_trks_collection");
92 std::vector<int> layers;
93 std::stringstream ss(strategy);
95 while (std::getline(ss, token,
',')) {
96 if (!token.empty()) layers.push_back(std::stoi(token));
98 std::set<int> distinct(layers.begin(), layers.end());
99 if (distinct.size() < min_layers) {
100 EXCEPTION_RAISE(
"BadConf",
101 "Seeding strategy '" + strategy +
"' has fewer than " +
102 std::to_string(min_layers) +
" distinct layers");
106 inflate_factors_ = parameters.
get<std::vector<double>>(
107 "inflate_factors", {10., 10., 10., 10., 10., 10.});
108 bfield_ = parameters.
get<
double>(
"bfield", 1.5);
109 input_pass_name_ = parameters.
get<std::string>(
"input_pass_name");
110 sim_particles_coll_name_ =
111 parameters.
get<std::string>(
"sim_particles_coll_name");
112 sim_particles_passname_ =
113 parameters.
get<std::string>(
"sim_particles_passname");
114 tagger_trks_event_collection_passname_ =
115 parameters.
get<std::string>(
"tagger_trks_event_collection_passname");
116 sim_particles_event_passname_ =
117 parameters.
get<std::string>(
"sim_particles_event_passname");
125 auto start = std::chrono::high_resolution_clock::now();
126 std::vector<ldmx::Track> seed_tracks;
131 std::map<int, ldmx::SimParticle> particle_map;
137 std::vector<ldmx::Track> tagger_tracks;
140 std::string pass = tagger_trks_event_collection_passname_;
143 pass =
event.getPassName();
151 EXCEPTION_RAISE(
"BadConf",
153 "' collections found, set "
154 "tagger_trks_event_collection_passname to pick "
158 "' collection for the target "
159 "constraint, run tagger tracking");
163 <<
"' collections found, set "
164 "tagger_trks_event_collection_passname to pick one";
173 ldmx::Measurements target_pseudo_meas;
175 for (
auto tagtrk : tagger_tracks) {
185 const auto& perigee_cov = tagtrk.getPerigeeCov();
186 if (!perigee_cov.empty()) {
187 Acts::BoundMatrix cov = tracking::sim::utils::unpackCov(perigee_cov);
188 double locu = tagtrk.getD0();
189 double locv = tagtrk.getZ0();
191 cov(Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc0);
193 cov(Acts::BoundIndices::eBoundLoc1, Acts::BoundIndices::eBoundLoc1);
197 Acts::Vector3 dummy{0., 0., 0.};
198 Acts::Vector2 local_pos{locu, locv};
199 Acts::Vector3 global_pos =
200 tgt_surf->localToGlobal(geometryContext(), local_pos, dummy);
207 target_pseudo_meas.push_back(pseudo_meas);
212 ldmx::Measurements fit_constraints;
215 if (event.
exists(sim_particles_coll_name_, sim_particles_event_passname_)) {
217 sim_particles_coll_name_, sim_particles_passname_);
218 truth_matching_tool_->setup(particle_map, measurements);
221 ldmx_log(debug) <<
"Preparing the strategies";
228 const size_t n_before = seed_tracks.size();
230 findSeedsFromMap(seed_tracks, target_pseudo_meas, fit_constraints);
236 ntracks_ += seed_tracks.size();
239 auto end = std::chrono::high_resolution_clock::now();
244 auto diff = end - start;
245 processing_time_ += std::chrono::duration<double, std::milli>(diff).count();
281 const ldmx::Measurements& vmeas,
double xOrigin,
282 const Acts::Vector3& perigee_location,
292 Acts::Matrix<5, 5> a = Acts::Matrix<5, 5>::Zero();
293 Acts::Vector<5> y = Acts::Vector<5>::Zero();
296 auto add_point = [&](
const Acts::Surface& surface,
const Acts::Vector2& loc,
297 double xmeas,
double var_u,
double var_v) {
298 auto rot = surface.localToGlobalTransform(geometryContext()).rotation();
299 auto tr = surface.localToGlobalTransform(geometryContext()).translation();
300 auto rotl2g = rot.transpose();
302 Acts::Matrix<2, 5> a_i;
303 a_i(0, 0) = rotl2g(0, 1);
304 a_i(0, 1) = rotl2g(0, 1) * xmeas;
305 a_i(0, 2) = rotl2g(0, 1) * xmeas * xmeas;
306 a_i(0, 3) = rotl2g(0, 2);
307 a_i(0, 4) = rotl2g(0, 2) * xmeas;
309 a_i(1, 0) = rotl2g(1, 1);
310 a_i(1, 1) = rotl2g(1, 1) * xmeas;
311 a_i(1, 2) = rotl2g(1, 1) * xmeas * xmeas;
312 a_i(1, 3) = rotl2g(1, 2);
313 a_i(1, 4) = rotl2g(1, 2) * xmeas;
315 Acts::Vector2 offset = (rot.transpose() * tr).topRows<2>();
316 Acts::Vector2 xoffset = {rotl2g(0, 0) * xmeas, rotl2g(1, 0) * xmeas};
318 Acts::Matrix<2, 2> w_i = Acts::Matrix<2, 2>::Zero();
319 w_i(0, 0) = 1. / var_u;
320 w_i(1, 1) = 1. / var_v;
322 Acts::Vector2 yprime_i = loc + offset - xoffset;
323 y += (a_i.transpose()) * w_i * yprime_i;
324 a += a_i.transpose() * (w_i * a_i);
327 for (
auto meas : vmeas) {
328 double xmeas = meas.getGlobalPosition()[0] - xOrigin;
329 const Acts::Surface* hit_surface = geometry().getSurface(meas.getLayerID());
331 xhit_.push_back(xmeas);
332 yhit_.push_back(meas.getGlobalPosition()[1]);
333 zhit_.push_back(meas.getGlobalPosition()[2]);
336 Acts::Vector2 loc{meas.getLocalPosition()[0], 0.};
347 add_point(*
target_surface_, loc, xmeas, std::max<double>(cov[0], 1e-6),
348 std::max<double>(cov[1], 1e-6));
361 Acts::Vector<3> ref{0., 0., 0.};
367 double relative_perigee_x = perigee_location(0) - xOrigin;
369 std::shared_ptr<const Acts::PerigeeSurface> seed_perigee =
370 Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3(
371 perigee_location(0), perigee_location(1), perigee_location(2)));
375 Acts::Vector3 seed_pos{perigee_location(0),
376 b(0) + b(1) * relative_perigee_x +
377 b(2) * relative_perigee_x * relative_perigee_x,
378 b(3) + b(4) * relative_perigee_x};
379 Acts::Vector3 dir{1, b(1) + 2 * b(2) * relative_perigee_x, b(4)};
384 double p = 0.3 * bfield_ * (1. / (2. * abs(b(2)))) * 0.001;
388 Acts::Vector3 seed_mom = p * dir / Acts::UnitConstants::MeV;
390 b(2) < 0 ? -1 * Acts::UnitConstants::e : +1 * Acts::UnitConstants::e;
406 (*seed_perigee).intersect(geometryContext(), seed_pos, dir);
408 Acts::FreeVector seed_free = tracking::sim::utils::toFreeParameters(
409 intersection[0].position(), seed_mom, q);
411 auto bound_params = Acts::transformFreeToBoundParameters(
412 seed_free, *seed_perigee, geometryContext())
415 ldmx_log(trace) <<
"bound parameters at perigee location" << bound_params;
417 Acts::BoundVector stddev;
419 double sigma_p = 0.75 * p * Acts::UnitConstants::GeV;
420 stddev[Acts::eBoundLoc0] =
421 inflate_factors_[Acts::eBoundLoc0] * 2 * Acts::UnitConstants::mm;
422 stddev[Acts::eBoundLoc1] =
423 inflate_factors_[Acts::eBoundLoc1] * 5 * Acts::UnitConstants::mm;
424 stddev[Acts::eBoundPhi] =
425 inflate_factors_[Acts::eBoundPhi] * 5 * Acts::UnitConstants::degree;
426 stddev[Acts::eBoundTheta] =
427 inflate_factors_[Acts::eBoundTheta] * 5 * Acts::UnitConstants::degree;
428 stddev[Acts::eBoundQOverP] =
429 inflate_factors_[Acts::eBoundQOverP] * (1. / p) * (1. / p) * sigma_p;
430 stddev[Acts::eBoundTime] =
431 inflate_factors_[Acts::eBoundTime] * 1000 * Acts::UnitConstants::ns;
434 <<
"Making covariance matrix as diagonal matrix with inflated terms";
435 Acts::BoundMatrix bound_cov = stddev.cwiseProduct(stddev).asDiagonal();
437 ldmx_log(debug) <<
"...now putting together the seed track ...";
442 Acts::Vector3 perigee_ldmx =
443 tracking::sim::utils::acts2Ldmx(perigee_location);
444 trk.setPerigeeLocation(perigee_ldmx(0), perigee_ldmx(1), perigee_ldmx(2));
446 trk.setNhits(vmeas.size());
448 trk.setNsharedHits(0);
449 trk.setCharge(q < 0 ? -1 : 1);
450 std::vector<double> v_seed_params(
451 (bound_params).data(),
452 bound_params.data() + bound_params.rows() * bound_params.cols());
453 std::vector<double> v_seed_cov;
454 tracking::sim::utils::flatCov(bound_cov, v_seed_cov);
455 trk.setPerigeeParameters(v_seed_params);
456 trk.setPerigeeCov(v_seed_cov);
459 <<
"...making the ParticleHypothesis ...assume electron for now";
460 auto part_hypo{Acts::ParticleHypothesis::electron()};
462 ldmx_log(debug) <<
"Making BoundTrackParameters seedParameters";
463 Acts::BoundTrackParameters seed_parameters(
464 seed_perigee, std::move(bound_params), bound_cov, part_hypo);
466 ldmx_log(debug) <<
"Returning seed track";
474 ldmx_log(info) <<
"AVG Time/Event: " << std::fixed << std::setprecision(1)
475 << processing_time_ / nevents_ <<
" ms";
476 ldmx_log(info) <<
"Total Seeds/Events: " << ntracks_ <<
"/" << nevents_;
481 ldmx_log(info) <<
"Seeds discarded due to multiple hits on layers "
483 ldmx_log(info) <<
"not enough seed points " << nmissing_;
484 ldmx_log(info) <<
" nfailpmin=" << nfailpmin_;
485 ldmx_log(info) <<
" nfailpmax=" << nfailpmax_;
486 ldmx_log(info) <<
" nfaild0max=" << nfaild0max_;
487 ldmx_log(info) <<
" nfaild0min=" << nfaild0min_;
488 ldmx_log(info) <<
" nfailphicut=" << nfailphi_;
489 ldmx_log(info) <<
" nfailthetacut=" << nfailtheta_;
490 ldmx_log(info) <<
" nfailz0max=" << nfailz0max_;
492 ldmx_log(info) <<
" nfailprefilter=" << nfailprefilter_;
500bool SeedFinderProcessor::groupStrips(
501 const std::vector<ldmx::Measurement>& measurements,
502 const std::vector<int> strategy) {
509 for (
auto& meas : measurements) {
510 ldmx_log(trace) << meas;
512 if (std::find(strategy.begin(), strategy.end(), meas.getLayer()) !=
514 ldmx_log(debug) <<
"Adding measurement from layer_ = " << meas.getLayer();
515 groups_map_[meas.getLayer()].push_back(&meas);
520 if (groups_map_.size() < strategy.size())
530void SeedFinderProcessor::findSeedsFromMap(
531 std::vector<ldmx::Track>& seeds,
const ldmx::Measurements& pmeas,
532 const ldmx::Measurements& fit_constraints) {
533 std::map<int, std::vector<const ldmx::Measurement*>>::iterator groups_iter =
536 const int k = groups_map_.size();
538 std::vector<std::vector<const ldmx::Measurement*>::iterator> it;
541 unsigned int ikey = 0;
542 for (
auto& key : groups_map_) {
543 it[ikey] = key.second.begin();
550 while (it[0] != groups_iter->second.end()) {
562 std::vector<ldmx::Measurement> meas_for_seeds;
563 meas_for_seeds.reserve(k);
565 ldmx_log(debug) <<
" Grouping ";
567 for (
int j = 0; j < k; j++) {
569 meas_for_seeds.push_back(*meas);
572 std::sort(meas_for_seeds.begin(), meas_for_seeds.end(),
574 return m1.getGlobalPosition()[0] < m2.getGlobalPosition()[0];
577 if (meas_for_seeds.size() < k) {
582 ldmx_log(debug) <<
"making seedTrack";
588 std::vector<const ldmx::Measurement*> constraints;
589 for (
const auto& c : fit_constraints) constraints.push_back(&c);
590 if (constraints.empty()) constraints.push_back(
nullptr);
595 meas_for_seeds.size() >= 5) {
597 meas_for_seeds, meas_for_seeds.at(k / 2).getGlobalPosition()[0],
604 const double p = 1. / std::abs(plain.getQoP());
605 if (p < pmin_ || p >
pmax_ || std::abs(plain.getZ0()) >
z0max_ ||
607 std::abs(plain.getPhi()) >
phicut_ ||
608 std::abs(plain.getTheta() - piover2_) >
thetacut_) {
614 for (
const auto* constraint : constraints) {
616 if (meas_for_seeds.size() + (constraint ? 2 : 0) < 5) {
622 meas_for_seeds, meas_for_seeds.at(k / 2).getGlobalPosition()[0],
623 perigee, constraint);
628 if (1. / abs(seed_track.getQoP()) <
pmin_) {
631 }
else if (1. / abs(seed_track.getQoP()) >
pmax_) {
639 else if (abs(seed_track.getZ0()) >
z0max_) {
642 }
else if (seed_track.getD0() <
d0min_) {
645 }
else if (seed_track.getD0() >
d0max_) {
648 }
else if (abs(seed_track.getPhi()) >
phicut_) {
651 }
else if (abs(seed_track.getTheta() - piover2_) >
thetacut_) {
660 if (pmeas.size() > 0) {
667 for (
auto tgt_pseudomeas : pmeas) {
671 seed_track.getD0() - tgt_pseudomeas.getLocalPosition()[0];
673 seed_track.getZ0() - tgt_pseudomeas.getLocalPosition()[1];
675 if (abs(delta_loc0) <
loc0cut_ && abs(delta_loc1) < loc1cut_) {
684 if (truth_matching_tool_->configured()) {
685 auto truth_info = truth_matching_tool_->truthMatch(meas_for_seeds);
686 seed_track.setTrackID(truth_info.track_id_);
687 seed_track.setPdgID(truth_info.pdg_id_);
688 seed_track.setTruthProb(truth_info.truth_prob_);
691 seeds.push_back(seed_track);
704 ldmx_log(debug) <<
"Go to the next combination";
708 (i > 0) && (it[i] == (std::next(groups_iter, i))->second.end()); --i) {
709 it[i] = std::next(groups_iter, i)->second.begin();
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
std::string getName() const
Get the processor name.
Implements an event buffer system for storing event data.
bool exists(const std::string &name, const std::string &passName, bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
std::string getPassName()
Get the current/default pass name.
Class which represents the process under execution.
Class encapsulating parameters for configuring a processor.
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
std::array< float, 3 > getGlobalPosition() const
void setLocalPosition(const float &meas_u, const float &meas_v)
Set the local position i.e.
std::array< float, 2 > getLocalPosition() const
std::array< float, 2 > getLocalCovariance() const
void setGlobalPosition(const float &meas_x, const float &meas_y, const float &meas_z)
Set the global position i.e.
void setLocalCovariance(const float &cov_uu, const float &cov_vv)
Set cov(U,U) and cov(V, V).
void setTime(const float &meas_t)
Set the measurement time in ns.
Class representing a simulated particle.
Implementation of a track object.
std::vector< std::vector< int > > strategy_layers_
Layer lists parsed from strategies_, one per strategy.
double thetacut_
ThetaRange.
double loc0cut_
loc0 / loc1 cuts
bool prefilter_unconstrained_
Constrained fits only after the plain fit passes the cuts.
SeedFinderProcessor(const std::string &name, framework::Process &process)
Constructor.
std::vector< long > seeds_per_strategy_
Seeds found per strategy, for the end of job summary.
std::string out_seed_collection_
The name of the output collection of seeds to be stored.
double pmax_
Maximum cut on the momentum of the seeds.
std::vector< std::string > strategies_
List of stragies for seed finding.
bool use_target_constraint_
Put tagger track positions at the target into the seed fit.
std::string input_hits_collection_
The name of the input hits collection to use in finding seeds..
ldmx::Track seedTracker(const ldmx::Measurements &vmeas, double xOrigin, const Acts::Vector3 &perigee_location, const ldmx::Measurement *constraint)
Fit the strips plus an optional target constraint (nullptr = none)
void onProcessEnd() override
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
std::shared_ptr< Acts::Surface > target_surface_
Target surface the constraints live on.
void produce(framework::Event &event) override
Run the processor and create a collection of results which indicate if a charge particle can be found...
void onProcessStart() override
Callback for the EventProcessor to take any necessary action when the processing of events starts,...
double pmin_
Minimum cut on the momentum of the seeds.
std::string tagger_trks_collection_
The name of the tagger Tracks (only for Recoil Seeding)
bool warned_ambiguous_tagger_
Warn only once about several tagger track collections.
std::vector< double > perigee_location_
Location of the perigee for the helix track parameters.
double d0max_
Max d0 allowed for the seeds.
void configure(framework::config::Parameters ¶meters) override
Configure the processor using the given user specified parameters.
double d0min_
Min d0 allowed for the seeds.
double z0max_
Max z0 allowed for the seeds.
a helper base class providing some methods to shorten access to common conditions used within the tra...
The measurement calibrator can be a function or a class/struct able to retrieve the sim hits containe...