LDMX Software
tracking::reco::LinearSeedFinder Class Reference

Public Member Functions

 LinearSeedFinder (const std::string &name, framework::Process &process)
 Constructor.
 
virtual ~LinearSeedFinder ()=default
 Destructor.
 
void onProcessStart () override
 Setup the truth matching.
 
void onProcessEnd () override
 Output event statistics.
 
void configure (framework::config::Parameters &parameters) override
 Configure the processor using the given user specified parameters.
 
void produce (framework::Event &event) override
 Run the processor and create a collection of results which indicate if a charge particle can be found by the recoil tracker.
 
- Public Member Functions inherited from tracking::reco::TrackingGeometryUser
 TrackingGeometryUser (const std::string &name, framework::Process &p)
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for a Producer is calling produce.
 
- Public Member Functions inherited from framework::EventProcessor
 DECLARE_FACTORY (EventProcessor, EventProcessor *, const std::string &, Process &)
 declare that we have a factory for this class
 
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()=default
 Class destructor.
 
virtual void beforeNewRun (ldmx::RunHeader &run_header)
 Callback for Producers to add parameters to the run header before conditions are initialized.
 
virtual void onNewRun (const ldmx::RunHeader &run_header)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a event input ROOT file is closed.
 
template<class T >
const T & getCondition (const std::string &condition_name)
 Access a conditions object for the current event.
 
TDirectory * getHistoDirectory ()
 Access/create a directory in the histogram file for this event processor to create histograms and analysis tuples.
 
void setStorageHint (framework::StorageControl::Hint hint)
 Mark the current event as having the given storage control hint from this module_.
 
void setStorageHint (framework::StorageControl::Hint hint, const std::string &purposeString)
 Mark the current event as having the given storage control hint from this module and the given purpose string.
 
int getLogFrequency () const
 Get the current logging frequency from the process.
 
int getRunNumber () const
 Get the run number from the process.
 
std::string getName () const
 Get the processor name.
 
void createHistograms (const std::vector< framework::config::Parameters > &histos)
 Internal function which is used to create histograms passed from the python configuration @parma histos vector of Parameters that configure histograms to create.
 

Protected Member Functions

ldmx::StraightTrack seedTracker (const std::tuple< std::array< double, 3 >, ldmx::Measurement, std::optional< ldmx::Measurement > > recoil_one, const std::tuple< std::array< double, 3 >, ldmx::Measurement, std::optional< ldmx::Measurement > > recoil_two, const std::array< double, 3 > ecal_one)
 
std::tuple< double, double, double, double, std::vector< double > > fit3DLine (const std::array< double, 3 > &first_recoil, const std::array< double, 3 > &second_recoil, const std::array< double, 3 > &ecal)
 
double calculateDistance (const std::array< double, 3 > &point1, const std::array< double, 3 > &point2)
 
Acts::Vector3 simple3DHitV2 (const ldmx::Measurement &axial, const Acts::Surface &axial_surface, const ldmx::Measurement &stereo, const Acts::Surface &stereo_surface, const ldmx::SimTrackerHit &hitOnTarget, std::vector< ldmx::SimTrackerHit > pair_sim_hits)
 
std::vector< std::tuple< std::array< double, 3 >, std::tuple< ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit >, std::optional< std::tuple< ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit > > > > processMeasurements (const std::vector< std::tuple< ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit > > &measurements, const geo::TrackersTrackingGeometry &tg)
 
double globalChiSquare (const std::array< double, 3 > &first_sensor, const std::array< double, 3 > &second_sensor, const std::array< double, 3 > &ecal_hit, double a_x, double a_y, double b_x, double b_y)
 
int uniqueLayersHit (const std::vector< ldmx::Measurement > &digi_points)
 
std::array< double, 3 > convertToLdmxStdArray (const Acts::Vector3 &vec)
 
std::tuple< Acts::Vector3, Acts::Vector3, Acts::Vector3 > getSurfaceVectors (const Acts::Surface &surface)
 
double dotProduct (const Acts::Vector3 &v1, const Acts::Vector3 &v2)
 
std::array< double, 3 > getPointAtZ (std::array< double, 3 > target, std::array< double, 3 > measurement, double z_target)
 
- Protected Member Functions inherited from tracking::reco::TrackingGeometryUser
const Acts::GeometryContext & geometryContext ()
 
const Acts::MagneticFieldContext & magneticFieldContext ()
 
const Acts::CalibrationContext & calibrationContext ()
 
const geo::TrackersTrackingGeometrygeometry ()
 
- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 

Protected Attributes

double processing_time_ {0.}
 
long n_events_ {0}
 
unsigned int n_seeds_ {0}
 
std::string out_seed_collection_ {"LinearRecoilSeedTracks"}
 The name of the output collection of seeds to be stored.
 
std::string input_hits_collection_ {"DigiRecoilSimHits"}
 The name of the input hits collection to use in finding seeds..
 
std::string input_rec_hits_collection_ {"EcalRecHits"}
 The name of the tagger Tracks (only for Recoil Seeding)
 
std::string input_pass_name_ {""}
 
double ecal_uncertainty_ {3.87}
 
double ecal_distance_threshold_ {10.0}
 
double layer12_midpoint_ {12.5}
 
double layer23_midpoint_ {20.0}
 
double layer34_midpoint_ {27.5}
 
double ecal_first_layer_z_threshold_ {250.0}
 
std::vector< double > recoil_uncertainty_ {0.006, 0.085}
 
long n_missing_ {0}
 
std::shared_ptr< tracking::sim::TruthMatchingTooltruth_matching_tool_
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManagerntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Private Attributes

std::string next_event_passname_
 
std::string sim_particles_passname_
 
std::string sim_particles_events_passname_
 

Detailed Description

Definition at line 26 of file LinearSeedFinder.h.

Constructor & Destructor Documentation

◆ LinearSeedFinder()

tracking::reco::LinearSeedFinder::LinearSeedFinder ( const std::string & name,
framework::Process & process )

Constructor.

Parameters
nameThe name of the instance of this object.
processThe process running this producer.

Definition at line 8 of file LinearSeedFinder.cxx.

10 : TrackingGeometryUser(name, process) {}
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.

Member Function Documentation

◆ calculateDistance()

double tracking::reco::LinearSeedFinder::calculateDistance ( const std::array< double, 3 > & point1,
const std::array< double, 3 > & point2 )
protected

Definition at line 590 of file LinearSeedFinder.cxx.

591 {
592 return sqrt(pow(point1[1] - point2[1], 2) + pow(point1[2] - point2[2], 2));
593} // calculateDistance in xy

◆ configure()

void tracking::reco::LinearSeedFinder::configure ( framework::config::Parameters & parameters)
overridevirtual

Configure the processor using the given user specified parameters.

Parameters
parametersSet of parameters used to configure this processor.

Reimplemented from framework::EventProcessor.

Definition at line 16 of file LinearSeedFinder.cxx.

16 {
17 // Output seed name
18 out_seed_collection_ = parameters.get<std::string>(
19 "out_seed_collection", getName() + "LinearRecoilSeedTracks");
20
21 // Input strip hits_
23 parameters.get<std::string>("input_hits_collection", "DigiRecoilSimHits");
25 parameters.get<std::string>("input_rec_hits_collection", "EcalRecHits");
26
27 input_pass_name_ = parameters.get<std::string>("input_pass_name", "");
28
29 sim_particles_passname_ =
30 parameters.get<std::string>("sim_particles_passname");
31
32 sim_particles_events_passname_ =
33 parameters.get<std::string>("sim_particles_events_passname");
34
35 // the uncertainty is sigma_x = 6 microns and sigma_y = 20./sqrt(12)
36 recoil_uncertainty_ =
37 parameters.get<std::vector<double>>("recoil_uncertainty", {0.006, 0.085});
38 ecal_uncertainty_ = parameters.get<double>("ecal_uncertainty", {3.87});
39 ecal_distance_threshold_ = parameters.get<double>("ecal_distance_threshold");
40 ecal_first_layer_z_threshold_ =
41 parameters.get<double>("ecal_first_layer_z_threshold");
42
43 layer12_midpoint_ = parameters.get<double>("layer12_midpoint");
44 layer23_midpoint_ = parameters.get<double>("layer23_midpoint");
45 layer34_midpoint_ = parameters.get<double>("layer34_midpoint");
46}
std::string getName() const
Get the processor name.
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
std::string out_seed_collection_
The name of the output collection of seeds to be stored.
std::string input_hits_collection_
The name of the input hits collection to use in finding seeds..
std::string input_rec_hits_collection_
The name of the tagger Tracks (only for Recoil Seeding)

References framework::config::Parameters::get(), framework::EventProcessor::getName(), input_hits_collection_, input_rec_hits_collection_, and out_seed_collection_.

◆ convertToLdmxStdArray()

std::array< double, 3 > tracking::reco::LinearSeedFinder::convertToLdmxStdArray ( const Acts::Vector3 & vec)
protected

Definition at line 429 of file LinearSeedFinder.cxx.

430 {
431 return {vec.x(), vec.y(), vec.z()};
432}

◆ dotProduct()

double tracking::reco::LinearSeedFinder::dotProduct ( const Acts::Vector3 & v1,
const Acts::Vector3 & v2 )
protected

Definition at line 537 of file LinearSeedFinder.cxx.

538 {
539 return v1.dot(v2);
540}

◆ fit3DLine()

std::tuple< double, double, double, double, std::vector< double > > tracking::reco::LinearSeedFinder::fit3DLine ( const std::array< double, 3 > & first_recoil,
const std::array< double, 3 > & second_recoil,
const std::array< double, 3 > & ecal )
protected

Definition at line 543 of file LinearSeedFinder.cxx.

545 {
546 double z_pos1 = first_recoil[0], x_pos1 = first_recoil[1],
547 y_pos1 = first_recoil[2];
548 double z_pos2 = second_recoil[0], x_pos2 = second_recoil[1],
549 y_pos2 = second_recoil[2];
550 double z_pos3 = ecal[0], x_pos3 = ecal[1], y_pos3 = ecal[2];
551
552 std::array<double, 6> weights = {
553 1 / pow(recoil_uncertainty_[0], 2), 1 / pow(recoil_uncertainty_[1], 2),
554 1 / pow(recoil_uncertainty_[0], 2), 1 / pow(recoil_uncertainty_[1], 2),
555 1 / pow(ecal_uncertainty_, 2), 1 / pow(ecal_uncertainty_, 2)};
556
557 Eigen::Matrix<double, 6, 4> a_mat;
558 Eigen::Matrix<double, 6, 1> d_vec, w_vec;
559
560 // Fill the A matrix (z, 1, 0, 0) for x and (0, 0, z, 1) for y
561 a_mat << z_pos1, 1, 0, 0, 0, 0, z_pos1, 1, z_pos2, 1, 0, 0, 0, 0, z_pos2, 1,
562 z_pos3, 1, 0, 0, 0, 0, z_pos3, 1;
563
564 // Fill the d vector with x and y values
565 d_vec << x_pos1, y_pos1, x_pos2, y_pos2, x_pos3, y_pos3;
566
567 // Fill the weights vector
568 w_vec = Eigen::Matrix<double, 6, 1>(weights.data());
569
570 // Solve the weighted least squares system
571 Eigen::MatrixXd at_w_a = a_mat.transpose() * w_vec.asDiagonal() * a_mat;
572 Eigen::MatrixXd at_w_d = a_mat.transpose() * w_vec.asDiagonal() * d_vec;
573 Eigen::VectorXd param_vec = at_w_a.ldlt().solve(at_w_d);
574
575 Eigen::Matrix4d covariance_matrix = at_w_a.inverse();
576
577 // Store only the upper triangular part of the covariance matrix since it is
578 // symmetric
579 std::vector<double> covariance_vector = {
580 covariance_matrix(0, 0), covariance_matrix(0, 1), covariance_matrix(0, 2),
581 covariance_matrix(0, 3), covariance_matrix(1, 1), covariance_matrix(1, 2),
582 covariance_matrix(1, 3), covariance_matrix(2, 2), covariance_matrix(2, 3),
583 covariance_matrix(3, 3)};
584
585 // return {slope_x, intercept_x, slope_y, intercept_y, covariance}
586 return {param_vec(0), param_vec(1), param_vec(2), param_vec(3),
587 covariance_vector};
588} // fit3DLine

◆ getPointAtZ()

std::array< double, 3 > tracking::reco::LinearSeedFinder::getPointAtZ ( std::array< double, 3 > target,
std::array< double, 3 > measurement,
double z_target )
protected

Definition at line 325 of file LinearSeedFinder.cxx.

327 {
328 double slope_x = (measurement[1] - target[0]) / (measurement[0] - target[2]);
329 double slope_y = (measurement[2] - target[1]) / (measurement[0] - target[2]);
330
331 double intercept_x = target[0] - slope_x * target[2];
332 double intercept_y = target[1] - slope_y * target[2];
333
334 double x_target = slope_x * z_target + intercept_x;
335 double y_target = slope_y * z_target + intercept_y;
336
337 return {z_target, x_target, y_target};
338}

◆ getSurfaceVectors()

std::tuple< Acts::Vector3, Acts::Vector3, Acts::Vector3 > tracking::reco::LinearSeedFinder::getSurfaceVectors ( const Acts::Surface & surface)
protected

Definition at line 437 of file LinearSeedFinder.cxx.

437 {
438 Acts::Vector3 dummy{0., 0., 0.};
439 Acts::Vector3 u =
440 surface.localToGlobal(geometryContext(), Acts::Vector2(1, 0), dummy) -
441 surface.center(geometryContext());
442 Acts::Vector3 v =
443 surface.localToGlobal(geometryContext(), Acts::Vector2(0, 1), dummy) -
444 surface.center(geometryContext());
445 Acts::Vector3 w = u.cross(v).normalized();
446 return {u.normalized(), v.normalized(), w};
447}

◆ globalChiSquare()

double tracking::reco::LinearSeedFinder::globalChiSquare ( const std::array< double, 3 > & first_sensor,
const std::array< double, 3 > & second_sensor,
const std::array< double, 3 > & ecal_hit,
double a_x,
double a_y,
double b_x,
double b_y )
protected

Definition at line 595 of file LinearSeedFinder.cxx.

599 {
600 double chi2_x = 0, chi2_y = 0;
601 chi2_x += pow(
602 (m_x * first_sensor[0] + b_x - first_sensor[1]) / recoil_uncertainty_[0],
603 2);
604 chi2_y += pow(
605 (m_y * first_sensor[0] + b_y - first_sensor[2]) / recoil_uncertainty_[1],
606 2);
607
608 chi2_x += pow((m_x * second_sensor[0] + b_x - second_sensor[1]) /
609 recoil_uncertainty_[0],
610 2);
611 chi2_y += pow((m_y * second_sensor[0] + b_y - second_sensor[2]) /
612 recoil_uncertainty_[1],
613 2);
614
615 chi2_x += pow((m_x * ecal_hit[0] + b_x - ecal_hit[1]) / ecal_uncertainty_, 2);
616 chi2_y += pow((m_y * ecal_hit[0] + b_y - ecal_hit[2]) / ecal_uncertainty_, 2);
617
618 return chi2_x + chi2_y;
619} // globalChiSquare

◆ onProcessEnd()

void tracking::reco::LinearSeedFinder::onProcessEnd ( )
overridevirtual

Output event statistics.

Reimplemented from framework::EventProcessor.

Definition at line 317 of file LinearSeedFinder.cxx.

317 {
318 ldmx_log(info) << "AVG Time/Event: " << std::fixed << std::setprecision(1)
319 << processing_time_ / n_events_ << " ms";
320 ldmx_log(info) << "Total Seeds/Events: " << n_seeds_ << "/" << n_events_;
321 ldmx_log(info) << "not enough seed points " << n_missing_;
322
323} // onProcessEnd

◆ onProcessStart()

void tracking::reco::LinearSeedFinder::onProcessStart ( )
overridevirtual

Setup the truth matching.

Reimplemented from framework::EventProcessor.

Definition at line 12 of file LinearSeedFinder.cxx.

12 {
13 truth_matching_tool_ = std::make_shared<tracking::sim::TruthMatchingTool>();
14}

◆ processMeasurements()

std::vector< std::tuple< std::array< double, 3 >, std::tuple< ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit >, std::optional< std::tuple< ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit > > > > tracking::reco::LinearSeedFinder::processMeasurements ( const std::vector< std::tuple< ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit > > & measurements,
const geo::TrackersTrackingGeometry & tg )
protected

Definition at line 345 of file LinearSeedFinder.cxx.

348 {
349 std::vector<
350 std::tuple<ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit>>
351 axial_measurements;
352 std::vector<
353 std::tuple<ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit>>
354 stereo_measurements;
355 std::vector<std::tuple<
356 std::array<double, 3>,
357 std::tuple<ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit>,
358 std::optional<std::tuple<ldmx::Measurement, ldmx::SimTrackerHit,
360 points_with_measurement;
361 Acts::Vector3 dummy{0., 0., 0.};
362
363 // Separate measurements into axial and stereo based on layerID
364 for (const auto& [measurement, sim_hit, scoring_hit] : measurements) {
365 if (measurement.getLayerID() % 2 == 0) {
366 axial_measurements.emplace_back(measurement, sim_hit, scoring_hit);
367 } else {
368 stereo_measurements.emplace_back(measurement, sim_hit, scoring_hit);
369 }
370 }
371
372 // If there are measurements in both axial and stereo layer_:
373 // Iterate over axial and stereo measurements to compute 3D points
374 if (!axial_measurements.empty() && !stereo_measurements.empty()) {
375 for (const auto& axial : axial_measurements) {
376 const auto& [axial_meas, axial_hit, axial_sp] = axial;
377
378 for (const auto& stereo : stereo_measurements) {
379 const auto& [stereo_meas, stereo_hit, stereo_sp] = stereo;
380
381 const Acts::Surface* axial_surface =
382 tg.getSurface(axial_meas.getLayerID());
383 const Acts::Surface* stereo_surface =
384 tg.getSurface(stereo_meas.getLayerID());
385
386 if (!axial_surface || !stereo_surface) continue;
387
388 std::vector<ldmx::SimTrackerHit> sim_hits = {axial_hit, stereo_hit};
389 Acts::Vector3 space_point =
390 simple3DHitV2(axial_meas, *axial_surface, stereo_meas,
391 *stereo_surface, axial_sp, sim_hits);
392
393 points_with_measurement.push_back(
394 {convertToLdmxStdArray(space_point), axial, stereo});
395 }
396 }
397 } else if (!axial_measurements.empty()) {
398 // if there are only axial measurements, take them to be our sensor points
399 for (const auto& axial : axial_measurements) {
400 const auto& [axial_meas, axial_hit, axial_sp] = axial;
401 const Acts::Surface* axial_surface =
402 tg.getSurface(axial_meas.getLayerID());
403
404 Acts::Vector3 axial_meas_hit = axial_surface->localToGlobal(
405 geometryContext(),
406 Acts::Vector2(axial_meas.getLocalPosition()[0], 0.0), dummy);
407
408 points_with_measurement.push_back(
409 {convertToLdmxStdArray(axial_meas_hit), axial, std::nullopt});
410 }
411 } else if (!stereo_measurements.empty()) {
412 for (const auto& stereo : stereo_measurements) {
413 const auto& [stereo_meas, stereo_hit, stereo_sp] = stereo;
414 const Acts::Surface* stereo_surface =
415 tg.getSurface(stereo_meas.getLayerID());
416
417 Acts::Vector3 stereo_meas_hit = stereo_surface->localToGlobal(
418 geometryContext(),
419 Acts::Vector2(stereo_meas.getLocalPosition()[0], 0.0), dummy);
420
421 points_with_measurement.push_back(
422 {convertToLdmxStdArray(stereo_meas_hit), stereo, std::nullopt});
423 }
424 }
425 return points_with_measurement;
426}
Represents a simulated tracker hit in the simulation.

◆ produce()

void tracking::reco::LinearSeedFinder::produce ( framework::Event & event)
overridevirtual

Run the processor and create a collection of results which indicate if a charge particle can be found by the recoil tracker.

Parameters
eventThe event to process.

Implements framework::Producer.

Definition at line 48 of file LinearSeedFinder.cxx.

48 {
49 auto start = std::chrono::high_resolution_clock::now();
50 std::vector<ldmx::StraightTrack> straight_seed_tracks;
51 n_events_++;
52 auto tg{geometry()};
53
54 const std::vector<ldmx::Measurement> recoil_hits =
55 event.getCollection<ldmx::Measurement>(input_hits_collection_,
56 input_pass_name_);
57 const std::vector<ldmx::EcalHit> ecal_rec_hit =
58 event.getCollection<ldmx::EcalHit>(input_rec_hits_collection_,
59 input_pass_name_);
60
61 std::vector<std::array<double, 3>> first_layer_ecal_rec_hits;
62
63 // Find RecHits at first layer_ of ECal
64 for (const auto& x_ecal : ecal_rec_hit) {
65 if (x_ecal.getZPos() < ecal_first_layer_z_threshold_) {
66 first_layer_ecal_rec_hits.push_back(
67 {x_ecal.getZPos(), x_ecal.getXPos(), x_ecal.getYPos()});
68 } // if first layer_ of Ecal
69 } // for positions in ecalRecHit
70
71 // Check if we would fit empty seeds, if so: end tracking
72 if ((recoil_hits.size() < 2) || (first_layer_ecal_rec_hits.empty()) ||
73 (uniqueLayersHit(recoil_hits) < 2)) {
74 n_missing_++;
75 n_seeds_ += straight_seed_tracks.size();
76 event.add(out_seed_collection_, straight_seed_tracks);
77 return;
78 }
79
80 // Setup truth map
81 std::map<int, ldmx::SimParticle> particle_map;
82 if (event.exists("SimParticles", sim_particles_events_passname_)) {
83 particle_map = event.getMap<int, ldmx::SimParticle>(
84 "SimParticles", sim_particles_passname_);
85 truth_matching_tool_->setup(particle_map, recoil_hits);
86 }
87
88 std::vector<
89 std::tuple<ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit>>
90 first_two_layers;
91 std::vector<
92 std::tuple<ldmx::Measurement, ldmx::SimTrackerHit, ldmx::SimTrackerHit>>
93 second_two_layers;
94
95 const std::vector<ldmx::SimTrackerHit> recoil_sim_hits =
96 event.getCollection<ldmx::SimTrackerHit>("RecoilSimHits",
97 input_pass_name_);
98 const std::vector<ldmx::SimTrackerHit> scoring_hits =
99 event.getCollection<ldmx::SimTrackerHit>("TargetScoringPlaneHits",
100 input_pass_name_);
101
102 // Index all sim hits_ by track ID
103 std::unordered_map<int, std::vector<const ldmx::SimTrackerHit*>>
104 sim_hits_by_track_id;
105 for (const auto& hit : recoil_sim_hits) {
106 sim_hits_by_track_id[hit.getTrackID()].push_back(&hit);
107 } // for sim hits_
108
109 // Index scoring hits_ by track ID (one positive scoring plane hit / ID)
110 std::unordered_map<int, const ldmx::SimTrackerHit*> scoring_hit_map;
111 for (const auto& sp_hit : scoring_hits) {
112 if (sp_hit.getPosition()[2] > 0)
113 scoring_hit_map[sp_hit.getTrackID()] = &sp_hit;
114 } // for sp hits_
115
116 for (const auto& point : recoil_hits) {
117 // x is in tracking coordinates, z is in ldmx coordinates
118 float x = point.getGlobalPosition()[0];
119 int track_id = point.getTrackIds()[0];
120
121 // get the key value = track_id
122 auto sim_range_it = sim_hits_by_track_id.find(track_id);
123 if (sim_range_it == sim_hits_by_track_id.end()) continue;
124
125 // access map value at track_id
126 const auto& sim_hits = sim_range_it->second;
127
128 for (const auto* sim_hit : sim_hits) {
129 float z = sim_hit->getPosition()[2];
130
131 if (x < layer12_midpoint_) {
132 if (z < layer12_midpoint_) {
133 auto sp_it = scoring_hit_map.find(track_id);
134 if (sp_it != scoring_hit_map.end()) {
135 first_two_layers.emplace_back(point, *sim_hit, *sp_it->second);
136 break;
137 } // add the associated scoring plane hit (will be needed for 3D
138 // reconstruction)
139 } // associate 1st layer_ sim hit
140 } // check if recoil hit is 1st layer_
141 else if (x < layer23_midpoint_) {
142 if (z > layer12_midpoint_ && z < layer23_midpoint_) {
143 first_two_layers.emplace_back(point, *sim_hit, ldmx::SimTrackerHit());
144 break;
145 } // associate 2nd layer_ sim hit
146 } // check if recoil hit is 2nd layer_
147 else if (x < layer34_midpoint_) {
148 if (z > layer23_midpoint_ && z < layer34_midpoint_) {
149 auto sp_it = scoring_hit_map.find(track_id);
150 if (sp_it != scoring_hit_map.end()) {
151 second_two_layers.emplace_back(point, *sim_hit, *sp_it->second);
152 break;
153 } // add the associated scoring plane hit (will be needed for 3D
154 // reconstruction)
155 } // associate 3rd layer_ sim hits_
156 } // check if recoil hit is 3rd layer_
157 else {
158 if (z > layer34_midpoint_) {
159 second_two_layers.emplace_back(point, *sim_hit,
161 break;
162 } // associate 4th layer_ sim hits_
163 } // check if recoil hits_ is 4th layer_
164
165 } // loop through simhits
166 } // loop through recoil hits_
167
168 // Reconstruct 3D sensor points on which to do fitting
169 auto first_sensor_combos = processMeasurements(first_two_layers, tg);
170 auto second_sensor_combos = processMeasurements(second_two_layers, tg);
171
172 for (const auto& [first_combo_3d_point, first_layer_one, first_layer_two] :
173 first_sensor_combos) {
174 std::tuple<std::array<double, 3>, ldmx::Measurement,
175 std::optional<ldmx::Measurement>>
176 first_sensor_point;
177
178 if (first_layer_two.has_value()) {
179 first_sensor_point = {first_combo_3d_point,
180 std::get<ldmx::Measurement>(first_layer_one),
181 std::get<ldmx::Measurement>(*first_layer_two)};
182 } // check whether we did reconstruction or...
183 else {
184 first_sensor_point = {first_combo_3d_point,
185 std::get<ldmx::Measurement>(first_layer_one),
186 std::nullopt};
187 } //...we are taking only one layer_ as the measurement (axial or stereo)
188
189 for (const auto& [second_combo_3d_point, second_layer_one,
190 second_layer_two] : second_sensor_combos) {
191 std::tuple<std::array<double, 3>, ldmx::Measurement,
192 std::optional<ldmx::Measurement>>
193 second_sensor_point;
194 if (second_layer_two.has_value()) {
195 second_sensor_point = {second_combo_3d_point,
196 std::get<ldmx::Measurement>(second_layer_one),
197 std::get<ldmx::Measurement>(*second_layer_two)};
198 } // check whether we did reconstruction or...
199 else {
200 second_sensor_point = {second_combo_3d_point,
201 std::get<ldmx::Measurement>(second_layer_one),
202 std::nullopt};
203 } //...we are taking only one layer_ as the measurement (axial or stereo)
204
205 for (const auto& rec_hit : first_layer_ecal_rec_hits) {
206 // Do fitting on 2 sensor + 1 recHit combinations = 1 degree of freedom
207 // for linear fit
208 ldmx::StraightTrack seed_track =
209 seedTracker(first_sensor_point, second_sensor_point, rec_hit);
210
211 // Seed passed RecHit distance check, add it
212 if (seed_track.getChi2() > 0.0) {
213 straight_seed_tracks.push_back(seed_track);
214 } // if chi2 > 0
215 } // for rec_hits
216 } // for second recoil tracker
217 } // for first recoil tracker
218
219 n_seeds_ += straight_seed_tracks.size();
220 event.add(out_seed_collection_, straight_seed_tracks);
221
222 auto end = std::chrono::high_resolution_clock::now();
223
224 auto diff = end - start;
225 processing_time_ += std::chrono::duration<double, std::milli>(diff).count();
226
227 first_layer_ecal_rec_hits.clear();
228 straight_seed_tracks.clear();
229
230} // produce
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:92
Stores reconstructed hit information from the ECAL.
Definition EcalHit.h:19
Class representing a simulated particle.
Definition SimParticle.h:23

References framework::Event::exists(), input_hits_collection_, input_rec_hits_collection_, and out_seed_collection_.

◆ seedTracker()

ldmx::StraightTrack tracking::reco::LinearSeedFinder::seedTracker ( const std::tuple< std::array< double, 3 >, ldmx::Measurement, std::optional< ldmx::Measurement > > recoil_one,
const std::tuple< std::array< double, 3 >, ldmx::Measurement, std::optional< ldmx::Measurement > > recoil_two,
const std::array< double, 3 > ecal_one )
protected

Definition at line 232 of file LinearSeedFinder.cxx.

239 {
240 auto [sensor1, layer1, layer2] = recoil_one;
241 auto [sensor2, layer3, layer4] = recoil_two;
242 std::vector<ldmx::Measurement> all_points;
243
244 // TODO: in the case where we don't have all 4 hits_, we will be fitting a
245 // sensor (weighted average of two layers) + single layer_
246 // TODO: or fitting two single layers. Currently, the single layer_ point has
247 // the uncertainty of a sensor assigned to it,
248 // TODO: but this is not a realistic uncertainty for a single layer_...
249 // IF all layers are well-defined, this sequence will add layer1, 2, 3, 4 to
250 // the allPoints vector
251 all_points.push_back(layer1);
252
253 // if layer2 doesn't exist (has_value == False), then the layer1 we added
254 // is either layer1 or 2, depending on which one has_value
255 if (layer2.has_value()) {
256 all_points.push_back(*layer2);
257 }
258
259 all_points.push_back(layer3);
260
261 // if layer4 doesn't exist (has_value == False), then the layer3 we added
262 // is either layer3 or 4, depending on which one has_value
263 if (layer4.has_value()) {
264 all_points.push_back(*layer4);
265 }
266
267 // Fit the 3 points to a 3D straight line, find track location at first layer_
268 // of Ecal, check distance to recHit used in fitting
269 // m = slope ; b = intercept
270 auto [m_x, b_x, m_y, b_y, seed_cov] = fit3DLine(sensor1, sensor2, ecal_one);
271 std::array<double, 3> temp_extrapolated_point = {
272 ecal_one[0], m_x * ecal_one[0] + b_x, m_y * ecal_one[0] + b_y};
273 double temp_distance = calculateDistance(temp_extrapolated_point, ecal_one);
274
276
277 if (temp_distance < ecal_distance_threshold_) {
278 trk.setSlopeX(m_x);
279 trk.setInterceptX(b_x);
280 trk.setSlopeY(m_y);
281 trk.setInterceptY(b_y);
282 trk.setTheta(std::atan2(m_y, std::sqrt(1 + m_x * m_x)));
283 trk.setPhi(std::atan2(m_x, 1.0));
284
285 trk.setAllSensorPoints(all_points);
286 trk.setFirstSensorPosition(sensor1);
287 trk.setSecondSensorPosition(sensor2);
288 trk.setFirstLayerEcalRecHit(ecal_one);
289 trk.setDistancetoRecHit(temp_distance);
290
291 trk.setTargetLocation(0.0, b_x, b_y);
292 trk.setEcalLayer1Location(temp_extrapolated_point);
293 trk.setChi2(
294 globalChiSquare(sensor1, sensor2, ecal_one, m_x, m_y, b_x, b_y));
295 trk.setNhits(3);
296 trk.setNdf(1);
297
298 trk.setCov(seed_cov);
299
300 // truth matching
301 if (truth_matching_tool_->configured()) {
302 auto truth_info = truth_matching_tool_->truthMatch(all_points);
303 trk.setTrackID(truth_info.track_id_);
304 trk.setPdgID(truth_info.pdg_id_);
305 trk.setTruthProb(truth_info.truth_prob_);
306 }
307
308 return trk;
309
310 } // if (track is close enough to EcalRecHit)
311 else {
312 trk.setChi2(-1);
313 return trk;
314 } // else (does not pass the threshold)
315} // SeedTracker

◆ simple3DHitV2()

Acts::Vector3 tracking::reco::LinearSeedFinder::simple3DHitV2 ( const ldmx::Measurement & axial,
const Acts::Surface & axial_surface,
const ldmx::Measurement & stereo,
const Acts::Surface & stereo_surface,
const ldmx::SimTrackerHit & hitOnTarget,
std::vector< ldmx::SimTrackerHit > pair_sim_hits )
protected

Definition at line 458 of file LinearSeedFinder.cxx.

462 {
463 Acts::Vector3 dummy{0., 0., 0.};
464 Acts::Vector3 hit_on_target{target_sp.getPosition()[0],
465 target_sp.getPosition()[1],
466 target_sp.getPosition()[2]}; // x,y,z
467
468 Acts::Vector3 axial_true_global{pair_sim_hits[0].getPosition()[0],
469 pair_sim_hits[0].getPosition()[1],
470 pair_sim_hits[0].getPosition()[2]};
471 // stereo_true_global is unused
472 Acts::Vector3 stereo_true_global{pair_sim_hits[1].getPosition()[0],
473 pair_sim_hits[1].getPosition()[1],
474 pair_sim_hits[1].getPosition()[2]};
475
476 Acts::Vector3 simpart_path = axial_true_global - hit_on_target;
477 Acts::Vector3 simpart_unit = simpart_path.normalized();
478
479 // Get global positions for strip origins .... actually these are in
480 // tracking coordinates!
481 Acts::Vector3 axial_origin = axial_surface.center(geometryContext());
482 Acts::Vector3 stereo_origin = stereo_surface.center(geometryContext());
483
484 // the tracking-global vector difference between stereo and axial sensor
485 // centers
486 Acts::Vector3 delta_sensors = stereo_origin - axial_origin;
487
488 // calculate the displacement in tracking global x (need to generalize) by
489 // going from tracking x=axial to x=stereo
490 double dx_proj = (simpart_unit[0] / simpart_unit[2]) *
491 delta_sensors[0]; // this looks weird because simpart_unit
492 // is in global-global and delta sensors
493 // is in tracking-global
494
495 // Compute unit vectors for both hits_
496 auto [axial_u, axial_v, axial_w] = getSurfaceVectors(axial_surface);
497 auto [stereo_u, stereo_v, stereo_w] = getSurfaceVectors(stereo_surface);
498 double salpha = dotProduct(axial_v, stereo_u);
499 double cosalpha = dotProduct(axial_u, stereo_u);
500
501 // Get sensor local measured coordinates
502 // Get local position components
503 auto [axial_u_value, axial_v_value] = axial.getLocalPosition();
504 auto [stereo_u_value, stereo_v_value] = stereo.getLocalPosition();
505
506 // Manual correction, since v should always be 0 (insensitive direction)
507 axial_v_value = 0.0;
508 stereo_v_value = 0.0;
509
510 // use the dx_proj as the displacement in u of the axial measurement
511 // it's axial_u_value - dx_proj because u is in the -x direction
512 // this calculation is in the axial frame
513 double v_intercept_useproj =
514 (stereo_u_value - (axial_u_value - dx_proj) * cosalpha) / salpha;
515 double u_intercept_useproj = axial_u_value - dx_proj;
516
517 // convert to tracking global
518 Acts::Vector3 axst_global_useproj = axial_surface.localToGlobal(
519 geometryContext(),
520 Acts::Vector2(u_intercept_useproj, v_intercept_useproj), dummy);
521 Acts::Vector3 dummy_stereo_proj = stereo_surface.localToGlobal(
522 geometryContext(),
523 Acts::Vector2(u_intercept_useproj, v_intercept_useproj), dummy);
524
525 // we want the reconstructed hit to be at the z of the stereo layer
526 Acts::Vector3 reconstructed_hit{dummy_stereo_proj[0], axst_global_useproj[1],
527 axst_global_useproj[2]};
528
529 ldmx_log(debug) << "The particle projected axst measured position is "
530 "(compare with stereo sim position): "
531 << reconstructed_hit[0] << ", " << reconstructed_hit[1]
532 << ", " << reconstructed_hit[2] << "\n";
533
534 return reconstructed_hit;
535}
std::array< float, 2 > getLocalPosition() const
Definition Measurement.h:65

◆ uniqueLayersHit()

int tracking::reco::LinearSeedFinder::uniqueLayersHit ( const std::vector< ldmx::Measurement > & digi_points)
protected

Definition at line 621 of file LinearSeedFinder.cxx.

622 {
623 std::vector<ldmx::Measurement> sorted_points = digi_points;
624
625 // Sort by z position in the Recoil
626 std::sort(sorted_points.begin(), sorted_points.end(),
627 [](const ldmx::Measurement& meas1, const ldmx::Measurement& meas2) {
628 return meas1.getGlobalPosition()[0] <
629 meas2.getGlobalPosition()[0];
630 });
631
632 // Remove duplicates to ensure we only keep unique z positions
633 auto last = std::unique(
634 sorted_points.begin(), sorted_points.end(),
635 [](const ldmx::Measurement& meas1, const ldmx::Measurement& meas2) {
636 return meas1.getGlobalPosition()[0] == meas2.getGlobalPosition()[0];
637 });
638
639 // return the number of unique layer_ hits_
640 return std::distance(sorted_points.begin(), last);
641} // uniqueLayersHit

Member Data Documentation

◆ ecal_distance_threshold_

double tracking::reco::LinearSeedFinder::ecal_distance_threshold_ {10.0}
protected

Definition at line 136 of file LinearSeedFinder.h.

136{10.0};

◆ ecal_first_layer_z_threshold_

double tracking::reco::LinearSeedFinder::ecal_first_layer_z_threshold_ {250.0}
protected

Definition at line 142 of file LinearSeedFinder.h.

142{250.0};

◆ ecal_uncertainty_

double tracking::reco::LinearSeedFinder::ecal_uncertainty_ {3.87}
protected

Definition at line 134 of file LinearSeedFinder.h.

134{3.87};

◆ input_hits_collection_

std::string tracking::reco::LinearSeedFinder::input_hits_collection_ {"DigiRecoilSimHits"}
protected

The name of the input hits collection to use in finding seeds..

Definition at line 129 of file LinearSeedFinder.h.

129{"DigiRecoilSimHits"};

Referenced by configure(), and produce().

◆ input_pass_name_

std::string tracking::reco::LinearSeedFinder::input_pass_name_ {""}
protected

Definition at line 132 of file LinearSeedFinder.h.

132{""};

◆ input_rec_hits_collection_

std::string tracking::reco::LinearSeedFinder::input_rec_hits_collection_ {"EcalRecHits"}
protected

The name of the tagger Tracks (only for Recoil Seeding)

Definition at line 131 of file LinearSeedFinder.h.

131{"EcalRecHits"};

Referenced by configure(), and produce().

◆ layer12_midpoint_

double tracking::reco::LinearSeedFinder::layer12_midpoint_ {12.5}
protected

Definition at line 139 of file LinearSeedFinder.h.

139{12.5};

◆ layer23_midpoint_

double tracking::reco::LinearSeedFinder::layer23_midpoint_ {20.0}
protected

Definition at line 140 of file LinearSeedFinder.h.

140{20.0};

◆ layer34_midpoint_

double tracking::reco::LinearSeedFinder::layer34_midpoint_ {27.5}
protected

Definition at line 141 of file LinearSeedFinder.h.

141{27.5};

◆ n_events_

long tracking::reco::LinearSeedFinder::n_events_ {0}
protected

Definition at line 123 of file LinearSeedFinder.h.

123{0};

◆ n_missing_

long tracking::reco::LinearSeedFinder::n_missing_ {0}
protected

Definition at line 147 of file LinearSeedFinder.h.

147{0};

◆ n_seeds_

unsigned int tracking::reco::LinearSeedFinder::n_seeds_ {0}
protected

Definition at line 124 of file LinearSeedFinder.h.

124{0};

◆ next_event_passname_

std::string tracking::reco::LinearSeedFinder::next_event_passname_
private

Definition at line 154 of file LinearSeedFinder.h.

◆ out_seed_collection_

std::string tracking::reco::LinearSeedFinder::out_seed_collection_ {"LinearRecoilSeedTracks"}
protected

The name of the output collection of seeds to be stored.

Definition at line 127 of file LinearSeedFinder.h.

127{"LinearRecoilSeedTracks"};

Referenced by configure(), and produce().

◆ processing_time_

double tracking::reco::LinearSeedFinder::processing_time_ {0.}
protected

Definition at line 122 of file LinearSeedFinder.h.

122{0.};

◆ recoil_uncertainty_

std::vector<double> tracking::reco::LinearSeedFinder::recoil_uncertainty_ {0.006, 0.085}
protected

Definition at line 144 of file LinearSeedFinder.h.

144{0.006, 0.085};

◆ sim_particles_events_passname_

std::string tracking::reco::LinearSeedFinder::sim_particles_events_passname_
private

Definition at line 156 of file LinearSeedFinder.h.

◆ sim_particles_passname_

std::string tracking::reco::LinearSeedFinder::sim_particles_passname_
private

Definition at line 155 of file LinearSeedFinder.h.

◆ truth_matching_tool_

std::shared_ptr<tracking::sim::TruthMatchingTool> tracking::reco::LinearSeedFinder::truth_matching_tool_
protected
Initial value:
=
nullptr

Definition at line 150 of file LinearSeedFinder.h.


The documentation for this class was generated from the following files: