LDMX Software
ecal::EcalMipTrackingProcessor Class Reference

Public Types

typedef std::pair< ldmx::EcalID, float > CellEnergyPair
 
using XYCoords = ldmx::XYCoords
 
using HitData = ldmx::HitData
 

Public Member Functions

 EcalMipTrackingProcessor (const std::string &name, framework::Process &process)
 
void onNewRun (const ldmx::RunHeader &rh) override
 onNewRun is the first function called for each processor after the conditions are fully configured and accessible.
 
void onProcessEnd () override
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
void configure (framework::config::Parameters &parameters) override
 Configure the processor using the given user specified parameters.
 
void produce (framework::Event &event) override
 Process the event and put new data products into it.
 
- 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 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.
 
virtual void onProcessStart ()
 Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.
 
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.
 

Private Member Functions

void clearProcessor ()
 

Private Attributes

int nevents_ {0}
 
double processing_time_ {0.}
 
std::map< std::string, double > profiling_map_
 
double linreg_radius_ {0}
 
int n_ecal_layers_ {0}
 
int n_readout_hits_ {0}
 
int n_straight_tracks_ {0}
 Number of "straight" tracks found in the event.
 
int n_linreg_tracks_ {0}
 Number of "linreg" tracks found in the event.
 
int first_near_ph_layer_ {0}
 Earliest ECal layer in which a hit is found near the projected photon trajectory.
 
int n_near_ph_hits_ {0}
 Number of hits near the photon trajectory.
 
int photon_territory_hits_ {0}
 Number of hits in the photon territory.
 
std::string ecal_collection_name_ {"EcalVeto"}
 
std::string ecal_pass_name_ {""}
 
std::string mip_collection_name_ {"EcalTrajectoryInfo"}
 
std::string mip_pass_name_ {""}
 
std::string mip_result_name_ {"EcalMipResult"}
 
const ldmx::EcalGeometry * geometry_
 handle to current geometry (to share with member functions)
 

Additional Inherited Members

- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 24 of file EcalMipTrackingProcessor.h.

Member Typedef Documentation

◆ CellEnergyPair

std::pair<ldmx::EcalID, float> ecal::EcalMipTrackingProcessor::CellEnergyPair

Definition at line 26 of file EcalMipTrackingProcessor.h.

◆ HitData

◆ XYCoords

using ecal::EcalMipTrackingProcessor::XYCoords = ldmx::XYCoords

Definition at line 28 of file EcalMipTrackingProcessor.h.

Constructor & Destructor Documentation

◆ EcalMipTrackingProcessor()

ecal::EcalMipTrackingProcessor::EcalMipTrackingProcessor ( const std::string & name,
framework::Process & process )
inline

Definition at line 30 of file EcalMipTrackingProcessor.h.

31 : Producer(name, process) {}
Producer(const std::string &name, Process &process)
Class constructor.
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.

Member Function Documentation

◆ clearProcessor()

void ecal::EcalMipTrackingProcessor::clearProcessor ( )
private

Definition at line 33 of file EcalMipTrackingProcessor.cxx.

33 {
34 // MIP tracking
40}
int photon_territory_hits_
Number of hits in the photon territory.
int n_linreg_tracks_
Number of "linreg" tracks found in the event.
int n_near_ph_hits_
Number of hits near the photon trajectory.
int first_near_ph_layer_
Earliest ECal layer in which a hit is found near the projected photon trajectory.
int n_straight_tracks_
Number of "straight" tracks found in the event.

◆ configure()

void ecal::EcalMipTrackingProcessor::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 22 of file EcalMipTrackingProcessor.cxx.

23 {
24 n_ecal_layers_ = parameters.get<int>("num_ecal_layers");
25 linreg_radius_ = parameters.get<double>("linreg_radius");
26 ecal_collection_name_ = parameters.get<std::string>("ecal_collection_name");
27 ecal_pass_name_ = parameters.get<std::string>("ecal_pass_name");
28 mip_collection_name_ = parameters.get<std::string>("mip_collection_name");
29 mip_pass_name_ = parameters.get<std::string>("mip_pass_name");
30 mip_result_name_ = parameters.get<std::string>("mip_result_name");
31}
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75

References framework::config::Parameters::get().

◆ onNewRun()

void ecal::EcalMipTrackingProcessor::onNewRun ( const ldmx::RunHeader & rh)
overridevirtual

onNewRun is the first function called for each processor after the conditions are fully configured and accessible.

This is where you could create single-processors, multi-event calculation objects.

Reimplemented from framework::EventProcessor.

Definition at line 16 of file EcalMipTrackingProcessor.cxx.

16 {
17 profiling_map_["straight_tracks"] = 0.;
18 profiling_map_["linreg_tracks"] = 0.;
19 profiling_map_["processing_time_"] = 0;
20}

◆ onProcessEnd()

void ecal::EcalMipTrackingProcessor::onProcessEnd ( )
overridevirtual

Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.

Reimplemented from framework::EventProcessor.

Definition at line 508 of file EcalMipTrackingProcessor.cxx.

508 {
509 ldmx_log(info) << "AVG Time/Event: " << std::fixed << std::setprecision(2)
510 << processing_time_ / nevents_ << " ms";
511
512 ldmx_log(info) << "Breakdown::";
513
514 ldmx_log(info) << "straight_tracks Avg Time/Event = " << std::fixed
515 << std::setprecision(3)
516 << profiling_map_["straight_tracks"] / nevents_ << " ms";
517
518 ldmx_log(info) << "linreg_tracks Avg Time/Event = " << std::fixed
519 << std::setprecision(3)
520 << profiling_map_["linreg_tracks"] / nevents_ << " ms";
521}

◆ produce()

void ecal::EcalMipTrackingProcessor::produce ( framework::Event & event)
overridevirtual

Process the event and put new data products into it.

Parameters
eventThe Event to process.

Implements framework::Producer.

Definition at line 42 of file EcalMipTrackingProcessor.cxx.

42 {
43 auto start = std::chrono::high_resolution_clock::now();
44
45 ldmx::EcalMipResult mip_result;
46 clearProcessor();
47
48 // Get the Ecal Geometry
50 ldmx::EcalGeometry::CONDITIONS_OBJECT_NAME);
51
52 // Read in hits near photon from EcalVetoProcessor
53 auto ecal_veto_result = event.getObject<ldmx::EcalVetoResult>(
54 ecal_collection_name_, ecal_pass_name_);
55 auto ecal_trajectory_info = event.getObject<ldmx::EcalTrajectoryInfo>(
56 mip_collection_name_, mip_pass_name_);
57 std::vector<XYCoords> ele_trajectory, photon_trajectory,
58 ele_trajectory_at_target;
59 std::vector<ldmx::HitData> tracking_hit_list;
60 ldmx_log(trace) << "EcalMipTrackingProcessor::produce() called";
61 ele_trajectory = ecal_trajectory_info.getEleTrajectory();
62 photon_trajectory = ecal_trajectory_info.getPhotonTrajectory();
63 tracking_hit_list = ecal_trajectory_info.getTrackingHitList();
64 n_readout_hits_ = ecal_veto_result.getNReadoutHits();
65 nevents_++;
66 // Now inputting Lines 753-1178 of the original EcalVetoProcessor
67 // ------------------------------------------------------
68 // MIP tracking starts here
69
70 /* Goal: Calculate
71 * n_straight_tracks (self-explanatory),
72 * n_linreg_tracks (tracks found by linreg algorithm),
73 */
74
75 // Find epAng and epSep, and prepare EP trajectory vectors:
76 ROOT::Math::XYZVector e_traj_start;
77 ROOT::Math::XYZVector e_traj_end;
78 ROOT::Math::XYZVector p_traj_start;
79 ROOT::Math::XYZVector p_traj_end;
80 if (!ele_trajectory.empty() && !photon_trajectory.empty()) {
81 // Create TVector3s marking the start and endpoints of each projected
82 // trajectory
83 e_traj_start.SetXYZ(ele_trajectory[0].first, ele_trajectory[0].second,
85 e_traj_end.SetXYZ(ele_trajectory[(n_ecal_layers_ - 1)].first,
86 ele_trajectory[(n_ecal_layers_ - 1)].second,
87 geometry_->getZPosition((n_ecal_layers_ - 1)));
88 p_traj_start.SetXYZ(photon_trajectory[0].first, photon_trajectory[0].second,
90 p_traj_end.SetXYZ(photon_trajectory[(n_ecal_layers_ - 1)].first,
91 photon_trajectory[(n_ecal_layers_ - 1)].second,
92 geometry_->getZPosition((n_ecal_layers_ - 1)));
93 } else {
94 // Electron trajectory is missing, so place trajectories far outside the
95 // ECal to ensure they don't interfere with tracking.
96 e_traj_start = ROOT::Math::XYZVector(999, 999, geometry_->getZPosition(0));
97 e_traj_end = ROOT::Math::XYZVector(
98 999, 999, geometry_->getZPosition((n_ecal_layers_ - 1)));
99 p_traj_start =
100 ROOT::Math::XYZVector(1000, 1000, geometry_->getZPosition(0));
101 p_traj_end = ROOT::Math::XYZVector(
102 1000, 1000, geometry_->getZPosition((n_ecal_layers_ - 1)));
103 }
104 // Near photon step: Find the first layer_ of the ECal where a hit near the
105 // projected photon trajectory is found Currently unusued pending further
106 // study; performance has dropped between v9 and v12. Currently used in
107 // segmipBDT
108 first_near_ph_layer_ = n_ecal_layers_ - 1;
109
110 // If no photon trajectory, leave this at the default (ECal back)
111 ldmx_log(trace) << "Finding first near photon layer_";
112 if (!photon_trajectory.empty()) {
113 for (std::vector<ldmx::HitData>::iterator it = tracking_hit_list.begin();
114 it != tracking_hit_list.end(); ++it) {
115 float eh_dist =
116 sqrt(pow((*it).pos_.X() - photon_trajectory[(*it).layer_].first, 2) +
117 pow((*it).pos_.Y() - photon_trajectory[(*it).layer_].second, 2));
118 // TODO: this 8.7 should be not hardcoded
119 if (eh_dist < 8.7) {
121 if ((*it).layer_ < first_near_ph_layer_) {
122 first_near_ph_layer_ = (*it).layer_;
123 }
124 }
125 }
126 ldmx_log(trace) << "First near photon layer_: " << first_near_ph_layer_;
127 }
128
129 // Territories limited to tracking_hit_list
130 ROOT::Math::XYZVector g_toe = (e_traj_start - p_traj_start).Unit();
131 // TODO what is this 8.7 here???
132 ROOT::Math::XYZVector origin = p_traj_start + 0.5 * 8.7 * g_toe;
133 ldmx_log(trace) << "Origin of photon territory: " << origin.X() << ", "
134 << origin.Y() << ", " << origin.Z();
135 if (!ele_trajectory.empty()) {
136 for (auto& hit_data : tracking_hit_list) {
137 ROOT::Math::XYZVector hit_pos = hit_data.pos_;
138 ROOT::Math::XYZVector hit_prime = hit_pos - origin;
139 if (hit_prime.Dot(g_toe) <= 0) {
141 }
142 }
143 ldmx_log(trace) << "Photon territory hits: " << photon_territory_hits_;
144 } else {
145 photon_territory_hits_ = n_readout_hits_;
146 }
147
148 // ------------------------------------------------------
149 // Find straight MIP tracks:
150
151 std::sort(
152 tracking_hit_list.begin(), tracking_hit_list.end(),
153 [](ldmx::HitData ha, ldmx::HitData hb) { return ha.layer_ > hb.layer_; });
154 // For merging tracks: Need to keep track of existing tracks
155 // Candidate tracks to merge in will always be in front of the current track
156 // (lower z_), so only store the last hit 3-layer_ vector: each track =
157 // vector of 3-tuples (xy+layer_).
158 std::vector<std::vector<ldmx::HitData>> track_list;
159
160 // print tracking_hit_list
161
162 ldmx_log(trace) << "====== Tracking hit list (original) length "
163 << tracking_hit_list.size() << " ======";
164 for (int i = 0; i < tracking_hit_list.size(); i++) {
165 ldmx_log(trace) << "[" << tracking_hit_list[i].pos_.X() << ", "
166 << tracking_hit_list[i].pos_.Y() << ", "
167 << tracking_hit_list[i].layer_ << "], ";
168 }
169 ldmx_log(trace) << "====== END OF Tracking hit list ======";
170
171 // in v14 minR is 4.17 mm
172 // while maxR is 4.81 mm
173 float cell_width = 2 * geometry_->getCellMaxR();
174 for (int i_hit = 0; i_hit < tracking_hit_list.size(); i_hit++) {
175 // list of hit numbers in track (34 = maximum theoretical length)
176 int track[34];
177 int current_hit{i_hit};
178 int track_len{1};
179
180 track[0] = i_hit;
181
182 // Search for hits to add to the track:
183 // repeatedly find hits in the front two layers with same x- & y-positions
184 // but since v14 the odd layers are offset, so we allow half a cell_width
185 // deviation and then add to track until no more hits are found
186 int j_hit = i_hit;
187 while (j_hit < tracking_hit_list.size()) {
188 if ((tracking_hit_list[j_hit].layer_ ==
189 tracking_hit_list[current_hit].layer_ - 1 ||
190 tracking_hit_list[j_hit].layer_ ==
191 tracking_hit_list[current_hit].layer_ - 2) &&
192 std::abs(tracking_hit_list[j_hit].pos_.X() -
193 tracking_hit_list[current_hit].pos_.X()) <=
194 0.5 * cell_width &&
195 std::abs(tracking_hit_list[j_hit].pos_.Y() -
196 tracking_hit_list[current_hit].pos_.Y()) <=
197 0.5 * cell_width) {
198 track[track_len] = j_hit;
199 track_len++;
200 current_hit = j_hit;
201 }
202 j_hit++;
203 }
204
205 // Confirm that the track is valid:
206 if (track_len < 2) continue; // Track must contain at least 2 hits
207 float closest_e = ecal::distTwoLines(
208 tracking_hit_list[track[0]].pos_,
209 tracking_hit_list[track[track_len - 1]].pos_, e_traj_start, e_traj_end);
210 float closest_p = ecal::distTwoLines(
211 tracking_hit_list[track[0]].pos_,
212 tracking_hit_list[track[track_len - 1]].pos_, p_traj_start, p_traj_end);
213 // Make sure that the track is near the photon trajectory and away from the
214 // electron trajectory Details of these constraints may be revised
215 if (closest_p > cell_width and closest_e < 2 * cell_width) continue;
216 if (track_len < 4 and closest_e > closest_p) continue;
217
218 ldmx_log(debug) << "====== After rejection for MIP tracking ======";
219 ldmx_log(debug) << "current hit: [" << tracking_hit_list[i_hit].pos_.X()
220 << ", " << tracking_hit_list[i_hit].pos_.Y() << ", "
221 << tracking_hit_list[i_hit].layer_ << "]";
222
223 for (int k = 0; k < track_len; k++) {
224 ldmx_log(debug) << "track[" << k << "] position = ["
225 << tracking_hit_list[track[k]].pos_.X() << ", "
226 << tracking_hit_list[track[k]].pos_.Y() << ", "
227 << tracking_hit_list[track[k]].layer_ << "]";
228 }
229
230 // if track found, increment n_straight_tracks and remove all hits in track
231 // from future consideration
232 if (track_len >= 2) {
233 std::vector<ldmx::HitData> temp_track_list;
234 int n_remove = 0;
235 for (int k_hit = 0; k_hit < track_len; k_hit++) {
236 temp_track_list.push_back(tracking_hit_list[track[k_hit] - n_remove]);
237 tracking_hit_list.erase(tracking_hit_list.begin() + track[k_hit] -
238 n_remove);
239 n_remove++;
240 }
241 // print tracking_hit_list
242
243 ldmx_log(trace) << "====== Tracking hit list (after erase) length "
244 << tracking_hit_list.size() << " ======";
245 for (int i = 0; i < tracking_hit_list.size(); i++) {
246 ldmx_log(trace) << "[" << tracking_hit_list[i].pos_.X() << ", "
247 << tracking_hit_list[i].pos_.Y() << ", "
248 << tracking_hit_list[i].layer_ << "] ";
249 }
250 ldmx_log(trace) << "====== END OF Tracking hit list ======";
251
252 track_list.push_back(temp_track_list);
253 // The *current* hit will have been removed, so i_hit is currently
254 // pointing to the next hit. Decrement i_hit so no hits will get skipped
255 // by i_hit++
256 i_hit--;
257 }
258 }
259
260 ldmx_log(debug) << "Straight tracks found (before merge): "
261 << track_list.size();
262
263 for (int i_track = 0; i_track < track_list.size(); i_track++) {
264 ldmx_log(trace) << "Track " << i_track << ":";
265 for (int i_hit = 0; i_hit < track_list[i_track].size(); i_hit++) {
266 ldmx_log(trace) << " Hit " << i_hit << ": ["
267 << track_list[i_track][i_hit].pos_.X() << ", "
268 << track_list[i_track][i_hit].pos_.Y() << ", "
269 << track_list[i_track][i_hit].layer_ << "]" << std::endl;
270 }
271 }
272
273 // Optional addition: Merge nearby straight tracks. Not necessary for veto.
274 // Criteria: consider tail of track. Merge if head of next track is 1/2
275 // layers behind, within 1 cell of xy position.
276 ldmx_log(debug) << "Beginning track merging using " << track_list.size()
277 << " tracks";
278
279 for (int track_i = 0; track_i < track_list.size(); track_i++) {
280 // for each track, check the remainder of the track list for compatible
281 // tracks
282 std::vector<ldmx::HitData> base_track = track_list[track_i];
283 ldmx::HitData tail_hitdata =
284 base_track.back(); // xylayer of last hit in track
285 ldmx_log(trace) << " Considering track " << track_i;
286 for (int track_j = track_i + 1; track_j < track_list.size(); track_j++) {
287 std::vector<ldmx::HitData> checking_track = track_list[track_j];
288 if (checking_track.empty()) {
289 ldmx_log(error) << "Broken logic: a straight ecal track had no hits in "
290 "it during merge.";
291 continue;
292 }
293 ldmx::HitData head_hitdata = checking_track.front();
294 // if 1-2 layers behind, and xy within one cell...
295 if ((head_hitdata.layer_ == tail_hitdata.layer_ + 1 ||
296 head_hitdata.layer_ == tail_hitdata.layer_ + 2) &&
297 pow(pow(head_hitdata.pos_.X() - tail_hitdata.pos_.X(), 2) +
298 pow(head_hitdata.pos_.Y() - tail_hitdata.pos_.Y(), 2),
299 0.5) <= cell_width) {
300 // ...then append the second track to the first one and delete it
301 // NOTE: TO ADD: (tracking_hit_list[i_hit].pos_ -
302 // tracking_hit_list[j_hit].pos_).R()
303 ldmx_log(trace) << " ** Compatible track found at index_ "
304 << track_j;
305 ldmx_log(trace) << " Tail xylayer: " << head_hitdata.pos_.X() << ","
306 << head_hitdata.pos_.Y() << "," << head_hitdata.layer_;
307 ldmx_log(trace) << " Head xylayer: " << tail_hitdata.pos_.X() << ","
308 << tail_hitdata.pos_.Y() << "," << tail_hitdata.layer_;
309 for (int hit_k = 0; hit_k < checking_track.size(); hit_k++) {
310 base_track.push_back(track_list[track_j][hit_k]);
311 }
312 track_list[track_i] = base_track;
313 track_list.erase(track_list.begin() + track_j);
314 break;
315 }
316 }
317 }
318 n_straight_tracks_ = track_list.size();
319 // print the track list
320 ldmx_log(debug) << "Straight tracks found (after merge): "
322 for (int track_i = 0; track_i < track_list.size(); track_i++) {
323 ldmx_log(debug) << "Track " << track_i << ":";
324 for (int hit_i = 0; hit_i < track_list[track_i].size(); hit_i++) {
325 ldmx_log(debug) << " Hit " << hit_i << ": ["
326 << track_list[track_i][hit_i].pos_.X() << ", "
327 << track_list[track_i][hit_i].pos_.Y() << ", "
328 << track_list[track_i][hit_i].layer_ << "]";
329 }
330 }
331
332 auto straight_tracks = std::chrono::high_resolution_clock::now();
333 profiling_map_["straight_tracks"] +=
334 std::chrono::duration<double, std::milli>(straight_tracks - start)
335 .count();
336 // ------------------------------------------------------
337 // Linreg tracking:
338 ldmx_log(info) << "Finding linreg tracks from a total of "
339 << tracking_hit_list.size() << " hits using a radius of "
340 << linreg_radius_ << " mm";
341
342 for (int i_hit = 0; i_hit < 0; i_hit++) {
343 // for (int i_hit = 0; i_hit < tracking_hit_list.size(); i_hit++) {
344 // Hits being considered at a given time
345 std::vector<int> hits_in_region;
346 TMatrixD vm(3, 3);
347 TMatrixD hdt(3, 3);
348 ROOT::Math::XYZVector slope_vec;
349 ROOT::Math::XYZVector h_mean;
350 ROOT::Math::XYZVector h_point;
351 float r_corr_best{0.0};
352 // Temp array having 3 potential hits
353 int hit_nums[3];
354 // From the above which are passing the correlation reqs
355 int best_hit_nums[3];
356
357 hits_in_region.push_back(i_hit);
358 // Find all hits within 2 cells of the primary hit:
359 for (int j_hit = 0; j_hit < tracking_hit_list.size(); j_hit++) {
360 // Dont try to put hits on the same layer_ to the lin-reg track
361 if (tracking_hit_list[i_hit].pos_.Z() ==
362 tracking_hit_list[j_hit].pos_.Z()) {
363 continue;
364 }
365 float dist_to_hit =
366 (tracking_hit_list[i_hit].pos_ - tracking_hit_list[j_hit].pos_).R();
367 // This distance optimized to give the best significance
368 // it used to be 2*cell_width, i.e. 4.81 mm
369 // note, the layers in the back have a separation of 22.3
370 if (dist_to_hit <= 2 * linreg_radius_) {
371 hits_in_region.push_back(j_hit);
372 }
373 }
374 // Found a track that passed the lin-reg reqs
375 bool best_lin_reg_found{false};
376
377 ldmx_log(debug) << "There are " << hits_in_region.size()
378 << " hits within a radius of " << linreg_radius_ << " mm";
379 // Look at combinations of hits within the region (do not consider the same
380 // combination twice):
381 hit_nums[0] = i_hit;
382 for (int j_hit_in_reg = 1; j_hit_in_reg < hits_in_region.size() - 1;
383 j_hit_in_reg++) {
384 // We require (exactly) 3 hits for the lin-reg track building
385 if (hits_in_region.size() < 3) break;
386 hit_nums[1] = hits_in_region[j_hit_in_reg];
387 for (int k_hit_reg = j_hit_in_reg + 1; k_hit_reg < hits_in_region.size();
388 k_hit_reg++) {
389 hit_nums[2] = hits_in_region[k_hit_reg];
390 const auto& p0 = tracking_hit_list[hit_nums[0]].pos_;
391 const auto& p1 = tracking_hit_list[hit_nums[1]].pos_;
392 const auto& p2 = tracking_hit_list[hit_nums[2]].pos_;
393
394 h_mean = (p0 + p1 + p2) / 3.0;
395
396 double p_arr[3][3] = {{p0.X(), p0.Y(), p0.Z()},
397 {p1.X(), p1.Y(), p1.Z()},
398 {p2.X(), p2.Y(), p2.Z()}};
399
400 // Compute mean in an indexable array
401 double mean_arr[3] = {(p0.X() + p1.X() + p2.X()) / 3.0,
402 (p0.Y() + p1.Y() + p2.Y()) / 3.0,
403 (p0.Z() + p1.Z() + p2.Z()) / 3.0};
404
405 for (int h_ind = 0; h_ind < 3; ++h_ind) {
406 for (int l_ind = 0; l_ind < 3; ++l_ind) {
407 hdt(h_ind, l_ind) = p_arr[h_ind][l_ind] - mean_arr[l_ind];
408 }
409 }
410
411 // Perform "linreg" on selected points
412 // Calculate the determinant of the matrix
413 double determinant =
414 hdt(0, 0) * (hdt(1, 1) * hdt(2, 2) - hdt(1, 2) * hdt(2, 1)) -
415 hdt(0, 1) * (hdt(1, 0) * hdt(2, 2) - hdt(1, 2) * hdt(2, 0)) +
416 hdt(0, 2) * (hdt(1, 0) * hdt(2, 1) - hdt(1, 1) * hdt(2, 0));
417 // Exit early if the matrix is singular (i.e. det = 0)
418 if (determinant == 0) continue;
419 // Perform matrix decomposition with SVD
420 TDecompSVD svd_obj(hdt);
421 bool decomposed = svd_obj.Decompose();
422 if (!decomposed) continue;
423
424 // First col of V matrix is the slope of the best-fit line
425 vm = svd_obj.GetV();
426 slope_vec.SetX(vm[0][0]);
427 slope_vec.SetY(vm[0][1]);
428 slope_vec.SetZ(vm[0][2]);
429 // h_mean, h_point are points on the best-fit line
430 h_point = slope_vec + h_mean;
431 // linreg complete: Now have best-fit line for 3 hits under
432 // consideration Check whether the track is valid: r^2 must be high,
433 // and the track must plausibly originate from the photon
434 float closest_e =
435 ecal::distTwoLines(h_mean, h_point, e_traj_start, e_traj_end);
436 float closest_p =
437 ecal::distTwoLines(h_mean, h_point, p_traj_start, p_traj_end);
438 // Projected track must be close to the photon; details may change after
439 // future study.
440 if (closest_p > cell_width or closest_e < 1.5 * cell_width) continue;
441 // find r^2
442 // ~variance
443 float vrnc = (tracking_hit_list[hit_nums[0]].pos_ - h_mean).R() +
444 (tracking_hit_list[hit_nums[1]].pos_ - h_mean).R() +
445 (tracking_hit_list[hit_nums[2]].pos_ - h_mean).R();
446 // sum of |errors|
447 float sumerr = ecal::distPtToLine(tracking_hit_list[hit_nums[0]].pos_,
448 h_mean, h_point) +
449 ecal::distPtToLine(tracking_hit_list[hit_nums[1]].pos_,
450 h_mean, h_point) +
451 ecal::distPtToLine(tracking_hit_list[hit_nums[2]].pos_,
452 h_mean, h_point);
453 float r_corr = 1 - sumerr / vrnc;
454 // Check whether r^2 exceeds a low minimum r_corr: "Fake" tracks are
455 // still much more common in background, so making the algorithm
456 // oversensitive doesn't lower performance significantly
457 if (r_corr > r_corr_best and r_corr > .6) {
458 r_corr_best = r_corr;
459 // Only looking for 3-hit tracks currently
460 best_lin_reg_found = true;
461 for (int k = 0; k < 3; k++) {
462 best_hit_nums[k] = hit_nums[k];
463 }
464 }
465 } // end loop on hits in the region
466 } // end 2nd loop on hits in the region
467
468 // Continue early if not hits on track
469 if (!best_lin_reg_found) continue;
470 // Otherwise increase the number of lin-reg tracks
472 ldmx_log(debug) << " Lin-reg track " << n_linreg_tracks_;
473 for (int final_hit_index = 0; final_hit_index < 3; final_hit_index++) {
474 ldmx_log(debug)
475 << " Hit " << final_hit_index << " ["
476 << tracking_hit_list[best_hit_nums[final_hit_index]].pos_.X() << ", "
477 << tracking_hit_list[best_hit_nums[final_hit_index]].pos_.Y() << ", "
478 << tracking_hit_list[best_hit_nums[final_hit_index]].pos_.Z() << "] ";
479 }
480
481 // Exclude all hits in a found track from further consideration:
482 for (int l_hit = 0; l_hit < 3; l_hit++) {
483 tracking_hit_list.erase(tracking_hit_list.begin() + best_hit_nums[l_hit]);
484 }
485 i_hit--;
486 } // end loop on all hits
487 ldmx_log(info) << " MIP tracking completed; found " << n_straight_tracks_
488 << " straight tracks and " << n_linreg_tracks_
489 << " lin-reg tracks";
490
491 auto linreg_tracks = std::chrono::high_resolution_clock::now();
492 profiling_map_["linreg_tracks"] +=
493 std::chrono::duration<double, std::milli>(linreg_tracks - straight_tracks)
494 .count();
495
496 mip_result.setVariables(n_straight_tracks_, n_linreg_tracks_,
499
500 event.add(mip_result_name_, mip_result);
501
502 auto end = std::chrono::high_resolution_clock::now();
503 auto time_diff = end - start;
504 processing_time_ +=
505 std::chrono::duration<double, std::milli>(time_diff).count();
506}
float distPtToLine(ROOT::Math::XYZVector h1, ROOT::Math::XYZVector p1, ROOT::Math::XYZVector p2)
Return the minimum distance between the point h1 and the line passing through points p1 and p2.
float distTwoLines(ROOT::Math::XYZVector v1, ROOT::Math::XYZVector v2, ROOT::Math::XYZVector w1, ROOT::Math::XYZVector w2)
Returns the distance between the lines v and w, with v defined to pass through the points (v1,...
const ldmx::EcalGeometry * geometry_
handle to current geometry (to share with member functions)
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
double getZPosition(int layer) const
Get the z-coordinate given the layer id.
double getCellMaxR() const
Get the center-to-corner radius of the cell hexagons.

References ecal::distPtToLine(), ecal::distTwoLines(), first_near_ph_layer_, geometry_, ldmx::EcalGeometry::getCellMaxR(), framework::EventProcessor::getCondition(), ldmx::EcalGeometry::getZPosition(), n_linreg_tracks_, n_near_ph_hits_, n_straight_tracks_, and photon_territory_hits_.

Member Data Documentation

◆ ecal_collection_name_

std::string ecal::EcalMipTrackingProcessor::ecal_collection_name_ {"EcalVeto"}
private

Definition at line 86 of file EcalMipTrackingProcessor.h.

86{"EcalVeto"};

◆ ecal_pass_name_

std::string ecal::EcalMipTrackingProcessor::ecal_pass_name_ {""}
private

Definition at line 87 of file EcalMipTrackingProcessor.h.

87{""};

◆ first_near_ph_layer_

int ecal::EcalMipTrackingProcessor::first_near_ph_layer_ {0}
private

Earliest ECal layer in which a hit is found near the projected photon trajectory.

Definition at line 80 of file EcalMipTrackingProcessor.h.

80{0};

Referenced by produce().

◆ geometry_

const ldmx::EcalGeometry* ecal::EcalMipTrackingProcessor::geometry_
private

handle to current geometry (to share with member functions)

Definition at line 93 of file EcalMipTrackingProcessor.h.

Referenced by produce().

◆ linreg_radius_

double ecal::EcalMipTrackingProcessor::linreg_radius_ {0}
private

Definition at line 68 of file EcalMipTrackingProcessor.h.

68{0};

◆ mip_collection_name_

std::string ecal::EcalMipTrackingProcessor::mip_collection_name_ {"EcalTrajectoryInfo"}
private

Definition at line 88 of file EcalMipTrackingProcessor.h.

88{"EcalTrajectoryInfo"};

◆ mip_pass_name_

std::string ecal::EcalMipTrackingProcessor::mip_pass_name_ {""}
private

Definition at line 89 of file EcalMipTrackingProcessor.h.

89{""};

◆ mip_result_name_

std::string ecal::EcalMipTrackingProcessor::mip_result_name_ {"EcalMipResult"}
private

Definition at line 90 of file EcalMipTrackingProcessor.h.

90{"EcalMipResult"};

◆ n_ecal_layers_

int ecal::EcalMipTrackingProcessor::n_ecal_layers_ {0}
private

Definition at line 70 of file EcalMipTrackingProcessor.h.

70{0};

◆ n_linreg_tracks_

int ecal::EcalMipTrackingProcessor::n_linreg_tracks_ {0}
private

Number of "linreg" tracks found in the event.

Definition at line 77 of file EcalMipTrackingProcessor.h.

77{0};

Referenced by produce().

◆ n_near_ph_hits_

int ecal::EcalMipTrackingProcessor::n_near_ph_hits_ {0}
private

Number of hits near the photon trajectory.

Definition at line 82 of file EcalMipTrackingProcessor.h.

82{0};

Referenced by produce().

◆ n_readout_hits_

int ecal::EcalMipTrackingProcessor::n_readout_hits_ {0}
private

Definition at line 71 of file EcalMipTrackingProcessor.h.

71{0};

◆ n_straight_tracks_

int ecal::EcalMipTrackingProcessor::n_straight_tracks_ {0}
private

Number of "straight" tracks found in the event.

Definition at line 75 of file EcalMipTrackingProcessor.h.

75{0};

Referenced by produce().

◆ nevents_

int ecal::EcalMipTrackingProcessor::nevents_ {0}
private

Definition at line 63 of file EcalMipTrackingProcessor.h.

63{0};

◆ photon_territory_hits_

int ecal::EcalMipTrackingProcessor::photon_territory_hits_ {0}
private

Number of hits in the photon territory.

Definition at line 84 of file EcalMipTrackingProcessor.h.

84{0};

Referenced by produce().

◆ processing_time_

double ecal::EcalMipTrackingProcessor::processing_time_ {0.}
private

Definition at line 64 of file EcalMipTrackingProcessor.h.

64{0.};

◆ profiling_map_

std::map<std::string, double> ecal::EcalMipTrackingProcessor::profiling_map_
private

Definition at line 66 of file EcalMipTrackingProcessor.h.


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