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

492 {
493 ldmx_log(info) << "AVG Time/Event: " << std::fixed << std::setprecision(2)
494 << processing_time_ / nevents_ << " ms";
495
496 ldmx_log(info) << "Breakdown::";
497
498 ldmx_log(info) << "straight_tracks Avg Time/Event = " << std::fixed
499 << std::setprecision(3)
500 << profiling_map_["straight_tracks"] / nevents_ << " ms";
501
502 ldmx_log(info) << "linreg_tracks Avg Time/Event = " << std::fixed
503 << std::setprecision(3)
504 << profiling_map_["linreg_tracks"] / nevents_ << " ms";
505}

◆ 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 ldmx::HitData head_hitdata = checking_track.front();
278 // if 1-2 layers behind, and xy within one cell...
279 if ((head_hitdata.layer_ == tail_hitdata.layer_ + 1 ||
280 head_hitdata.layer_ == tail_hitdata.layer_ + 2) &&
281 pow(pow(head_hitdata.pos_.X() - tail_hitdata.pos_.X(), 2) +
282 pow(head_hitdata.pos_.Y() - tail_hitdata.pos_.Y(), 2),
283 0.5) <= cell_width) {
284 // ...then append the second track to the first one and delete it
285 // NOTE: TO ADD: (tracking_hit_list[i_hit].pos_ -
286 // tracking_hit_list[j_hit].pos_).R()
287 ldmx_log(trace) << " ** Compatible track found at index_ "
288 << track_j;
289 ldmx_log(trace) << " Tail xylayer: " << head_hitdata.pos_.X() << ","
290 << head_hitdata.pos_.Y() << "," << head_hitdata.layer_;
291 ldmx_log(trace) << " Head xylayer: " << tail_hitdata.pos_.X() << ","
292 << tail_hitdata.pos_.Y() << "," << tail_hitdata.layer_;
293 for (int hit_k = 0; hit_k < checking_track.size(); hit_k++) {
294 base_track.push_back(track_list[track_j][hit_k]);
295 }
296 track_list[track_i] = base_track;
297 track_list.erase(track_list.begin() + track_j);
298 break;
299 }
300 }
301 }
302 n_straight_tracks_ = track_list.size();
303 // print the track list
304 ldmx_log(debug) << "Straight tracks found (after merge): "
306 for (int track_i = 0; track_i < track_list.size(); track_i++) {
307 ldmx_log(debug) << "Track " << track_i << ":";
308 for (int hit_i = 0; hit_i < track_list[track_i].size(); hit_i++) {
309 ldmx_log(debug) << " Hit " << hit_i << ": ["
310 << track_list[track_i][hit_i].pos_.X() << ", "
311 << track_list[track_i][hit_i].pos_.Y() << ", "
312 << track_list[track_i][hit_i].layer_ << "]";
313 }
314 }
315
316 auto straight_tracks = std::chrono::high_resolution_clock::now();
317 profiling_map_["straight_tracks"] +=
318 std::chrono::duration<double, std::milli>(straight_tracks - start)
319 .count();
320 // ------------------------------------------------------
321 // Linreg tracking:
322 ldmx_log(info) << "Finding linreg tracks from a total of "
323 << tracking_hit_list.size() << " hits using a radius of "
324 << linreg_radius_ << " mm";
325
326 for (int i_hit = 0; i_hit < 0; i_hit++) {
327 // for (int i_hit = 0; i_hit < tracking_hit_list.size(); i_hit++) {
328 // Hits being considered at a given time
329 std::vector<int> hits_in_region;
330 TMatrixD vm(3, 3);
331 TMatrixD hdt(3, 3);
332 ROOT::Math::XYZVector slope_vec;
333 ROOT::Math::XYZVector h_mean;
334 ROOT::Math::XYZVector h_point;
335 float r_corr_best{0.0};
336 // Temp array having 3 potential hits
337 int hit_nums[3];
338 // From the above which are passing the correlation reqs
339 int best_hit_nums[3];
340
341 hits_in_region.push_back(i_hit);
342 // Find all hits within 2 cells of the primary hit:
343 for (int j_hit = 0; j_hit < tracking_hit_list.size(); j_hit++) {
344 // Dont try to put hits on the same layer_ to the lin-reg track
345 if (tracking_hit_list[i_hit].pos_.Z() ==
346 tracking_hit_list[j_hit].pos_.Z()) {
347 continue;
348 }
349 float dist_to_hit =
350 (tracking_hit_list[i_hit].pos_ - tracking_hit_list[j_hit].pos_).R();
351 // This distance optimized to give the best significance
352 // it used to be 2*cell_width, i.e. 4.81 mm
353 // note, the layers in the back have a separation of 22.3
354 if (dist_to_hit <= 2 * linreg_radius_) {
355 hits_in_region.push_back(j_hit);
356 }
357 }
358 // Found a track that passed the lin-reg reqs
359 bool best_lin_reg_found{false};
360
361 ldmx_log(debug) << "There are " << hits_in_region.size()
362 << " hits within a radius of " << linreg_radius_ << " mm";
363 // Look at combinations of hits within the region (do not consider the same
364 // combination twice):
365 hit_nums[0] = i_hit;
366 for (int j_hit_in_reg = 1; j_hit_in_reg < hits_in_region.size() - 1;
367 j_hit_in_reg++) {
368 // We require (exactly) 3 hits for the lin-reg track building
369 if (hits_in_region.size() < 3) break;
370 hit_nums[1] = hits_in_region[j_hit_in_reg];
371 for (int k_hit_reg = j_hit_in_reg + 1; k_hit_reg < hits_in_region.size();
372 k_hit_reg++) {
373 hit_nums[2] = hits_in_region[k_hit_reg];
374 const auto &p0 = tracking_hit_list[hit_nums[0]].pos_;
375 const auto &p1 = tracking_hit_list[hit_nums[1]].pos_;
376 const auto &p2 = tracking_hit_list[hit_nums[2]].pos_;
377
378 h_mean = (p0 + p1 + p2) / 3.0;
379
380 double p_arr[3][3] = {{p0.X(), p0.Y(), p0.Z()},
381 {p1.X(), p1.Y(), p1.Z()},
382 {p2.X(), p2.Y(), p2.Z()}};
383
384 // Compute mean in an indexable array
385 double mean_arr[3] = {(p0.X() + p1.X() + p2.X()) / 3.0,
386 (p0.Y() + p1.Y() + p2.Y()) / 3.0,
387 (p0.Z() + p1.Z() + p2.Z()) / 3.0};
388
389 for (int h_ind = 0; h_ind < 3; ++h_ind) {
390 for (int l_ind = 0; l_ind < 3; ++l_ind) {
391 hdt(h_ind, l_ind) = p_arr[h_ind][l_ind] - mean_arr[l_ind];
392 }
393 }
394
395 // Perform "linreg" on selected points
396 // Calculate the determinant of the matrix
397 double determinant =
398 hdt(0, 0) * (hdt(1, 1) * hdt(2, 2) - hdt(1, 2) * hdt(2, 1)) -
399 hdt(0, 1) * (hdt(1, 0) * hdt(2, 2) - hdt(1, 2) * hdt(2, 0)) +
400 hdt(0, 2) * (hdt(1, 0) * hdt(2, 1) - hdt(1, 1) * hdt(2, 0));
401 // Exit early if the matrix is singular (i.e. det = 0)
402 if (determinant == 0) continue;
403 // Perform matrix decomposition with SVD
404 TDecompSVD svd_obj(hdt);
405 bool decomposed = svd_obj.Decompose();
406 if (!decomposed) continue;
407
408 // First col of V matrix is the slope of the best-fit line
409 vm = svd_obj.GetV();
410 slope_vec.SetX(vm[0][0]);
411 slope_vec.SetY(vm[0][1]);
412 slope_vec.SetZ(vm[0][2]);
413 // h_mean, h_point are points on the best-fit line
414 h_point = slope_vec + h_mean;
415 // linreg complete: Now have best-fit line for 3 hits under
416 // consideration Check whether the track is valid: r^2 must be high,
417 // and the track must plausibly originate from the photon
418 float closest_e =
419 ecal::distTwoLines(h_mean, h_point, e_traj_start, e_traj_end);
420 float closest_p =
421 ecal::distTwoLines(h_mean, h_point, p_traj_start, p_traj_end);
422 // Projected track must be close to the photon; details may change after
423 // future study.
424 if (closest_p > cell_width or closest_e < 1.5 * cell_width) continue;
425 // find r^2
426 // ~variance
427 float vrnc = (tracking_hit_list[hit_nums[0]].pos_ - h_mean).R() +
428 (tracking_hit_list[hit_nums[1]].pos_ - h_mean).R() +
429 (tracking_hit_list[hit_nums[2]].pos_ - h_mean).R();
430 // sum of |errors|
431 float sumerr = ecal::distPtToLine(tracking_hit_list[hit_nums[0]].pos_,
432 h_mean, h_point) +
433 ecal::distPtToLine(tracking_hit_list[hit_nums[1]].pos_,
434 h_mean, h_point) +
435 ecal::distPtToLine(tracking_hit_list[hit_nums[2]].pos_,
436 h_mean, h_point);
437 float r_corr = 1 - sumerr / vrnc;
438 // Check whether r^2 exceeds a low minimum r_corr: "Fake" tracks are
439 // still much more common in background, so making the algorithm
440 // oversensitive doesn't lower performance significantly
441 if (r_corr > r_corr_best and r_corr > .6) {
442 r_corr_best = r_corr;
443 // Only looking for 3-hit tracks currently
444 best_lin_reg_found = true;
445 for (int k = 0; k < 3; k++) {
446 best_hit_nums[k] = hit_nums[k];
447 }
448 }
449 } // end loop on hits in the region
450 } // end 2nd loop on hits in the region
451
452 // Continue early if not hits on track
453 if (!best_lin_reg_found) continue;
454 // Otherwise increase the number of lin-reg tracks
456 ldmx_log(debug) << " Lin-reg track " << n_linreg_tracks_;
457 for (int final_hit_index = 0; final_hit_index < 3; final_hit_index++) {
458 ldmx_log(debug)
459 << " Hit " << final_hit_index << " ["
460 << tracking_hit_list[best_hit_nums[final_hit_index]].pos_.X() << ", "
461 << tracking_hit_list[best_hit_nums[final_hit_index]].pos_.Y() << ", "
462 << tracking_hit_list[best_hit_nums[final_hit_index]].pos_.Z() << "] ";
463 }
464
465 // Exclude all hits in a found track from further consideration:
466 for (int l_hit = 0; l_hit < 3; l_hit++) {
467 tracking_hit_list.erase(tracking_hit_list.begin() + best_hit_nums[l_hit]);
468 }
469 i_hit--;
470 } // end loop on all hits
471 ldmx_log(info) << " MIP tracking completed; found " << n_straight_tracks_
472 << " straight tracks and " << n_linreg_tracks_
473 << " lin-reg tracks";
474
475 auto linreg_tracks = std::chrono::high_resolution_clock::now();
476 profiling_map_["linreg_tracks"] +=
477 std::chrono::duration<double, std::milli>(linreg_tracks - straight_tracks)
478 .count();
479
480 mip_result.setVariables(n_straight_tracks_, n_linreg_tracks_,
483
484 event.add(mip_result_name_, mip_result);
485
486 auto end = std::chrono::high_resolution_clock::now();
487 auto time_diff = end - start;
488 processing_time_ +=
489 std::chrono::duration<double, std::milli>(time_diff).count();
490}
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: