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::EcalGeometrygeometry_
 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
 
NtupleManagerntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 38 of file EcalMipTrackingProcessor.h.

Member Typedef Documentation

◆ CellEnergyPair

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

Definition at line 40 of file EcalMipTrackingProcessor.h.

◆ HitData

◆ XYCoords

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

Definition at line 42 of file EcalMipTrackingProcessor.h.

Constructor & Destructor Documentation

◆ EcalMipTrackingProcessor()

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

Definition at line 44 of file EcalMipTrackingProcessor.h.

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

22 {
23 // MIP tracking
29}
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 11 of file EcalMipTrackingProcessor.cxx.

12 {
13 n_ecal_layers_ = parameters.get<int>("num_ecal_layers");
14 linreg_radius_ = parameters.get<double>("linreg_radius");
15 ecal_collection_name_ = parameters.get<std::string>("ecal_collection_name");
16 ecal_pass_name_ = parameters.get<std::string>("ecal_pass_name");
17 mip_collection_name_ = parameters.get<std::string>("mip_collection_name");
18 mip_pass_name_ = parameters.get<std::string>("mip_pass_name");
19 mip_result_name_ = parameters.get<std::string>("mip_result_name");
20}
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78

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 5 of file EcalMipTrackingProcessor.cxx.

5 {
6 profiling_map_["straight_tracks"] = 0.;
7 profiling_map_["linreg_tracks"] = 0.;
8 profiling_map_["processing_time_"] = 0;
9}

◆ 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 497 of file EcalMipTrackingProcessor.cxx.

497 {
498 ldmx_log(info) << "AVG Time/Event: " << std::fixed << std::setprecision(2)
499 << processing_time_ / nevents_ << " ms";
500
501 ldmx_log(info) << "Breakdown::";
502
503 ldmx_log(info) << "straight_tracks Avg Time/Event = " << std::fixed
504 << std::setprecision(3)
505 << profiling_map_["straight_tracks"] / nevents_ << " ms";
506
507 ldmx_log(info) << "linreg_tracks Avg Time/Event = " << std::fixed
508 << std::setprecision(3)
509 << profiling_map_["linreg_tracks"] / nevents_ << " ms";
510}

◆ 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 31 of file EcalMipTrackingProcessor.cxx.

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

100{"EcalVeto"};

◆ ecal_pass_name_

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

Definition at line 101 of file EcalMipTrackingProcessor.h.

101{""};

◆ 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 94 of file EcalMipTrackingProcessor.h.

94{0};

Referenced by produce().

◆ geometry_

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

handle to current geometry (to share with member functions)

Definition at line 107 of file EcalMipTrackingProcessor.h.

Referenced by produce().

◆ linreg_radius_

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

Definition at line 82 of file EcalMipTrackingProcessor.h.

82{0};

◆ mip_collection_name_

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

Definition at line 102 of file EcalMipTrackingProcessor.h.

102{"EcalTrajectoryInfo"};

◆ mip_pass_name_

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

Definition at line 103 of file EcalMipTrackingProcessor.h.

103{""};

◆ mip_result_name_

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

Definition at line 104 of file EcalMipTrackingProcessor.h.

104{"EcalMipResult"};

◆ n_ecal_layers_

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

Definition at line 84 of file EcalMipTrackingProcessor.h.

84{0};

◆ n_linreg_tracks_

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

Number of "linreg" tracks found in the event.

Definition at line 91 of file EcalMipTrackingProcessor.h.

91{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 96 of file EcalMipTrackingProcessor.h.

96{0};

Referenced by produce().

◆ n_readout_hits_

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

Definition at line 85 of file EcalMipTrackingProcessor.h.

85{0};

◆ n_straight_tracks_

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

Number of "straight" tracks found in the event.

Definition at line 89 of file EcalMipTrackingProcessor.h.

89{0};

Referenced by produce().

◆ nevents_

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

Definition at line 77 of file EcalMipTrackingProcessor.h.

77{0};

◆ photon_territory_hits_

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

Number of hits in the photon territory.

Definition at line 98 of file EcalMipTrackingProcessor.h.

98{0};

Referenced by produce().

◆ processing_time_

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

Definition at line 78 of file EcalMipTrackingProcessor.h.

78{0.};

◆ profiling_map_

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

Definition at line 80 of file EcalMipTrackingProcessor.h.


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