LDMX Software
SeedFinderProcessor.cxx
1#include "Tracking/Reco/SeedFinderProcessor.h"
2
3#include <algorithm>
4#include <iostream>
5#include <set>
6#include <sstream>
7
8#include "Acts/Definitions/TrackParametrization.hpp"
9#include "Acts/Utilities/Intersection.hpp"
10#include "Eigen/Dense"
11#include "Tracking/Sim/TrackingUtils.h"
12
13/* This processor takes in input a set of 3D space points and builds seedTracks
14 * using the ACTS algorithm which is based on the ATLAS 3-space point conformal
15 * fit.
16 *
17 */
18
19using Eigen::MatrixXd;
20using Eigen::VectorXd;
21
22namespace tracking {
23namespace reco {
24
26 framework::Process& process)
27 : TrackingGeometryUser(name, process) {
28 // TODO REMOVE FROM DEFAULT
29 /*
30 output_file_ = new TFile("seeder.root", "RECREATE");
31 output_tree_ = new TTree("seeder", "seeder");
32
33 output_tree_->Branch("nevents", &nevents_);
34 output_tree_->Branch("xhit", &xhit_);
35 output_tree_->Branch("yhit", &yhit_);
36 output_tree_->Branch("zhit", &zhit_);
37
38 output_tree_->Branch("b0", &b0_);
39 output_tree_->Branch("b1", &b1_);
40 output_tree_->Branch("b2", &b2_);
41 output_tree_->Branch("b3", &b3_);
42 output_tree_->Branch("b4", &b4_);
43 */
44}
45
47 truth_matching_tool_ = std::make_shared<tracking::sim::TruthMatchingTool>();
48 target_surface_ = tracking::sim::utils::unboundSurface(0.);
49}
50
52 // Output seed name
53 out_seed_collection_ = parameters.get<std::string>("out_seed_collection",
54 getName() + "SeedTracks");
55
56 // Input strip hits
58 parameters.get<std::string>("input_hits_collection", "TaggerSimHits");
59
60 // Tagger tracks - only for Recoil Seed finding
62 parameters.get<std::string>("tagger_trks_collection", "TaggerTracks");
63
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);
72 thetacut_ = parameters.get<double>("thetacut", 0.2);
73 loc0cut_ = parameters.get<double>("loc0cut", 0.1);
74 loc1cut_ = parameters.get<double>("loc1cut", 0.3);
76 parameters.get<std::vector<std::string>>("strategies", {"0,1,2,3,4"});
77 use_target_constraint_ = parameters.get<bool>("use_target_constraint", false);
79 parameters.get<bool>("use_beamspot_constraint", false);
81 parameters.get<std::vector<double>>("beamspot_sigma", {5.77, 23.1});
82
84 EXCEPTION_RAISE("BadConf",
85 "use_target_constraint needs a tagger_trks_collection");
86 }
87
88 // 5 fit parameters: one equation per strip, two per target constraint
89 const size_t min_layers =
91
92 // parse each "l0,l1,..." string into a layer list
93 strategy_layers_.clear();
94 for (const auto& strategy : strategies_) {
95 std::vector<int> layers;
96 std::stringstream ss(strategy);
97 std::string token;
98 while (std::getline(ss, token, ',')) {
99 if (!token.empty()) layers.push_back(std::stoi(token));
100 }
101 std::set<int> distinct(layers.begin(), layers.end());
102 if (distinct.size() < min_layers) {
103 EXCEPTION_RAISE("BadConf",
104 "Seeding strategy '" + strategy + "' has fewer than " +
105 std::to_string(min_layers) + " distinct layers");
106 }
107 strategy_layers_.push_back(layers);
108 }
109 inflate_factors_ = parameters.get<std::vector<double>>(
110 "inflate_factors", {10., 10., 10., 10., 10., 10.});
111 bfield_ = parameters.get<double>("bfield", 1.5);
112 input_pass_name_ = parameters.get<std::string>("input_pass_name");
113 sim_particles_coll_name_ =
114 parameters.get<std::string>("sim_particles_coll_name");
115 sim_particles_passname_ =
116 parameters.get<std::string>("sim_particles_passname");
117 tagger_trks_event_collection_passname_ =
118 parameters.get<std::string>("tagger_trks_event_collection_passname");
119 sim_particles_event_passname_ =
120 parameters.get<std::string>("sim_particles_event_passname");
121 u_error_ = parameters.get<double>("u_error");
122 v_error_ = parameters.get<double>("v_error");
123}
124
126 // tg is unused, should it be? FIXME
127 // const auto& tg{geometry()};
128 auto start = std::chrono::high_resolution_clock::now();
129 std::vector<ldmx::Track> seed_tracks;
130
131 nevents_++;
132
133 // check if SimParticleMap is available for truth matching
134 std::map<int, ldmx::SimParticle> particle_map;
135
136 const auto& measurements = event.getCollection<ldmx::Measurement>(
137 input_hits_collection_, input_pass_name_);
138
139 // tagger tracks give the target position; an empty name disables it
140 std::vector<ldmx::Track> tagger_tracks;
141 if (!tagger_trks_collection_.empty()) {
142 // prefer this pass so a re-reco does not see two copies
143 std::string pass = tagger_trks_event_collection_passname_;
144 if (pass.empty() &&
146 pass = event.getPassName();
147 }
148 if (event.exists(tagger_trks_collection_, pass)) {
149 tagger_tracks =
150 event.getCollection<ldmx::Track>(tagger_trks_collection_, pass);
151 } else if (!warned_ambiguous_tagger_ &&
152 event.exists(tagger_trks_collection_, pass, false)) {
153 ldmx_log(warn) << "Several '" << tagger_trks_collection_
154 << "' collections found, set "
155 "tagger_trks_event_collection_passname to pick one";
157 }
158 }
159
160 const auto& tgt_surf = target_surface_;
161
162 // Create the pseudomeasurements at the target
163
164 ldmx::Measurements target_pseudo_meas;
165
166 for (auto tagtrk : tagger_tracks) {
167 // For Track, the perigee parameters are stored at the target surface.
168 // Use d0/z0 as local position and the perigee covariance for the
169 // pseudo measurement. Only create the pseudo measurement if cov is
170 // available.
171
172 // The covariance matrix passed to the pseudo measurement is considered as
173 // uncorrelated. This is an approx that considers that loc-u and loc-v from
174 // the track have small correlation.
175
176 const auto& perigee_cov = tagtrk.getPerigeeCov();
177 if (!perigee_cov.empty()) {
178 Acts::BoundMatrix cov = tracking::sim::utils::unpackCov(perigee_cov);
179 double locu = tagtrk.getD0();
180 double locv = tagtrk.getZ0();
181 double covuu =
182 cov(Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc0);
183 double covvv =
184 cov(Acts::BoundIndices::eBoundLoc1, Acts::BoundIndices::eBoundLoc1);
185
186 ldmx::Measurement pseudo_meas;
187 pseudo_meas.setLocalPosition(locu, locv);
188 Acts::Vector3 dummy{0., 0., 0.};
189 Acts::Vector2 local_pos{locu, locv};
190 Acts::Vector3 global_pos =
191 tgt_surf->localToGlobal(geometryContext(), local_pos, dummy);
192
193 pseudo_meas.setGlobalPosition(global_pos(0), global_pos(1),
194 global_pos(2));
195 pseudo_meas.setTime(0.);
196 pseudo_meas.setLocalCovariance(covuu, covvv);
197
198 target_pseudo_meas.push_back(pseudo_meas);
199 }
200 }
201
202 // Constraints that enter the fit: tagger tracks, else the beam spot
203 ldmx::Measurements fit_constraints;
204 if (use_target_constraint_) fit_constraints = target_pseudo_meas;
205 if (fit_constraints.empty() && use_beamspot_constraint_) {
206 ldmx::Measurement beamspot;
207 beamspot.setLocalPosition(0., 0.);
208 Acts::Vector3 global_pos = tgt_surf->localToGlobal(
209 geometryContext(), Acts::Vector2{0., 0.}, Acts::Vector3{0., 0., 0.});
210 beamspot.setGlobalPosition(global_pos(0), global_pos(1), global_pos(2));
211 beamspot.setTime(0.);
214 fit_constraints.push_back(beamspot);
215 }
216
217 if (event.exists(sim_particles_coll_name_, sim_particles_event_passname_)) {
218 particle_map = event.getMap<int, ldmx::SimParticle>(
219 sim_particles_coll_name_, sim_particles_passname_);
220 truth_matching_tool_->setup(particle_map, measurements);
221 }
222
223 ldmx_log(debug) << "Preparing the strategies";
224
225 // a strategy is a list of layers from which to make the seed
226 // layer_ numbering starts at 0
227 for (const auto& strategy : strategy_layers_) {
228 groups_map_.clear();
229 if (groupStrips(measurements, strategy))
230 findSeedsFromMap(seed_tracks, target_pseudo_meas, fit_constraints);
231 }
232
233 groups_map_.clear();
234 // output_tree_->Fill();
235 ntracks_ += seed_tracks.size();
236 event.add(out_seed_collection_, seed_tracks);
237
238 auto end = std::chrono::high_resolution_clock::now();
239
240 // long long microseconds =
241 // std::chrono::duration_cast<std::chrono::microseconds>(end-start).count();
242
243 auto diff = end - start;
244 processing_time_ += std::chrono::duration<double, std::milli>(diff).count();
245
246 // Seed finding using 2D Hits
247 // - The hits should keep track if they are already associated to a track or
248 // not. This can be used for subsequent passes of seed-finding
249
250 // This should go into a digitization producer, which takes care of producing
251 // measurements from:
252 // - raw hits in data
253 // - sim hits in MC
254 // Step 0: Get the sim hits and project them on the surfaces to mimic 2d
255 // hits Step 1: Smear the hits and associate an uncertainty to those
256 // measurements.
257
258 xhit_.clear();
259 yhit_.clear();
260 zhit_.clear();
261
262 b0_.clear();
263 b1_.clear();
264 b2_.clear();
265 b3_.clear();
266 b4_.clear();
267
268} // produce
269
270// Seed finder from Robert's in HPS
271// https://github.com/JeffersonLab/hps-java/blob/47712878302eb0c0374d077a208a6f8f0e2c3dc6/tracking/src/main/java/org/hps/recon/tracking/kalman/SeedTrack.java
272// Adapted to possible 3D hit points.
273
274// yOrigin is the location along the beam about which we fit the seed helix
275// perigee_location is where the track parameters will be extracted
276
277// the optional constraint is a 2D point on the target surface
278
280 const ldmx::Measurements& vmeas, double xOrigin,
281 const Acts::Vector3& perigee_location,
282 const ldmx::Measurement* constraint) {
283 // Fit a straight line in the non-bending plane and a parabola in the bending
284 // plane
285
286 // Each measurement is treated as a 3D point, where the v direction is in the
287 // center of the strip with sigma equal to the length of the strip / sqrt(12).
288 // In this way it's easier to incorporate the tagger track extrapolation to
289 // the fit
290
291 Acts::Matrix<5, 5> a = Acts::Matrix<5, 5>::Zero();
292 Acts::Vector<5> y = Acts::Vector<5>::Zero();
293
294 // accumulate one 2D point on a surface into the normal equations
295 auto add_point = [&](const Acts::Surface& surface, const Acts::Vector2& loc,
296 double xmeas, double var_u, double var_v) {
297 auto rot = surface.localToGlobalTransform(geometryContext()).rotation();
298 auto tr = surface.localToGlobalTransform(geometryContext()).translation();
299 auto rotl2g = rot.transpose();
300
301 Acts::Matrix<2, 5> a_i;
302 a_i(0, 0) = rotl2g(0, 1);
303 a_i(0, 1) = rotl2g(0, 1) * xmeas;
304 a_i(0, 2) = rotl2g(0, 1) * xmeas * xmeas;
305 a_i(0, 3) = rotl2g(0, 2);
306 a_i(0, 4) = rotl2g(0, 2) * xmeas;
307
308 a_i(1, 0) = rotl2g(1, 1);
309 a_i(1, 1) = rotl2g(1, 1) * xmeas;
310 a_i(1, 2) = rotl2g(1, 1) * xmeas * xmeas;
311 a_i(1, 3) = rotl2g(1, 2);
312 a_i(1, 4) = rotl2g(1, 2) * xmeas;
313
314 Acts::Vector2 offset = (rot.transpose() * tr).topRows<2>();
315 Acts::Vector2 xoffset = {rotl2g(0, 0) * xmeas, rotl2g(1, 0) * xmeas};
316
317 Acts::Matrix<2, 2> w_i = Acts::Matrix<2, 2>::Zero();
318 w_i(0, 0) = 1. / var_u;
319 w_i(1, 1) = 1. / var_v;
320
321 Acts::Vector2 yprime_i = loc + offset - xoffset;
322 y += (a_i.transpose()) * w_i * yprime_i;
323 a += a_i.transpose() * (w_i * a_i);
324 };
325
326 for (auto meas : vmeas) {
327 double xmeas = meas.getGlobalPosition()[0] - xOrigin;
328 const Acts::Surface* hit_surface = geometry().getSurface(meas.getLayerID());
329
330 xhit_.push_back(xmeas);
331 yhit_.push_back(meas.getGlobalPosition()[1]);
332 zhit_.push_back(meas.getGlobalPosition()[2]);
333
334 // strips measure u only; v sits at the strip center
335 Acts::Vector2 loc{meas.getLocalPosition()[0], 0.};
336 add_point(*hit_surface, loc, xmeas, u_error_ * u_error_,
338 }
339
340 if (constraint) {
341 double xmeas = constraint->getGlobalPosition()[0] - xOrigin;
342 Acts::Vector2 loc{constraint->getLocalPosition()[0],
343 constraint->getLocalPosition()[1]};
344 auto cov = constraint->getLocalCovariance();
345 // floor at (1 um)^2 so a missing covariance cannot blow up the weight
346 add_point(*target_surface_, loc, xmeas, std::max<double>(cov[0], 1e-6),
347 std::max<double>(cov[1], 1e-6));
348 }
349
350 Acts::Vector<5> b;
351 b = a.inverse() * y;
352
353 b0_.push_back(b(0));
354 b1_.push_back(b(1));
355 b2_.push_back(b(2));
356 b3_.push_back(b(3));
357 b4_.push_back(b(4));
358
359 // Acts::Vector<5> hlx = Acts::Vector<5>::Zero();
360 Acts::Vector<3> ref{0., 0., 0.};
361
362 // relative_perigee_x is the perigee position in the fit frame (fit-x = ACTS x
363 // - xOrigin). It is used only for evaluating the fitted curve (y, z, slopes).
364 // The PerigeeSurface and seed_pos must use the absolute ACTS x coordinate,
365 // which is perigee_location(0) directly.
366 double relative_perigee_x = perigee_location(0) - xOrigin;
367
368 std::shared_ptr<const Acts::PerigeeSurface> seed_perigee =
369 Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3(
370 perigee_location(0), perigee_location(1), perigee_location(2)));
371
372 // in mm — x is absolute ACTS x; y and z evaluated at fit-x =
373 // relative_perigee_x
374 Acts::Vector3 seed_pos{perigee_location(0),
375 b(0) + b(1) * relative_perigee_x +
376 b(2) * relative_perigee_x * relative_perigee_x,
377 b(3) + b(4) * relative_perigee_x};
378 Acts::Vector3 dir{1, b(1) + 2 * b(2) * relative_perigee_x, b(4)};
379 dir /= dir.norm();
380
381 // Momentum at xmeas
382 // R in meters, p in GeV
383 double p = 0.3 * bfield_ * (1. / (2. * abs(b(2)))) * 0.001;
384 // std::cout<<"Momentum "<< p*dir << std::endl;
385
386 // Convert it to MeV since that's what TrackUtils assumes
387 Acts::Vector3 seed_mom = p * dir / Acts::UnitConstants::MeV;
388 double q =
389 b(2) < 0 ? -1 * Acts::UnitConstants::e : +1 * Acts::UnitConstants::e;
390
391 // Linear intersection with the perigee line. TODO:: Use propagator instead
392 // Project the position on the surface.
393 // This is mainly necessary for the perigee surface, where
394 // the mean might not fulfill the perigee condition.
395
396 // mg Aug 2024 .. interect has changed, but just remove boundary check
397 // and change intersection to intersections
398 // auto intersection =
399 // (*seed_perigee).intersect(geometry_context(), seed_pos, dir, false);
400
401 // Acts::FreeVector seed_free = tracking::sim::utils::toFreeParameters(
402 // intersection.intersection.position, seed_mom, q);
403
404 auto intersection =
405 (*seed_perigee).intersect(geometryContext(), seed_pos, dir);
406
407 Acts::FreeVector seed_free = tracking::sim::utils::toFreeParameters(
408 intersection[0].position(), seed_mom, q);
409
410 auto bound_params = Acts::transformFreeToBoundParameters(
411 seed_free, *seed_perigee, geometryContext())
412 .value();
413
414 ldmx_log(trace) << "bound parameters at perigee location" << bound_params;
415
416 Acts::BoundVector stddev;
417 // sigma set to 75% of momentum
418 double sigma_p = 0.75 * p * Acts::UnitConstants::GeV;
419 stddev[Acts::eBoundLoc0] =
420 inflate_factors_[Acts::eBoundLoc0] * 2 * Acts::UnitConstants::mm;
421 stddev[Acts::eBoundLoc1] =
422 inflate_factors_[Acts::eBoundLoc1] * 5 * Acts::UnitConstants::mm;
423 stddev[Acts::eBoundPhi] =
424 inflate_factors_[Acts::eBoundPhi] * 5 * Acts::UnitConstants::degree;
425 stddev[Acts::eBoundTheta] =
426 inflate_factors_[Acts::eBoundTheta] * 5 * Acts::UnitConstants::degree;
427 stddev[Acts::eBoundQOverP] =
428 inflate_factors_[Acts::eBoundQOverP] * (1. / p) * (1. / p) * sigma_p;
429 stddev[Acts::eBoundTime] =
430 inflate_factors_[Acts::eBoundTime] * 1000 * Acts::UnitConstants::ns;
431
432 ldmx_log(debug)
433 << "Making covariance matrix as diagonal matrix with inflated terms";
434 Acts::BoundMatrix bound_cov = stddev.cwiseProduct(stddev).asDiagonal();
435
436 ldmx_log(debug) << "...now putting together the seed track ...";
437
438 ldmx::Track trk = ldmx::Track();
439 // Store the perigee surface position (absolute ACTS coordinates) converted to
440 // LDMX frame so CKFProcessor can reconstruct the same surface.
441 Acts::Vector3 perigee_ldmx =
442 tracking::sim::utils::acts2Ldmx(perigee_location);
443 trk.setPerigeeLocation(perigee_ldmx(0), perigee_ldmx(1), perigee_ldmx(2));
444 trk.setChi2(0.);
445 trk.setNhits(vmeas.size());
446 trk.setNdf(0);
447 trk.setNsharedHits(0);
448 trk.setCharge(q < 0 ? -1 : 1);
449 std::vector<double> v_seed_params(
450 (bound_params).data(),
451 bound_params.data() + bound_params.rows() * bound_params.cols());
452 std::vector<double> v_seed_cov;
453 tracking::sim::utils::flatCov(bound_cov, v_seed_cov);
454 trk.setPerigeeParameters(v_seed_params);
455 trk.setPerigeeCov(v_seed_cov);
456
457 ldmx_log(debug)
458 << "...making the ParticleHypothesis ...assume electron for now";
459 auto part_hypo{Acts::ParticleHypothesis::electron()};
460
461 ldmx_log(debug) << "Making BoundTrackParameters seedParameters";
462 Acts::BoundTrackParameters seed_parameters(
463 seed_perigee, std::move(bound_params), bound_cov, part_hypo);
464
465 ldmx_log(debug) << "Returning seed track";
466 return trk;
467}
468
470 // output_file_->cd();
471 // output_tree_->Write();
472 // output_file_->Close();
473 ldmx_log(info) << "AVG Time/Event: " << std::fixed << std::setprecision(1)
474 << processing_time_ / nevents_ << " ms";
475 ldmx_log(info) << "Total Seeds/Events: " << ntracks_ << "/" << nevents_;
476 ldmx_log(info) << "Seeds discarded due to multiple hits on layers "
477 << ndoubles_;
478 ldmx_log(info) << "not enough seed points " << nmissing_;
479 ldmx_log(info) << " nfailpmin=" << nfailpmin_;
480 ldmx_log(info) << " nfailpmax=" << nfailpmax_;
481 ldmx_log(info) << " nfaild0max=" << nfaild0max_;
482 ldmx_log(info) << " nfaild0min=" << nfaild0min_;
483 ldmx_log(info) << " nfailphicut=" << nfailphi_;
484 ldmx_log(info) << " nfailthetacut=" << nfailtheta_;
485 ldmx_log(info) << " nfailz0max=" << nfailz0max_;
486}
487
488// Given a strategy, group the hits according to some options
489// Not a good algorithm. The best would be to organize all the hits in sensors
490// *first* then only select the hits that we are interested into. TODO!
491
492bool SeedFinderProcessor::groupStrips(
493 const std::vector<ldmx::Measurement>& measurements,
494 const std::vector<int> strategy) {
495 // std::cout<<"Using stratedy"<<std::endl;
496 // for (auto& e : strategy) {
497 // std::cout<<e<<" ";
498 //}
499 // std::cout<<std::endl;
500
501 for (auto& meas : measurements) {
502 ldmx_log(trace) << meas;
503
504 if (std::find(strategy.begin(), strategy.end(), meas.getLayer()) !=
505 strategy.end()) {
506 ldmx_log(debug) << "Adding measurement from layer_ = " << meas.getLayer();
507 groups_map_[meas.getLayer()].push_back(&meas);
508 }
509
510 } // loop meas
511
512 if (groups_map_.size() < strategy.size())
513 return false;
514 else
515 return true;
516}
517
518// For each strategy, form all the possible combinatorics and form a seedTrack
519// for each of those This will reshuffle all points. (issue?) Will sort the
520// meas_for_seed vector
521
522void SeedFinderProcessor::findSeedsFromMap(
523 std::vector<ldmx::Track>& seeds, const ldmx::Measurements& pmeas,
524 const ldmx::Measurements& fit_constraints) {
525 std::map<int, std::vector<const ldmx::Measurement*>>::iterator groups_iter =
526 groups_map_.begin();
527 // Vector of iterators, one per grouped layer
528 const int k = groups_map_.size();
529 if (k < 1) return;
530 std::vector<std::vector<const ldmx::Measurement*>::iterator> it;
531 it.resize(k);
532
533 unsigned int ikey = 0;
534 for (auto& key : groups_map_) {
535 it[ikey] = key.second.begin();
536 ikey++;
537 }
538
539 // K vectors in an array v[0],v[1].... v[K-1]
540
541 // Loop over all combinations
542 while (it[0] != groups_iter->second.end()) {
543 // process the pointed-to elements
544
545 /*
546 for (int j=0; j<K; j++) {
547 const ldmx::Measurement* meas = (*(it[j]));
548 std::cout<<meas->getGlobalPosition()[0]<<","
549 <<meas->getGlobalPosition()[1]<<","
550 <<meas->getGlobalPosition()[2]<<","<<std::endl;
551 }
552 */
553
554 std::vector<ldmx::Measurement> meas_for_seeds;
555 meas_for_seeds.reserve(k);
556
557 ldmx_log(debug) << " Grouping ";
558
559 for (int j = 0; j < k; j++) {
560 const ldmx::Measurement* meas = (*(it[j]));
561 meas_for_seeds.push_back(*meas);
562 }
563
564 std::sort(meas_for_seeds.begin(), meas_for_seeds.end(),
565 [](const ldmx::Measurement& m1, const ldmx::Measurement& m2) {
566 return m1.getGlobalPosition()[0] < m2.getGlobalPosition()[0];
567 });
568
569 if (meas_for_seeds.size() < k) {
570 nmissing_++;
571 return;
572 }
573
574 ldmx_log(debug) << "making seedTrack";
575
576 Acts::Vector3 perigee{perigee_location_[0], perigee_location_[1],
578
579 // one seed per constraint; nullptr is the unconstrained fit
580 std::vector<const ldmx::Measurement*> constraints;
581 for (const auto& c : fit_constraints) constraints.push_back(&c);
582 if (constraints.empty()) constraints.push_back(nullptr);
583
584 for (const auto* constraint : constraints) {
585 // 5 parameters need 5 equations: one per strip, two per constraint
586 if (meas_for_seeds.size() + (constraint ? 2 : 0) < 5) {
587 nmissing_++;
588 continue;
589 }
590
591 ldmx::Track seed_track = seedTracker(
592 meas_for_seeds, meas_for_seeds.at(k / 2).getGlobalPosition()[0],
593 perigee, constraint);
594
595 bool fail = false;
596
597 // Remove failed fits
598 if (1. / abs(seed_track.getQoP()) < pmin_) {
599 nfailpmin_++;
600 fail = true;
601 } else if (1. / abs(seed_track.getQoP()) > pmax_) {
602 nfailpmax_++;
603 fail = true;
604 }
605
606 // Remove large part of fake tracks and duplicates with the following cuts
607 // for various compatibility checks.
608
609 else if (abs(seed_track.getZ0()) > z0max_) {
610 nfailz0max_++;
611 fail = true;
612 } else if (seed_track.getD0() < d0min_) {
613 nfaild0min_++;
614 fail = true;
615 } else if (seed_track.getD0() > d0max_) {
616 nfaild0max_++;
617 fail = true;
618 } else if (abs(seed_track.getPhi()) > phicut_) {
619 fail = true;
620 nfailphi_++;
621 } else if (abs(seed_track.getTheta() - piover2_) > thetacut_) {
622 fail = true;
623 nfailtheta_++;
624 }
625
626 // If I didn't use the target pseudo measurements in the track finding
627 // I can use them for compatibility with the tagger track
628
629 // the tagger seeder has no tagger_trks_collection, so pmeas is empty
630 if (pmeas.size() > 0) {
631 // I can have multiple target pseudo measurements
632 // A seed is rejected if it is found incompatible with all the target
633 // extrapolations
634
635 // This is set but unused, eventually we will use tagger track position
636 // at target to inform recoil tracking bool tgt_compatible = false;
637 for (auto tgt_pseudomeas : pmeas) {
638 // The d0/z0 are in a frame with the same orientation of the target
639 // surface
640 double delta_loc0 =
641 seed_track.getD0() - tgt_pseudomeas.getLocalPosition()[0];
642 double delta_loc1 =
643 seed_track.getZ0() - tgt_pseudomeas.getLocalPosition()[1];
644
645 if (abs(delta_loc0) < loc0cut_ && abs(delta_loc1) < loc1cut_) {
646 // found at least 1 compatible target location
647 // tgt_compatible = true;
648 break;
649 }
650 }
651 } // pmeas > 0
652
653 if (!fail) {
654 if (truth_matching_tool_->configured()) {
655 auto truth_info = truth_matching_tool_->truthMatch(meas_for_seeds);
656 seed_track.setTrackID(truth_info.track_id_);
657 seed_track.setPdgID(truth_info.pdg_id_);
658 seed_track.setTruthProb(truth_info.truth_prob_);
659 }
660
661 seeds.push_back(seed_track);
662 }
663
664 else {
665 b0_.pop_back();
666 b1_.pop_back();
667 b2_.pop_back();
668 b3_.pop_back();
669 b4_.pop_back();
670 }
671 } // constraints
672
673 // Go to next combination
674 ldmx_log(debug) << "Go to the next combination";
675
676 ++it[k - 1];
677 for (int i = k - 1;
678 (i > 0) && (it[i] == (std::next(groups_iter, i))->second.end()); --i) {
679 it[i] = std::next(groups_iter, i)->second.begin();
680 ++it[i - 1];
681 }
682 }
683} // find seeds
684
685} // namespace reco
686} // namespace tracking
687
#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.
Definition Event.h:40
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.
Definition Event.cxx:107
std::string getPassName()
Get the current/default pass name.
Definition Event.h:492
Class which represents the process under execution.
Definition Process.h:34
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
std::array< float, 3 > getGlobalPosition() const
Definition Measurement.h:50
void setLocalPosition(const float &meas_u, const float &meas_v)
Set the local position i.e.
Definition Measurement.h:61
std::array< float, 2 > getLocalPosition() const
Definition Measurement.h:67
std::array< float, 2 > getLocalCovariance() const
Definition Measurement.h:84
void setGlobalPosition(const float &meas_x, const float &meas_y, const float &meas_z)
Set the global position i.e.
Definition Measurement.h:42
void setLocalCovariance(const float &cov_uu, const float &cov_vv)
Set cov(U,U) and cov(V, V).
Definition Measurement.h:77
void setTime(const float &meas_t)
Set the measurement time in ns.
Definition Measurement.h:93
Class representing a simulated particle.
Definition SimParticle.h:25
Implementation of a track object.
Definition Track.h:54
std::vector< std::vector< int > > strategy_layers_
Layer lists parsed from strategies_, one per strategy.
bool use_beamspot_constraint_
Put the beam spot into the seed fit when no tagger track exists.
SeedFinderProcessor(const std::string &name, framework::Process &process)
Constructor.
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...
std::vector< double > beamspot_sigma_
Beam spot sigma at the target in local (u, v) [mm].
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 &parameters) 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...