Process the event and put new data products into it.
522 {
523 if (!event.
exists(input_track_coll_name_, input_tracks_passname_)) {
524 ldmx_log(error) << "Unable to find (one) collection named "
525 << input_track_coll_name_ << "_" << input_tracks_passname_;
526 return;
527 }
528 if (!event.
exists(input_ecal_coll_name_, input_ecal_passname_)) {
529 ldmx_log(error) << "Unable to find (one) collection named "
530 << input_ecal_coll_name_ << "_" << input_ecal_passname_;
531 return;
532 }
533 if (!event.
exists(input_hcal_coll_name_, input_hcal_passname_)) {
534 ldmx_log(error) << "Unable to find (one) collection named "
535 << input_hcal_coll_name_ << "_" << input_hcal_passname_;
536 return;
537 }
538
540 input_hcal_coll_name_, input_hcal_passname_);
541 if (hcal_merge_angle_ > 0) hcal_clusters = linkHcalClusters(hcal_clusters);
542 const auto tracks =
event.getCollection<
ldmx::Track>(input_track_coll_name_,
543 input_tracks_passname_);
544
545 std::vector<ldmx::SimTrackerHit> sp_hits;
546 if (event.
exists(truth_sp_coll_name_, truth_sp_passname_))
548 truth_sp_passname_);
549
550 std::map<int, ldmx::TrackDeDxMassEstimate> mass_estimates;
551 if (!input_mass_coll_name_.empty() &&
552 event.
exists(input_mass_coll_name_, input_mass_passname_)) {
554 input_mass_coll_name_, input_mass_passname_)) {
555 mass_estimates[est.getTrackIndex()] = est;
556 }
557 }
558
559 auto ecal_clusters =
560 use_existing_ecal_clusters_
561 ? getEcalClusters(event, input_ecal_coll_name_, input_ecal_passname_)
562 : event.getCollection<ldmx::CaloCluster>(input_ecal_coll_name_,
563 input_ecal_passname_);
564 if (ecal_link_radius_ > 0)
565 ecal_clusters = linkEcalClusters(ecal_clusters, tracks);
566
567 std::vector<ldmx::PFCandidate> pf_cands;
568
569 if (!single_particle_) {
570
571
572
573
574
575
576
577
578
579
580
581
582
583 std::vector<bool> tk_usable(tracks.size(), false);
584
585 std::map<int, std::vector<std::pair<float, int>>> tk_calo_map;
586 for (int i = 0; i < tracks.size(); i++) {
587 const auto& tk = tracks[i];
588 const std::vector<double> xyz = tk.getPosition(ldmx::AtECAL);
589 const std::vector<double> pxyz = tk.getMomentum(ldmx::AtECAL);
590
591 if (pxyz.empty() || pxyz[2] <= 0) {
592 ldmx_log(warn) << "Skipping track " << i << " without AtECAL state";
593 continue;
594 }
595 tk_usable[i] = true;
596 for (int j = 0; j < ecal_clusters.size(); j++) {
597 float dist = trackClusterDist(xyz, pxyz, ecal_clusters[j]);
598
599 if (dist < link_max_dist_) tk_calo_map[i].emplace_back(dist, j);
600 }
601 std::sort(tk_calo_map[i].begin(), tk_calo_map[i].end());
602 }
603
604
605 std::map<int, std::vector<int>> em_had_calo_map;
606 for (int i = 0; i < ecal_clusters.size(); i++) {
607 const auto& ecal = ecal_clusters[i];
608 for (int j = 0; j < hcal_clusters.size(); j++) {
609 const auto& hcal = hcal_clusters[j];
610 const float x_at_h_clus =
611 ecal.getCentroidX() +
612 ecal.getDXDZ() * (hcal.getCentroidZ() -
613 ecal.getCentroidZ());
614 const float y_at_h_clus =
615 ecal.getCentroidY() +
616 ecal.getDYDZ() * (hcal.getCentroidZ() - ecal.getCentroidZ());
617 float dist = sqrt(
618 pow(x_at_h_clus - hcal.getCentroidX(), 2) /
619 std::max(1.0, pow(hcal.getRMSX(), 2) + pow(ecal.getRMSX(), 2)) +
620 pow(y_at_h_clus - hcal.getCentroidY(), 2) /
621 std::max(1.0, pow(hcal.getRMSY(), 2) + pow(ecal.getRMSY(), 2)));
622 bool is_match = (dist < 5);
623 if (is_match) em_had_calo_map[i].push_back(j);
624 }
625 }
626
627
628
629
630 std::vector<bool> tk_is_em_linked(tracks.size(), false);
631 std::vector<bool> em_is_tk_linked(ecal_clusters.size(), false);
632 std::map<int, int> tk_em_pairs{};
633 for (int i = 0; i < tracks.size(); i++) {
634 if (tk_calo_map.count(i)) {
635
636 for (const auto& [dist, em_idx] : tk_calo_map[i]) {
637 if (!em_is_tk_linked[em_idx]) {
638 em_is_tk_linked[em_idx] = true;
639 tk_is_em_linked[i] = true;
640 tk_em_pairs[i] = em_idx;
641 break;
642 }
643 }
644 }
645 }
646
647
648 std::vector<bool> em_is_had_linked(ecal_clusters.size(), false);
649 std::vector<bool> had_is_em_linked(hcal_clusters.size(), false);
650 std::map<int, int> em_had_pairs{};
651 for (int i = 0; i < ecal_clusters.size(); i++) {
652 if (em_had_calo_map.count(i)) {
653
654 for (int had_idx : em_had_calo_map[i]) {
655 if (!had_is_em_linked[had_idx]) {
656 had_is_em_linked[had_idx] = true;
657 em_is_had_linked[i] = true;
658 em_had_pairs[i] = had_idx;
659 break;
660 }
661 }
662 }
663 }
664
665
666
667
668
669
670
671
672 for (int i = 0; i < tracks.size(); i++) {
673 if (!tk_usable[i]) continue;
675 fillCandTrack(cand, tracks[i],
676 sp_hits);
677 cand.setTrackIndex(i);
678 if (tk_is_em_linked[i]) {
679 int em_idx = tk_em_pairs[i];
680 fillCandEMCalo(cand, ecal_clusters[em_idx]);
681 cand.setEcalWidth(ecalWidth(ecal_clusters[em_idx], tracks[i]));
682 cand.setEcalIndex(em_idx);
683 if (em_is_had_linked[em_idx]) {
684 fillCandHadCalo(cand, hcal_clusters[em_had_pairs[em_idx]]);
685 cand.setHcalIndex(em_had_pairs[em_idx]);
686 }
687 recoverEcal(cand, tracks[i], ecal_clusters, em_is_tk_linked);
688 }
689
690
691 if (cand.getHcalIndex() < 0) {
692 int h = linkTrackHcal(tracks[i], hcal_clusters, had_is_em_linked);
693 if (h >= 0) {
694 fillCandHadCalo(cand, hcal_clusters[h]);
695 cand.setHcalIndex(h);
696 had_is_em_linked[h] = true;
697 }
698 }
699 if (auto it = mass_estimates.find(i); it != mass_estimates.end()) {
700 cand.setDeDxMassSquared(it->second.getMassSquared());
701 cand.setDeDxIh(it->second.getIh());
702 cand.setDeDxNhits(it->second.getNhits());
703 }
704 cand.setCharge(static_cast<int>(tracks[i].getCharge()));
705 identifyCharged(cand);
706 if (std::abs(cand.getPdgId()) == 211) {
707 absorbHadronShower(cand, tracks[i], ecal_clusters, em_is_tk_linked,
708 hcal_clusters, had_is_em_linked);
709 }
710
711 auto p = cand.getTrackPxPyPz();
712 double trk_p = std::hypot(p[0], p[1], p[2]);
713 cand.setEnergy(std::hypot(trk_p, cand.getMass()));
714 pf_cands.push_back(cand);
715
716
717 double ecal_e = cand.getEcalEnergy();
718 if (tk_is_em_linked[i] && trk_p > 0 && ecal_e > excess_ep_ * trk_p) {
720 fillCandEMCalo(excess, ecal_clusters[tk_em_pairs[i]]);
721 excess.setEcalIndex(tk_em_pairs[i]);
722 excess.setPdgId(22);
723
724 excess.clearEcalHits();
725 excess.setEnergy(ecal_e - trk_p);
726 pf_cands.push_back(excess);
727 }
728 }
729
730
731 for (int i = 0; i < ecal_clusters.size(); i++) {
732 if (em_is_tk_linked[i]) continue;
734 fillCandEMCalo(cand, ecal_clusters[i]);
735 cand.setEcalIndex(i);
736 if (em_is_had_linked[i]) {
737 fillCandHadCalo(cand, hcal_clusters[em_had_pairs[i]]);
738 cand.setHcalIndex(em_had_pairs[i]);
739 }
740
741
742 cand.setPdgId(em_is_had_linked[i] ? 130 : 22);
743 cand.setEnergy(cand.getEcalEnergy() + cand.getHcalEnergy());
744 if (cand.getEnergy() >= min_neutral_e_) pf_cands.push_back(cand);
745 }
746
747
748 for (int i = 0; i < hcal_clusters.size(); i++) {
749 if (had_is_em_linked[i]) continue;
751 fillCandHadCalo(cand, hcal_clusters[i]);
752 cand.setHcalIndex(i);
753 cand.setPdgId(130);
754 cand.setEnergy(cand.getHcalEnergy());
755 if (cand.getEnergy() >= min_neutral_e_) pf_cands.push_back(cand);
756 }
757
758 } else {
759
761 int pid = 0;
762 if (tracks.size() && !tracks[0].getMomentum(ldmx::AtECAL).empty()) {
763 fillCandTrack(pf, tracks[0], sp_hits);
764 pf.setTrackIndex(0);
765 pid += 1;
766 }
767 if (ecal_clusters.size()) {
768 fillCandEMCalo(pf, ecal_clusters[0]);
769 pf.setEcalIndex(0);
770 pid += 2;
771 }
772 if (hcal_clusters.size()) {
773 fillCandHadCalo(pf, hcal_clusters[0]);
774 pf.setHcalIndex(0);
775 pid += 4;
776 }
777 pf.setPID(pid);
778 pf.setEnergy(pf.getEcalEnergy() + pf.getHcalEnergy());
779 pf_cands.push_back(pf);
780 }
781
782 event.add(output_coll_name_, pf_cands);
783}
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.
const std::vector< ContentType > & getCollection(const std::string &collectionName, const std::string &passName) const
Get a collection (std::vector) of objects from the event bus.
Represents a reconstructed particle.
Represents the estimated mass of a particle using tracker dE/dx information.
Implementation of a track object.