Process the event and put new data products into it.
192 {
193 auto start = std::chrono::high_resolution_clock::now();
194 nevents_++;
195
196
198 ldmx::EcalGeometry::CONDITIONS_OBJECT_NAME);
199
201
202 clearProcessor();
203
204
205
206
207 std::array<float, 3> recoilP = {0., 0., 0.};
208 std::array<float, 3> recoilPos = {-9999., -9999., -9999.};
209 std::array<float, 3> recoilPAtTarget = {0., 0., 0.};
210 std::array<float, 3> recoilPosAtTarget = {-9999., -9999., -9999.};
211
212 auto setup = std::chrono::high_resolution_clock::now();
213 profiling_map_["setup"] +=
214 std::chrono::duration<float, std::milli>(setup - start).count();
215
216 if (!recoil_from_tracking_ &&
217 event.
exists(
"EcalScoringPlaneHits", sp_pass_name_)) {
218 ldmx_log(trace) << " Loop through all of the sim particles and find the "
219 "recoil electron";
220
221
222
223
224
226
227
229
230
232 "EcalScoringPlaneHits", sp_pass_name_)};
233 float pmax = 0;
236 auto ecal_sp_momentum = spHit.getMomentum();
237 auto ecal_sp_position = spHit.getPosition();
238 if (hit_id.plane() != 31 || ecal_sp_momentum[2] <= 0) continue;
239
240 if (spHit.getTrackID() == recoilTrackID) {
241
242 if (sqrt((ecal_sp_momentum[0] * ecal_sp_momentum[0]) +
243 (ecal_sp_momentum[1] * ecal_sp_momentum[1]) +
244 (ecal_sp_momentum[2] * ecal_sp_momentum[2])) > pmax) {
245 recoilP = {static_cast<float>(ecal_sp_momentum[0]),
246 static_cast<float>(ecal_sp_momentum[1]),
247 static_cast<float>(ecal_sp_momentum[2])};
248 recoilPos = {(ecal_sp_position[0]), (ecal_sp_position[1]),
249 (ecal_sp_position[2])};
250 pmax = sqrt(recoilP[0] * recoilP[0] + recoilP[1] * recoilP[1] +
251 recoilP[2] * recoilP[2]);
252 }
253 }
254 }
255
256
257 if (event.
exists(
"TargetScoringPlaneHits", sp_pass_name_)) {
258 std::vector<ldmx::SimTrackerHit> targetSpHits =
260 sp_pass_name_);
261 pmax = 0;
264 auto target_sp_momentum = spHit.getMomentum();
265 auto target_sp_position = spHit.getPosition();
266 if (hit_id.plane() != 1 || target_sp_momentum[2] <= 0) continue;
267
268 if (spHit.getTrackID() == recoilTrackID) {
269 if (sqrt((target_sp_momentum[0] * target_sp_momentum[0]) +
270 (target_sp_momentum[1] * target_sp_momentum[1]) +
271 (target_sp_momentum[2] * target_sp_momentum[2])) > pmax) {
272 recoilPAtTarget = {static_cast<float>(target_sp_momentum[0]),
273 static_cast<float>(target_sp_momentum[1]),
274 static_cast<float>(target_sp_momentum[2])};
275 recoilPosAtTarget = {target_sp_position[0], target_sp_position[1],
276 target_sp_position[2]};
277
278 pmax = sqrt((recoilPAtTarget[0] * recoilPAtTarget[0]) +
279 (recoilPAtTarget[1] * recoilPAtTarget[1]) +
280 (recoilPAtTarget[2] * recoilPAtTarget[2]));
281 }
282 }
283 }
284 }
285 }
286
287
288 bool fiducial_in_tracker{false};
289 if (recoil_from_tracking_) {
290 ldmx_log(trace) << " Get recoil tracks collection";
291
292
293 auto recoil_tracks{
294 event.getCollection<
ldmx::Track>(track_collection_, track_pass_name_)};
295
296 ldmx_log(trace) << " Propagate the recoil ele to the ECAL";
297 ldmx::TrackStateType ts_type = ldmx::TrackStateType::AtECAL;
298 auto recoil_track_states_ecal =
trackProp(recoil_tracks, ts_type,
"ecal");
299 ldmx_log(trace) << " Propagate the recoil ele to the Target";
300 ldmx::TrackStateType ts_type_target = ldmx::TrackStateType::AtTarget;
301 auto recoil_track_states_target =
302 trackProp(recoil_tracks, ts_type_target,
"target");
303
304 ldmx_log(trace) << " Set recoilPos and recoilP";
305
306
307 if (!recoil_track_states_ecal.empty()) {
308 fiducial_in_tracker = true;
309 recoilPos = {recoil_track_states_ecal[0], recoil_track_states_ecal[1],
310 recoil_track_states_ecal[2]};
311 recoilP = {(recoil_track_states_ecal[3]), (recoil_track_states_ecal[4]),
312 (recoil_track_states_ecal[5])};
313 } else {
314 ldmx_log(trace) << " No recoil track at ECAL";
315 fiducial_in_tracker = false;
316 }
317 ldmx_log(debug) << " Set recoilP = (" << recoilP[0] << ", " << recoilP[1]
318 << ", " << recoilP[2] << ") and recoilPos = ("
319 << recoilPos[0] << ", " << recoilPos[1] << ", "
320 << recoilPos[2] << ")";
321
322
323 if (!recoil_track_states_target.empty()) {
324 recoilPosAtTarget = {(recoil_track_states_target[0]),
325 (recoil_track_states_target[1]),
326 (recoil_track_states_target[2])};
327 recoilPAtTarget = {recoil_track_states_target[3],
328 recoil_track_states_target[4],
329 recoil_track_states_target[5]};
330 }
331 ldmx_log(debug) << " Set recoilPAtTarget = (" << recoilPAtTarget[0] << ", "
332 << recoilPAtTarget[1] << ", " << recoilPAtTarget[2]
333 << ") and recoilPosAtTarget = (" << recoilPosAtTarget[0]
334 << ", " << recoilPosAtTarget[1] << ", "
335 << recoilPosAtTarget[2] << ")";
336 }
337
338 ldmx_log(trace) << " Get projected trajectories for electron and photon";
339
340 auto recoil_electron = std::chrono::high_resolution_clock::now();
341 profiling_map_["recoil_electron"] +=
342 std::chrono::duration<float, std::milli>(recoil_electron - setup).count();
343
344
345 std::vector<XYCoords> ele_trajectory, photon_trajectory,
346 ele_trajectory_at_target;
347
348
349 if ((recoilP[2] > 0.) && (recoilPAtTarget[2] > 0.) &&
350 (recoilPos[0] != -9999.) && (recoilPosAtTarget[0] != -9999.)) {
351 ele_trajectory = getTrajectory(recoilP, recoilPos);
352
353
354 std::array<float, 3> photon_proj_momentum = {
355 -recoilPAtTarget[0], -recoilPAtTarget[1],
356 beamEnergyMeV_ - recoilPAtTarget[2]};
357 photon_trajectory = getTrajectory(photon_proj_momentum, recoilPosAtTarget);
358 } else {
359 ldmx_log(trace) << "Ele / photon trajectory cannot be determined, pZ = "
360 << recoilP[2] << " pZAtTarget = " << recoilPAtTarget[2]
361 << " X = " << recoilPos[0]
362 << " XAtTarget = " << recoilPosAtTarget[0];
363 }
364
365 float recoilPMag = (recoilP[2] > 0.) ? sqrt((recoilP[0] * recoilP[0]) +
366 (recoilP[1] * recoilP[1]) +
367 (recoilP[2] * recoilP[2]))
368 : -1.0;
369 float recoilTheta =
370 recoilPMag > 0 ? acos(recoilP[2] / recoilPMag) * 180.0 / M_PI : -1.0;
371
372 ldmx_log(trace) << " Build Radii of containment (ROC)";
373
374 auto trajectories = std::chrono::high_resolution_clock::now();
375 profiling_map_["trajectories"] +=
376 std::chrono::duration<float, std::milli>(trajectories - recoil_electron)
377 .count();
378
379
380 std::vector<float> roc_values_bin0(roc_range_values_[0].begin() + 4,
381 roc_range_values_[0].end());
382 std::vector<float> ele_radii = roc_values_bin0;
383 float theta_min, theta_max, p_min, p_max;
384 bool inrange;
385
386 for (int i = 0; i < roc_range_values_.size(); i++) {
387 theta_min = roc_range_values_[i][0];
388 theta_max = roc_range_values_[i][1];
389 p_min = roc_range_values_[i][2];
390 p_max = roc_range_values_[i][3];
391 inrange = true;
392
393 if (theta_min != -1.0) {
394 inrange = inrange && (recoilTheta >= theta_min);
395 }
396 if (theta_max != -1.0) {
397 inrange = inrange && (recoilTheta < theta_max);
398 }
399 if (p_min != -1.0) {
400 inrange = inrange && (recoilPMag >= p_min);
401 }
402 if (p_max != -1.0) {
403 inrange = inrange && (recoilPMag < p_max);
404 }
405 if (inrange) {
406 std::vector<float> roc_values_bini(roc_range_values_[i].begin() + 4,
407 roc_range_values_[i].end());
408 ele_radii = roc_values_bini;
409 }
410 }
411
412 std::vector<float> photon_radii = roc_values_bin0;
413
414 auto roc_var = std::chrono::high_resolution_clock::now();
415 profiling_map_["roc_var"] +=
416 std::chrono::duration<float, std::milli>(roc_var - trajectories).count();
417
418
419 const std::vector<ldmx::EcalHit> ecalRecHits =
420 event.getCollection<
ldmx::EcalHit>(rec_coll_name_, rec_pass_name_);
421
423 GetShowerCentroidIDAndRMS(ecalRecHits, showerRMS_);
424
426 bool doTight = true;
427
428 fillIsolatedHitMap(ecalRecHits, globalCentroid, cellMap_, cellMapTightIso_,
429 doTight);
430
431 auto fill_hitmaps = std::chrono::high_resolution_clock::now();
432 profiling_map_["fill_hitmaps"] +=
433 std::chrono::duration<float, std::milli>(fill_hitmaps - roc_var).count();
434
435
436
437
438 float wavgLayerHit = 0;
439 float xMean = 0;
440 float yMean = 0;
441
442
443 unsigned int nregions = 5;
444 std::vector<float> electronContainmentEnergy(nregions, 0.0);
445 std::vector<float> photonContainmentEnergy(nregions, 0.0);
446 std::vector<float> outsideContainmentEnergy(nregions, 0.0);
447 std::vector<int> outsideContainmentNHits(nregions, 0);
448 std::vector<float> outsideContainmentXmean(nregions, 0.0);
449 std::vector<float> outsideContainmentYmean(nregions, 0.0);
450 std::vector<float> outsideContainmentXstd(nregions, 0.0);
451 std::vector<float> outsideContainmentYstd(nregions, 0.0);
452
453 std::vector<int> segLayers = {0, 6, 17, 34};
454 unsigned int nsegments = segLayers.size() - 1;
455 std::vector<float> energySeg(nsegments, 0.0);
456 std::vector<float> xMeanSeg(nsegments, 0.0);
457 std::vector<float> xStdSeg(nsegments, 0.0);
458 std::vector<float> yMeanSeg(nsegments, 0.0);
459 std::vector<float> yStdSeg(nsegments, 0.0);
460 std::vector<float> layerMeanSeg(nsegments, 0.0);
461 std::vector<float> layerStdSeg(nsegments, 0.0);
462 std::vector<std::vector<float>> eContEnergy(
463 nregions, std::vector<float>(nsegments, 0.0));
464 std::vector<std::vector<float>> eContXMean(
465 nregions, std::vector<float>(nsegments, 0.0));
466 std::vector<std::vector<float>> eContYMean(
467 nregions, std::vector<float>(nsegments, 0.0));
468 std::vector<std::vector<float>> gContEnergy(
469 nregions, std::vector<float>(nsegments, 0.0));
470 std::vector<std::vector<int>> gContNHits(nregions,
471 std::vector<int>(nsegments, 0));
472 std::vector<std::vector<float>> gContXMean(
473 nregions, std::vector<float>(nsegments, 0.0));
474 std::vector<std::vector<float>> gContYMean(
475 nregions, std::vector<float>(nsegments, 0.0));
476 std::vector<std::vector<float>> oContEnergy(
477 nregions, std::vector<float>(nsegments, 0.0));
478 std::vector<std::vector<int>> oContNHits(nregions,
479 std::vector<int>(nsegments, 0));
480 std::vector<std::vector<float>> oContXMean(
481 nregions, std::vector<float>(nsegments, 0.0));
482 std::vector<std::vector<float>> oContYMean(
483 nregions, std::vector<float>(nsegments, 0.0));
484 std::vector<std::vector<float>> oContXStd(nregions,
485 std::vector<float>(nsegments, 0.0));
486 std::vector<std::vector<float>> oContYStd(nregions,
487 std::vector<float>(nsegments, 0.0));
488 std::vector<std::vector<float>> oContLayerMean(
489 nregions, std::vector<float>(nsegments, 0.0));
490 std::vector<std::vector<float>> oContLayerStd(
491 nregions, std::vector<float>(nsegments, 0.0));
492
493 auto containment_var = std::chrono::high_resolution_clock::now();
494 profiling_map_["containment_var"] +=
495 std::chrono::duration<float, std::milli>(containment_var - fill_hitmaps)
496 .count();
497
498
499
500
501 std::vector<HitData> trackingHitList;
502
503 ldmx_log(trace)
504 << " Loop over the hits from the event to calculate the BDT features";
505
507
509 ecalLayerEdepRaw_[id.layer()] =
510 ecalLayerEdepRaw_[id.layer()] + hit.getEnergy();
511 if (id.layer() >= 20) ecalBackEnergy_ += hit.getEnergy();
512 if (maxCellDep_ < hit.getEnergy()) maxCellDep_ = hit.getEnergy();
513 if (hit.getEnergy() <= 0) {
514 ldmx_log(fatal)
515 << "ECal hit has negative or zero energy, this should never happen, "
516 "check the threshold settings in HgcrocEmulator";
517 continue;
518 }
519 nReadoutHits_++;
520 ecalLayerEdepReadout_[id.layer()] += hit.getEnergy();
521 ecalLayerTime_[id.layer()] += (hit.getEnergy()) * hit.getTime();
523 xMean += x * hit.getEnergy();
524 yMean += y * hit.getEnergy();
525 avgLayerHit_ += id.layer();
526 wavgLayerHit += id.layer() * hit.getEnergy();
527 if (deepestLayerHit_ < id.layer()) {
528 deepestLayerHit_ = id.layer();
529 }
530 XYCoords xy_pair = std::make_pair(x, y);
531 float distance_ele_trajectory =
532 ele_trajectory.size()
533 ? sqrt(pow((xy_pair.first - ele_trajectory[id.layer()].first), 2) +
534 pow((xy_pair.second - ele_trajectory[id.layer()].second), 2))
535 : -1.0;
536 float distance_photon_trajectory =
537 photon_trajectory.size()
538 ? sqrt(pow((xy_pair.first - photon_trajectory[id.layer()].first),
539 2) +
540 pow((xy_pair.second - photon_trajectory[id.layer()].second),
541 2))
542 : -1.0;
543
544
545 for (unsigned int iseg = 0; iseg < nsegments; iseg++) {
546 if (id.layer() >= segLayers[iseg] &&
547 id.layer() <= segLayers[iseg + 1] - 1) {
548 energySeg[iseg] += hit.getEnergy();
549 xMeanSeg[iseg] += xy_pair.first * hit.getEnergy();
550 yMeanSeg[iseg] += xy_pair.second * hit.getEnergy();
551 layerMeanSeg[iseg] += id.layer() * hit.getEnergy();
552
553
554 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
555 if (distance_ele_trajectory >= ireg * ele_radii[id.layer()] &&
556 distance_ele_trajectory < (ireg + 1) * ele_radii[id.layer()]) {
557 eContEnergy[ireg][iseg] += hit.getEnergy();
558 eContXMean[ireg][iseg] += xy_pair.first * hit.getEnergy();
559 eContYMean[ireg][iseg] += xy_pair.second * hit.getEnergy();
560 }
561 if (distance_photon_trajectory >= ireg * photon_radii[id.layer()] &&
562 distance_photon_trajectory <
563 (ireg + 1) * photon_radii[id.layer()]) {
564 gContEnergy[ireg][iseg] += hit.getEnergy();
565 gContNHits[ireg][iseg] += 1;
566 gContXMean[ireg][iseg] += xy_pair.first * hit.getEnergy();
567 gContYMean[ireg][iseg] += xy_pair.second * hit.getEnergy();
568 }
569 if (distance_ele_trajectory > (ireg + 1) * ele_radii[id.layer()] &&
570 distance_photon_trajectory >
571 (ireg + 1) * photon_radii[id.layer()]) {
572 oContEnergy[ireg][iseg] += hit.getEnergy();
573 oContNHits[ireg][iseg] += 1;
574 oContXMean[ireg][iseg] += xy_pair.first * hit.getEnergy();
575 oContYMean[ireg][iseg] += xy_pair.second * hit.getEnergy();
576 oContLayerMean[ireg][iseg] += id.layer() * hit.getEnergy();
577 }
578 }
579 }
580 }
581
582
583 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
584 if (distance_ele_trajectory >= ireg * ele_radii[id.layer()] &&
585 distance_ele_trajectory < (ireg + 1) * ele_radii[id.layer()])
586 electronContainmentEnergy[ireg] += hit.getEnergy();
587 if (distance_photon_trajectory >= ireg * photon_radii[id.layer()] &&
588 distance_photon_trajectory < (ireg + 1) * photon_radii[id.layer()])
589 photonContainmentEnergy[ireg] += hit.getEnergy();
590 if (distance_ele_trajectory > (ireg + 1) * ele_radii[id.layer()] &&
591 distance_photon_trajectory > (ireg + 1) * photon_radii[id.layer()]) {
592 outsideContainmentEnergy[ireg] += hit.getEnergy();
593 outsideContainmentNHits[ireg] += 1;
594 outsideContainmentXmean[ireg] += xy_pair.first * hit.getEnergy();
595 outsideContainmentYmean[ireg] += xy_pair.second * hit.getEnergy();
596 }
597 }
598
599
600
601 if (distance_ele_trajectory >= ele_radii[id.layer()] ||
602 distance_ele_trajectory == -1.0) {
603 HitData hd;
604 hd.pos = TVector3(xy_pair.first, xy_pair.second,
606 hd.layer = id.layer();
607 trackingHitList.push_back(hd);
608 }
609 }
610
611 for (const auto &[id, energy] : cellMapTightIso_) {
612 if (energy > 0) summedTightIso_ += energy;
613 }
614
615 for (int iLayer = 0; iLayer < ecalLayerEdepReadout_.size(); iLayer++) {
616 ecalLayerTime_[iLayer] =
617 ecalLayerTime_[iLayer] / ecalLayerEdepReadout_[iLayer];
618 summedDet_ += ecalLayerEdepReadout_[iLayer];
619 }
620
621 if (nReadoutHits_ > 0) {
622 avgLayerHit_ /= nReadoutHits_;
623 wavgLayerHit /= summedDet_;
624 xMean /= summedDet_;
625 yMean /= summedDet_;
626 } else {
627 wavgLayerHit = 0;
628 avgLayerHit_ = 0;
629 xMean = 0;
630 yMean = 0;
631 }
632
633
634 for (unsigned int iseg = 0; iseg < nsegments; iseg++) {
635 if (energySeg[iseg] > 0) {
636 xMeanSeg[iseg] /= energySeg[iseg];
637 yMeanSeg[iseg] /= energySeg[iseg];
638 layerMeanSeg[iseg] /= energySeg[iseg];
639 }
640 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
641 if (eContEnergy[ireg][iseg] > 0) {
642 eContXMean[ireg][iseg] /= eContEnergy[ireg][iseg];
643 eContYMean[ireg][iseg] /= eContEnergy[ireg][iseg];
644 }
645 if (gContEnergy[ireg][iseg] > 0) {
646 gContXMean[ireg][iseg] /= gContEnergy[ireg][iseg];
647 gContYMean[ireg][iseg] /= gContEnergy[ireg][iseg];
648 }
649 if (oContEnergy[ireg][iseg] > 0) {
650 oContXMean[ireg][iseg] /= oContEnergy[ireg][iseg];
651 oContYMean[ireg][iseg] /= oContEnergy[ireg][iseg];
652 oContLayerMean[ireg][iseg] /= oContEnergy[ireg][iseg];
653 }
654 }
655 }
656
657 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
658 if (outsideContainmentEnergy[ireg] > 0) {
659 outsideContainmentXmean[ireg] /= outsideContainmentEnergy[ireg];
660 outsideContainmentYmean[ireg] /= outsideContainmentEnergy[ireg];
661 }
662 }
663
664
668 if (hit.getEnergy() > 0) {
669 xStd_ += pow((x - xMean), 2) * hit.getEnergy();
670 yStd_ += pow((y - yMean), 2) * hit.getEnergy();
671 stdLayerHit_ += pow((id.layer() - wavgLayerHit), 2) * hit.getEnergy();
672 }
673 XYCoords xy_pair = std::make_pair(x, y);
674 float distance_ele_trajectory =
675 ele_trajectory.size()
676 ? sqrt(pow((xy_pair.first - ele_trajectory[id.layer()].first), 2) +
677 pow((xy_pair.second - ele_trajectory[id.layer()].second), 2))
678 : -1.0;
679 float distance_photon_trajectory =
680 photon_trajectory.size()
681 ? sqrt(pow((xy_pair.first - photon_trajectory[id.layer()].first),
682 2) +
683 pow((xy_pair.second - photon_trajectory[id.layer()].second),
684 2))
685 : -1.0;
686
687 for (unsigned int iseg = 0; iseg < nsegments; iseg++) {
688 if (id.layer() >= segLayers[iseg] &&
689 id.layer() <= segLayers[iseg + 1] - 1) {
690 xStdSeg[iseg] +=
691 pow((xy_pair.first - xMeanSeg[iseg]), 2) * hit.getEnergy();
692 yStdSeg[iseg] +=
693 pow((xy_pair.second - yMeanSeg[iseg]), 2) * hit.getEnergy();
694 layerStdSeg[iseg] +=
695 pow((id.layer() - layerMeanSeg[iseg]), 2) * hit.getEnergy();
696
697 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
698 if (distance_ele_trajectory > (ireg + 1) * ele_radii[id.layer()] &&
699 distance_photon_trajectory >
700 (ireg + 1) * photon_radii[id.layer()]) {
701 oContXStd[ireg][iseg] +=
702 pow((xy_pair.first - oContXMean[ireg][iseg]), 2) *
703 hit.getEnergy();
704 oContYStd[ireg][iseg] +=
705 pow((xy_pair.second - oContYMean[ireg][iseg]), 2) *
706 hit.getEnergy();
707 oContLayerStd[ireg][iseg] +=
708 pow((id.layer() - oContLayerMean[ireg][iseg]), 2) *
709 hit.getEnergy();
710 }
711 }
712 }
713 }
714
715 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
716 if (distance_ele_trajectory > (ireg + 1) * ele_radii[id.layer()] &&
717 distance_photon_trajectory > (ireg + 1) * photon_radii[id.layer()]) {
718 outsideContainmentXstd[ireg] +=
719 pow((xy_pair.first - outsideContainmentXmean[ireg]), 2) *
720 hit.getEnergy();
721 outsideContainmentYstd[ireg] +=
722 pow((xy_pair.second - outsideContainmentYmean[ireg]), 2) *
723 hit.getEnergy();
724 }
725 }
726 }
727
728 if (nReadoutHits_ > 0) {
729 xStd_ = sqrt(xStd_ / summedDet_);
730 yStd_ = sqrt(yStd_ / summedDet_);
731 stdLayerHit_ = sqrt(stdLayerHit_ / summedDet_);
732 } else {
733 xStd_ = 0;
734 yStd_ = 0;
735 stdLayerHit_ = 0;
736 }
737
738
739
740 for (unsigned int iseg = 0; iseg < nsegments; iseg++) {
741 if (energySeg[iseg] > 0) {
742 xStdSeg[iseg] = sqrt(xStdSeg[iseg] / energySeg[iseg]);
743 yStdSeg[iseg] = sqrt(yStdSeg[iseg] / energySeg[iseg]);
744 layerStdSeg[iseg] = sqrt(layerStdSeg[iseg] / energySeg[iseg]);
745 }
746 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
747 if (oContEnergy[ireg][iseg] > 0) {
748 oContXStd[ireg][iseg] =
749 sqrt(oContXStd[ireg][iseg] / oContEnergy[ireg][iseg]);
750 oContYStd[ireg][iseg] =
751 sqrt(oContYStd[ireg][iseg] / oContEnergy[ireg][iseg]);
752 oContLayerStd[ireg][iseg] =
753 sqrt(oContLayerStd[ireg][iseg] / oContEnergy[ireg][iseg]);
754 }
755 }
756 }
757
758 for (unsigned int ireg = 0; ireg < nregions; ireg++) {
759 if (outsideContainmentEnergy[ireg] > 0) {
760 outsideContainmentXstd[ireg] =
761 sqrt(outsideContainmentXstd[ireg] / outsideContainmentEnergy[ireg]);
762 outsideContainmentYstd[ireg] =
763 sqrt(outsideContainmentYstd[ireg] / outsideContainmentEnergy[ireg]);
764 }
765 }
766
767 ldmx_log(trace) << " Find out if the recoil electron is fiducial";
768
769
770
771
772 const float dz_from_face{7.932};
773 float drifted_recoil_x{-9999.};
774 float drifted_recoil_y{-9999.};
775 if (recoilP[2] > 0.) {
776 ldmx_log(trace) << " Recoil electron pX = " << recoilP[0]
777 << " pY = " << recoilP[1] << " pZ = " << recoilP[2];
778 ldmx_log(trace) << " Recoil electron PosX = " << recoilPos[0]
779 << " PosY = " << recoilPos[1] << " PosZ = " << recoilPos[2];
780 drifted_recoil_x =
781 (dz_from_face * (recoilP[0] / recoilP[2])) + recoilPos[0];
782 drifted_recoil_y =
783 (dz_from_face * (recoilP[1] / recoilP[2])) + recoilPos[1];
784 }
785 const int recoil_layer_index = 0;
786
787
788 bool inside_ecal_cell{false};
789
790 const auto ecalID =
geometry_->
getID(drifted_recoil_x, drifted_recoil_y,
791 recoil_layer_index, true);
792 if (!ecalID.null()) {
793
794 const auto cellID =
795 geometry_->
getID(drifted_recoil_x, drifted_recoil_y, recoil_layer_index,
796 ecalID.getModuleID(), true);
797 if (!cellID.null()) {
798 inside_ecal_cell = true;
799 }
800 }
801
802 ldmx_log(info) << " Is this event is fiducial in ECAL? "
803 << inside_ecal_cell;
804
805
806
807
808
809
810
811
812
813
814 TVector3 e_traj_start;
815 TVector3 e_traj_end;
816 TVector3 e_traj_target_start;
817 TVector3 e_traj_target_end;
818 TVector3 p_traj_start;
819 TVector3 p_traj_end;
820 if (!ele_trajectory.empty() && !photon_trajectory.empty()) {
821
822
823 e_traj_start.SetXYZ(ele_trajectory[0].first, ele_trajectory[0].second,
825 e_traj_end.SetXYZ(ele_trajectory[(nEcalLayers_ - 1)].first,
826 ele_trajectory[(nEcalLayers_ - 1)].second,
828 p_traj_start.SetXYZ(photon_trajectory[0].first, photon_trajectory[0].second,
830 p_traj_end.SetXYZ(photon_trajectory[(nEcalLayers_ - 1)].first,
831 photon_trajectory[(nEcalLayers_ - 1)].second,
833
834 TVector3 evec = e_traj_end - e_traj_start;
835 TVector3 e_norm = evec.Unit();
836 TVector3 pvec = p_traj_end - p_traj_start;
837 TVector3 p_norm = pvec.Unit();
838
839
840
841 epDot_ = e_norm.Dot(p_norm);
843 epSep_ = sqrt(pow(e_traj_start.X() - p_traj_start.X(), 2) +
844 pow(e_traj_start.Y() - p_traj_start.Y(), 2));
845
846
847 if (!ele_trajectory_at_target.empty()) {
848 e_traj_target_start.SetXYZ(ele_trajectory_at_target[0].first,
849 ele_trajectory_at_target[0].second,
851 e_traj_target_end.SetXYZ(ele_trajectory_at_target[(0)].first,
852 ele_trajectory_at_target[(0)].second,
854
855 TVector3 evec_target = e_traj_target_end - e_traj_target_start;
856 TVector3 e_norm_target = evec_target.Unit();
859 }
860 ldmx_log(trace) << " Electron trajectory calculated";
861 } else {
862
863
864
865 ldmx_log(trace) << " Electron trajectory is missing";
867 e_traj_end =
870 p_traj_end =
872
878 }
879
880
881
882
883
885
886
887 if (!photon_trajectory.empty()) {
888 for (std::vector<HitData>::iterator it = trackingHitList.begin();
889 it != trackingHitList.end(); ++it) {
890 float ehDist =
891 sqrt(pow((*it).pos.X() - photon_trajectory[(*it).layer].first, 2) +
892 pow((*it).pos.Y() - photon_trajectory[(*it).layer].second, 2));
893 if (ehDist < 8.7) {
897 }
898 }
899 }
900 }
901
902
903 TVector3 gToe = (e_traj_start - p_traj_start).Unit();
904 TVector3 origin = p_traj_start + 0.5 * 8.7 * gToe;
905 if (!ele_trajectory.empty()) {
906 for (auto &hitData : trackingHitList) {
907 TVector3 hitPos = hitData.pos;
908 TVector3 hitPrime = hitPos - origin;
909 if (hitPrime.Dot(gToe) <= 0) {
911 }
912 }
913 } else {
915 }
916
917 auto mip_tracking_setup = std::chrono::high_resolution_clock::now();
918 profiling_map_["mip_tracking_setup"] +=
919 std::chrono::duration<float, std::milli>(mip_tracking_setup -
920 containment_var)
921 .count();
922
923
924
925
926 std::sort(trackingHitList.begin(), trackingHitList.end(),
927 [](HitData ha, HitData hb) { return ha.layer > hb.layer; });
928
929
930
931
932 std::vector<std::vector<HitData>> track_list;
933
934
935
936 ldmx_log(trace) << "====== Tracking hit list (original) length "
937 << trackingHitList.size() << " ======";
938 for (int i = 0; i < trackingHitList.size(); i++) {
939 ldmx_log(trace) << " [" << trackingHitList[i].pos.X() << ", "
940 << trackingHitList[i].pos.Y() << ", "
941 << trackingHitList[i].layer << "]";
942 }
943 ldmx_log(trace) << "====== END OF Tracking hit list ======";
944
945
946
948 for (int iHit = 0; iHit < trackingHitList.size(); iHit++) {
949
950 int track[34];
951 int currenthit{iHit};
952 int trackLen{1};
953
954 track[0] = iHit;
955
956
957
958
959
960 int jHit = iHit;
961 while (jHit < trackingHitList.size()) {
962 if ((trackingHitList[jHit].layer ==
963 trackingHitList[currenthit].layer - 1 ||
964 trackingHitList[jHit].layer ==
965 trackingHitList[currenthit].layer - 2) &&
966 abs(trackingHitList[jHit].pos.X() -
967 trackingHitList[currenthit].pos.X()) <= 0.5 * cellWidth &&
968 abs(trackingHitList[jHit].pos.Y() -
969 trackingHitList[currenthit].pos.Y()) <= 0.5 * cellWidth) {
970 track[trackLen] = jHit;
971 trackLen++;
972 currenthit = jHit;
973 }
974 jHit++;
975 }
976
977
978 if (trackLen < 2) continue;
979 float closest_e =
distTwoLines(trackingHitList[track[0]].pos,
980 trackingHitList[track[trackLen - 1]].pos,
981 e_traj_start, e_traj_end);
982 float closest_p =
distTwoLines(trackingHitList[track[0]].pos,
983 trackingHitList[track[trackLen - 1]].pos,
984 p_traj_start, p_traj_end);
985
986
987 if (closest_p > cellWidth and closest_e < 2 * cellWidth) continue;
988 if (trackLen < 4 and closest_e > closest_p) continue;
989 ldmx_log(trace) << "====== After rejection for MIP tracking ======";
990 ldmx_log(trace) << "current hit: [" << trackingHitList[iHit].pos.X() << ", "
991 << trackingHitList[iHit].pos.Y() << ", "
992 << trackingHitList[iHit].layer << "]";
993
994 for (int k = 0; k < trackLen; k++) {
995 ldmx_log(trace) << " track[" << k << "] position = ["
996 << trackingHitList[track[k]].pos.X() << ", "
997 << trackingHitList[track[k]].pos.Y() << ", "
998 << trackingHitList[track[k]].layer << "]";
999 }
1000
1001
1002
1003 if (trackLen >= 2) {
1004 std::vector<HitData> temp_track_list;
1005 int n_remove = 0;
1006 for (int kHit = 0; kHit < trackLen; kHit++) {
1007 temp_track_list.push_back(trackingHitList[track[kHit] - n_remove]);
1008 trackingHitList.erase(trackingHitList.begin() + track[kHit] - n_remove);
1009 n_remove++;
1010 }
1011
1012 ldmx_log(trace) << "====== Tracking hit list (after erase) length "
1013 << trackingHitList.size() << " ======";
1014 for (int i = 0; i < trackingHitList.size(); i++) {
1015 ldmx_log(trace) << " [" << trackingHitList[i].pos.X() << ", "
1016 << trackingHitList[i].pos.Y() << ", "
1017 << trackingHitList[i].layer << "] ";
1018 }
1019 ldmx_log(trace) << "====== END OF Tracking hit list ======";
1020
1021 track_list.push_back(temp_track_list);
1022
1023
1024 iHit--;
1025 }
1026 }
1027
1028 ldmx_log(debug) << "Straight tracks found (before merge): "
1029 << track_list.size();
1030 for (int iTrack = 0; iTrack < track_list.size(); iTrack++) {
1031 ldmx_log(trace) << "Track " << iTrack << ":";
1032 for (int iHit = 0; iHit < track_list[iTrack].size(); iHit++) {
1033 ldmx_log(trace) << " Hit " << iHit << ": ["
1034 << track_list[iTrack][iHit].pos.X() << ", "
1035 << track_list[iTrack][iHit].pos.Y() << ", "
1036 << track_list[iTrack][iHit].layer << "]";
1037 }
1038 }
1039
1040
1041
1042
1043 ldmx_log(debug) << "Beginning track merging using " << track_list.size()
1044 << " tracks";
1045
1046 for (int track_i = 0; track_i < track_list.size(); track_i++) {
1047
1048
1049 std::vector<HitData> base_track = track_list[track_i];
1050 HitData tail_hitdata = base_track.back();
1051 ldmx_log(trace) << " Considering track " << track_i;
1052 for (int track_j = track_i + 1; track_j < track_list.size(); track_j++) {
1053 std::vector<HitData> checking_track = track_list[track_j];
1054 HitData head_hitdata = checking_track.front();
1055
1056 if ((head_hitdata.layer == tail_hitdata.layer + 1 ||
1057 head_hitdata.layer == tail_hitdata.layer + 2) &&
1058 pow(pow(head_hitdata.pos.X() - tail_hitdata.pos.X(), 2) +
1059 pow(head_hitdata.pos.Y() - tail_hitdata.pos.Y(), 2),
1060 0.5) <= cellWidth) {
1061
1062
1063
1064 ldmx_log(trace) << " ** Compatible track found at index "
1065 << track_j;
1066 ldmx_log(trace) << " Tail xylayer: " << head_hitdata.pos.X() << ","
1067 << head_hitdata.pos.Y() << "," << head_hitdata.layer;
1068 ldmx_log(trace) << " Head xylayer: " << tail_hitdata.pos.X() << ","
1069 << tail_hitdata.pos.Y() << "," << tail_hitdata.layer;
1070
1071 for (int hit_k = 0; hit_k < checking_track.size(); hit_k++) {
1072 base_track.push_back(track_list[track_j][hit_k]);
1073 }
1074 track_list[track_i] = base_track;
1075 track_list.erase(track_list.begin() + track_j);
1076 break;
1077 }
1078 }
1079 }
1081
1082 ldmx_log(debug) << "Straight tracks found (after merge): "
1084 for (int track_i = 0; track_i < track_list.size(); track_i++) {
1085 ldmx_log(debug) << "Track " << track_i << ":";
1086 for (int hit_i = 0; hit_i < track_list[track_i].size(); hit_i++) {
1087 ldmx_log(debug) << " Hit " << hit_i << ": ["
1088 << track_list[track_i][hit_i].pos.X() << ", "
1089 << track_list[track_i][hit_i].pos.Y() << ", "
1090 << track_list[track_i][hit_i].layer << "]";
1091 }
1092 }
1093
1094 auto straight_tracks = std::chrono::high_resolution_clock::now();
1095 profiling_map_["straight_tracks"] += std::chrono::duration<float, std::milli>(
1096 straight_tracks - mip_tracking_setup)
1097 .count();
1098
1099
1100
1101 ldmx_log(info) << "Finding linreg tracks from a total of "
1102 << trackingHitList.size() << " hits using a radius of "
1103 << linreg_radius_ << " mm";
1104
1105 int max_lin_reg_hit{0};
1106 if (run_lin_reg_) max_lin_reg_hit = trackingHitList.size();
1107 for (int iHit = 0; iHit < max_lin_reg_hit; iHit++) {
1108
1109 std::vector<int> hitsInRegion;
1110 TMatrixD Vm(3, 3);
1111 TMatrixD hdt(3, 3);
1112 TVector3 slopeVec;
1113 TVector3 hmean;
1114 TVector3 hpoint;
1115 float r_corr_best{0.0};
1116
1117 int hitNums[3];
1118
1119 int bestHitNums[3];
1120
1121 hitsInRegion.push_back(iHit);
1122
1123 for (int jHit = 0; jHit < trackingHitList.size(); jHit++) {
1124
1125 if (trackingHitList[iHit].pos(2) == trackingHitList[jHit].pos(2)) {
1126 continue;
1127 }
1128 float dstToHit =
1129 (trackingHitList[iHit].pos - trackingHitList[jHit].pos).Mag();
1130
1131
1132
1133 if (dstToHit <= 2 * linreg_radius_) {
1134 hitsInRegion.push_back(jHit);
1135 }
1136 }
1137
1138 bool bestLinRegFound{false};
1139
1140 ldmx_log(trace) << "There are " << hitsInRegion.size()
1141 << " hits within a radius of " << linreg_radius_ << " mm";
1142
1143
1144
1145 hitNums[0] = iHit;
1146 for (int jHitInReg = 1; jHitInReg < hitsInRegion.size() - 1; jHitInReg++) {
1147
1148 if (hitsInRegion.size() < 3) break;
1149 hitNums[1] = hitsInRegion[jHitInReg];
1150 for (int kHitReg = jHitInReg + 1; kHitReg < hitsInRegion.size();
1151 kHitReg++) {
1152 hitNums[2] = hitsInRegion[kHitReg];
1153 for (int hInd = 0; hInd < 3; hInd++) {
1154
1155
1156 hmean(hInd) = (trackingHitList[hitNums[0]].pos(hInd) +
1157 trackingHitList[hitNums[1]].pos(hInd) +
1158 trackingHitList[hitNums[2]].pos(hInd)) /
1159 3.0;
1160 }
1161 for (int hInd = 0; hInd < 3; hInd++) {
1162 for (int lInd = 0; lInd < 3; lInd++) {
1163 hdt(hInd, lInd) =
1164 trackingHitList[hitNums[hInd]].pos(lInd) - hmean(lInd);
1165 }
1166 }
1167
1168
1169
1170 float determinant =
1171 hdt(0, 0) * (hdt(1, 1) * hdt(2, 2) - hdt(1, 2) * hdt(2, 1)) -
1172 hdt(0, 1) * (hdt(1, 0) * hdt(2, 2) - hdt(1, 2) * hdt(2, 0)) +
1173 hdt(0, 2) * (hdt(1, 0) * hdt(2, 1) - hdt(1, 1) * hdt(2, 0));
1174
1175 if (determinant == 0) continue;
1176
1177 TDecompSVD svdObj(hdt);
1178 bool decomposed = svdObj.Decompose();
1179 if (!decomposed) continue;
1180
1181
1182 Vm = svdObj.GetV();
1183 for (int hInd = 0; hInd < 3; hInd++) {
1184 slopeVec(hInd) = Vm[0][hInd];
1185 }
1186
1187 hpoint = slopeVec + hmean;
1188
1189
1190
1191 float closest_e =
distTwoLines(hmean, hpoint, e_traj_start, e_traj_end);
1192 float closest_p =
distTwoLines(hmean, hpoint, p_traj_start, p_traj_end);
1193
1194
1195 if (closest_p > cellWidth or closest_e < 1.5 * cellWidth) continue;
1196
1197
1198 float vrnc = (trackingHitList[hitNums[0]].pos - hmean).Mag() +
1199 (trackingHitList[hitNums[1]].pos - hmean).Mag() +
1200 (trackingHitList[hitNums[2]].pos - hmean).Mag();
1201
1202 float sumerr =
1203 distPtToLine(trackingHitList[hitNums[0]].pos, hmean, hpoint) +
1204 distPtToLine(trackingHitList[hitNums[1]].pos, hmean, hpoint) +
1205 distPtToLine(trackingHitList[hitNums[2]].pos, hmean, hpoint);
1206 float r_corr = 1 - sumerr / vrnc;
1207
1208
1209
1210 if (r_corr > r_corr_best and r_corr > .6) {
1211 r_corr_best = r_corr;
1212
1213 bestLinRegFound = true;
1214 for (int k = 0; k < 3; k++) {
1215 bestHitNums[k] = hitNums[k];
1216 }
1217 }
1218 }
1219 }
1220
1221
1222 if (!bestLinRegFound) continue;
1223
1226 for (int finalHitIndx = 0; finalHitIndx < 3; finalHitIndx++) {
1227 ldmx_log(debug) << " Hit " << finalHitIndx << " ["
1228 << trackingHitList[bestHitNums[finalHitIndx]].pos(0)
1229 << ", "
1230 << trackingHitList[bestHitNums[finalHitIndx]].pos(1)
1231 << ", "
1232 << trackingHitList[bestHitNums[finalHitIndx]].pos(2)
1233 << "] ";
1234 }
1235
1236
1237 for (int lHit = 0; lHit < 3; lHit++) {
1238 if (!trackingHitList.empty()) {
1239 trackingHitList.erase(trackingHitList.begin() + bestHitNums[lHit]);
1240 }
1241 }
1242 iHit--;
1243 }
1244
1245 auto linreg_tracks = std::chrono::high_resolution_clock::now();
1246 profiling_map_["linreg_tracks"] +=
1247 std::chrono::duration<float, std::milli>(linreg_tracks - straight_tracks)
1248 .count();
1249
1252 << " lin-reg tracks";
1253
1255 nReadoutHits_, deepestLayerHit_, summedDet_, summedTightIso_, maxCellDep_,
1256 showerRMS_, xStd_, yStd_, avgLayerHit_, stdLayerHit_, ecalBackEnergy_,
1259 epDotAtTarget_, electronContainmentEnergy, photonContainmentEnergy,
1260 outsideContainmentEnergy, outsideContainmentNHits, outsideContainmentXstd,
1261 outsideContainmentYstd, energySeg, xMeanSeg, yMeanSeg, xStdSeg, yStdSeg,
1262 layerMeanSeg, layerStdSeg, eContEnergy, eContXMean, eContYMean,
1263 gContEnergy, gContNHits, gContXMean, gContYMean, oContEnergy, oContNHits,
1264 oContXMean, oContYMean, oContXStd, oContYStd, oContLayerMean,
1265 oContLayerStd, ecalLayerEdepReadout_, recoilP, recoilPos);
1266
1267 auto set_variables = std::chrono::high_resolution_clock::now();
1268 profiling_map_["set_variables"] +=
1269 std::chrono::duration<float, std::milli>(set_variables - linreg_tracks)
1270 .count();
1271
1273 ldmx::Ort::FloatArrays inputs({bdtFeatures_});
1274 float pred = rt_->run({featureListName_}, inputs, {"probabilities"})[0].at(1);
1275 ldmx_log(info) << " BDT was ran, score is " << pred;
1276
1277
1278
1280 result.setVetoResult(pred > bdtCutVal_ && passesTrackingVeto);
1281 result.setDiscValue(pred);
1282 ldmx_log(info) << " The pred > bdtCutVal = " << (pred > bdtCutVal_)
1283 << " and MIP tracking passed = " << passesTrackingVeto;
1284
1285
1286 result.setFiducial(inside_ecal_cell);
1287 result.setTrackingFiducial(fiducial_in_tracker);
1288
1289
1290
1291 if (!inverse_skim_) {
1294 } else {
1296 }
1297 } else {
1298
1301 } else {
1303 }
1304 }
1305
1307
1308 auto bdt_variables = std::chrono::high_resolution_clock::now();
1309 profiling_map_["bdt_variables"] +=
1310 std::chrono::duration<float, std::milli>(bdt_variables - set_variables)
1311 .count();
1312
1313 auto end = std::chrono::high_resolution_clock::now();
1314 auto time_diff = end - start;
1315 processing_time_ +=
1316 std::chrono::duration<float, std::milli>(time_diff).count();
1317}
std::tuple< int, const ldmx::SimParticle * > getRecoil(const std::map< int, ldmx::SimParticle > &particleMap)
Find and return the sim particle associated with the recoil electron.
std::vector< float > trackProp(const ldmx::Tracks &tracks, ldmx::TrackStateType ts_type, const std::string &ts_title)
Return a vector of parameters for a propagated recoil track.
float distTwoLines(TVector3 v1, TVector3 v2, TVector3 w1, TVector3 w2)
Returns the distance between the lines v and w, with v defined to pass through the points (v1,...
void buildBDTFeatureVector(const ldmx::EcalVetoResult &result)
float distPtToLine(TVector3 h1, TVector3 p1, TVector3 p2)
Return the minimum distance between the point h1 and the line passing through points p1 and p2.
void fillHitMap(const std::vector< ldmx::EcalHit > &ecalRecHits, std::map< ldmx::EcalID, float > &cellMap_)
Function to load up empty vector of hit maps.
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
void setStorageHint(framework::StorageControl::Hint hint)
Mark the current event as having the given storage control hint from this module.
bool exists(const std::string &name, const std::string &passName="", bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
EcalID getID(double x, double y, double z, bool fallible=false) const
Get a cell's ID number from its position.
double getCellMaxR() const
Get the center-to-corner radius of the cell hexagons.
bool passesVeto() const
Checks if the event passes the Ecal veto.
void setVariables(int nReadoutHits, int deepestLayerHit, float summedDet, float summedTightIso, float maxCellDep, float showerRMS, float xStd, float yStd, float avgLayerHit, float stdLayerHit, float ecalBackEnergy, int nStraightTracks, int nLinregTracks, int firstNearPhLayer, int nNearPhHits, int photonTerritoryHits, float epAng, float epAngAtTarget, float epSep, float epDot, float epDotAtTarget, std::vector< float > electronContainmentEnergy, std::vector< float > photonContainmentEnergy, std::vector< float > outsideContainmentEnergy, std::vector< int > outsideContainmentNHits, std::vector< float > outsideContainmentXStd, std::vector< float > outsideContainmentYStd, std::vector< float > energySeg, std::vector< float > xMeanSeg, std::vector< float > yMeanSeg, std::vector< float > xStdSeg, std::vector< float > yStdSeg, std::vector< float > layerMeanSeg, std::vector< float > layerStdSeg, std::vector< std::vector< float > > eContEnergy, std::vector< std::vector< float > > eContXMean, std::vector< std::vector< float > > eContYMean, std::vector< std::vector< float > > gContEnergy, std::vector< std::vector< int > > gContNHits, std::vector< std::vector< float > > gContXMean, std::vector< std::vector< float > > gContYMean, std::vector< std::vector< float > > oContEnergy, std::vector< std::vector< int > > oContNHits, std::vector< std::vector< float > > oContXMean, std::vector< std::vector< float > > oContYMean, std::vector< std::vector< float > > oContXStd, std::vector< std::vector< float > > oContYStd, std::vector< std::vector< float > > oContLayerMean, std::vector< std::vector< float > > oContLayerStd, std::vector< float > EcalLayerEdepReadout, std::array< float, 3 > recoilP, std::array< float, 3 > recoilPos)
Set the sim particle and 'is findable' flag.
Class representing a simulated particle.
Implements detector ids for special simulation-derived hits like scoring planes.
Represents a simulated tracker hit in the simulation.
Implementation of a track object.
constexpr StorageControl::Hint hint_shouldKeep
storage control hint alias for backwards compatibility
constexpr StorageControl::Hint hint_shouldDrop
storage control hint alias for backwards compatibility