193 auto start = std::chrono::high_resolution_clock::now();
198 ldmx::EcalGeometry::CONDITIONS_OBJECT_NAME);
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.};
212 auto setup = std::chrono::high_resolution_clock::now();
213 profiling_map_[
"setup"] +=
214 std::chrono::duration<float, std::milli>(setup - start).count();
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 "
228 auto [recoilTrackID, recoilElectron] = Analysis::getRecoil(particleMap);
232 "EcalScoringPlaneHits", sp_pass_name_)};
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;
240 if (spHit.getTrackID() == recoilTrackID) {
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]);
257 if (event.
exists(
"TargetScoringPlaneHits", sp_pass_name_)) {
258 std::vector<ldmx::SimTrackerHit> targetSpHits =
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;
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]};
278 pmax = sqrt((recoilPAtTarget[0] * recoilPAtTarget[0]) +
279 (recoilPAtTarget[1] * recoilPAtTarget[1]) +
280 (recoilPAtTarget[2] * recoilPAtTarget[2]));
288 bool fiducial_in_tracker{
false};
289 if (recoil_from_tracking_) {
290 ldmx_log(trace) <<
" Get recoil tracks collection";
294 event.getCollection<
ldmx::Track>(track_collection_, track_pass_name_)};
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");
304 ldmx_log(trace) <<
" Set recoilPos and recoilP";
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])};
314 ldmx_log(trace) <<
" No recoil track at ECAL";
315 fiducial_in_tracker =
false;
317 ldmx_log(debug) <<
" Set recoilP = (" << recoilP[0] <<
", " << recoilP[1]
318 <<
", " << recoilP[2] <<
") and recoilPos = ("
319 << recoilPos[0] <<
", " << recoilPos[1] <<
", "
320 << recoilPos[2] <<
")";
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]};
331 ldmx_log(debug) <<
" Set recoilPAtTarget = (" << recoilPAtTarget[0] <<
", "
332 << recoilPAtTarget[1] <<
", " << recoilPAtTarget[2]
333 <<
") and recoilPosAtTarget = (" << recoilPosAtTarget[0]
334 <<
", " << recoilPosAtTarget[1] <<
", "
335 << recoilPosAtTarget[2] <<
")";
338 ldmx_log(trace) <<
" Get projected trajectories for electron and photon";
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();
345 std::vector<XYCoords> ele_trajectory, photon_trajectory,
346 ele_trajectory_at_target;
349 if ((recoilP[2] > 0.) && (recoilPAtTarget[2] > 0.) &&
350 (recoilPos[0] != -9999.) && (recoilPosAtTarget[0] != -9999.)) {
351 ele_trajectory = getTrajectory(recoilP, recoilPos);
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);
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];
365 float recoilPMag = (recoilP[2] > 0.) ? sqrt((recoilP[0] * recoilP[0]) +
366 (recoilP[1] * recoilP[1]) +
367 (recoilP[2] * recoilP[2]))
370 recoilPMag > 0 ? acos(recoilP[2] / recoilPMag) * 180.0 / M_PI : -1.0;
372 ldmx_log(trace) <<
" Build Radii of containment (ROC)";
374 auto trajectories = std::chrono::high_resolution_clock::now();
375 profiling_map_[
"trajectories"] +=
376 std::chrono::duration<float, std::milli>(trajectories - recoil_electron)
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;
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];
393 if (theta_min != -1.0) {
394 inrange = inrange && (recoilTheta >= theta_min);
396 if (theta_max != -1.0) {
397 inrange = inrange && (recoilTheta < theta_max);
400 inrange = inrange && (recoilPMag >= p_min);
403 inrange = inrange && (recoilPMag < p_max);
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;
412 std::vector<float> photon_radii = roc_values_bin0;
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();
419 const std::vector<ldmx::EcalHit> ecalRecHits =
420 event.getCollection<
ldmx::EcalHit>(rec_coll_name_, rec_pass_name_);
423 GetShowerCentroidIDAndRMS(ecalRecHits, showerRMS_);
428 fillIsolatedHitMap(ecalRecHits, globalCentroid, cellMap_, cellMapTightIso_,
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();
438 float wavgLayerHit = 0;
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);
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));
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)
501 std::vector<HitData> trackingHitList;
504 <<
" Loop over the hits from the event to calculate the BDT features";
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) {
515 <<
"ECal hit has negative or zero energy, this should never happen, "
516 "check the threshold settings in HgcrocEmulator";
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();
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))
536 float distance_photon_trajectory =
537 photon_trajectory.size()
538 ? sqrt(pow((xy_pair.first - photon_trajectory[
id.layer()].first),
540 pow((xy_pair.second - photon_trajectory[
id.layer()].second),
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();
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();
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();
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();
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();
601 if (distance_ele_trajectory >= ele_radii[
id.layer()] ||
602 distance_ele_trajectory == -1.0) {
604 hd.pos = TVector3(xy_pair.first, xy_pair.second,
606 hd.layer =
id.layer();
607 trackingHitList.push_back(hd);
611 for (
const auto &[
id, energy] : cellMapTightIso_) {
612 if (energy > 0) summedTightIso_ += energy;
615 for (
int iLayer = 0; iLayer < ecalLayerEdepReadout_.size(); iLayer++) {
616 ecalLayerTime_[iLayer] =
617 ecalLayerTime_[iLayer] / ecalLayerEdepReadout_[iLayer];
618 summedDet_ += ecalLayerEdepReadout_[iLayer];
621 if (nReadoutHits_ > 0) {
622 avgLayerHit_ /= nReadoutHits_;
623 wavgLayerHit /= summedDet_;
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];
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];
645 if (gContEnergy[ireg][iseg] > 0) {
646 gContXMean[ireg][iseg] /= gContEnergy[ireg][iseg];
647 gContYMean[ireg][iseg] /= gContEnergy[ireg][iseg];
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];
657 for (
unsigned int ireg = 0; ireg < nregions; ireg++) {
658 if (outsideContainmentEnergy[ireg] > 0) {
659 outsideContainmentXmean[ireg] /= outsideContainmentEnergy[ireg];
660 outsideContainmentYmean[ireg] /= outsideContainmentEnergy[ireg];
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();
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))
679 float distance_photon_trajectory =
680 photon_trajectory.size()
681 ? sqrt(pow((xy_pair.first - photon_trajectory[
id.layer()].first),
683 pow((xy_pair.second - photon_trajectory[
id.layer()].second),
687 for (
unsigned int iseg = 0; iseg < nsegments; iseg++) {
688 if (
id.layer() >= segLayers[iseg] &&
689 id.layer() <= segLayers[iseg + 1] - 1) {
691 pow((xy_pair.first - xMeanSeg[iseg]), 2) * hit.getEnergy();
693 pow((xy_pair.second - yMeanSeg[iseg]), 2) * hit.getEnergy();
695 pow((
id.layer() - layerMeanSeg[iseg]), 2) * hit.getEnergy();
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) *
704 oContYStd[ireg][iseg] +=
705 pow((xy_pair.second - oContYMean[ireg][iseg]), 2) *
707 oContLayerStd[ireg][iseg] +=
708 pow((
id.layer() - oContLayerMean[ireg][iseg]), 2) *
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) *
721 outsideContainmentYstd[ireg] +=
722 pow((xy_pair.second - outsideContainmentYmean[ireg]), 2) *
728 if (nReadoutHits_ > 0) {
729 xStd_ = sqrt(xStd_ / summedDet_);
730 yStd_ = sqrt(yStd_ / summedDet_);
731 stdLayerHit_ = sqrt(stdLayerHit_ / summedDet_);
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]);
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]);
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]);
767 ldmx_log(trace) <<
" Find out if the recoil electron is fiducial";
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];
781 (dz_from_face * (recoilP[0] / recoilP[2])) + recoilPos[0];
783 (dz_from_face * (recoilP[1] / recoilP[2])) + recoilPos[1];
785 const int recoil_layer_index = 0;
788 bool inside_ecal_cell{
false};
790 const auto ecalID =
geometry_->
getID(drifted_recoil_x, drifted_recoil_y,
791 recoil_layer_index,
true);
792 if (!ecalID.null()) {
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;
802 ldmx_log(info) <<
" Is this event is fiducial in ECAL? "
814 TVector3 e_traj_start;
816 TVector3 e_traj_target_start;
817 TVector3 e_traj_target_end;
818 TVector3 p_traj_start;
820 if (!ele_trajectory.empty() && !photon_trajectory.empty()) {
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,
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();
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));
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,
855 TVector3 evec_target = e_traj_target_end - e_traj_target_start;
856 TVector3 e_norm_target = evec_target.Unit();
860 ldmx_log(trace) <<
" Electron trajectory calculated";
865 ldmx_log(trace) <<
" Electron trajectory is missing";
887 if (!photon_trajectory.empty()) {
888 for (std::vector<HitData>::iterator it = trackingHitList.begin();
889 it != trackingHitList.end(); ++it) {
891 sqrt(pow((*it).pos.X() - photon_trajectory[(*it).layer].first, 2) +
892 pow((*it).pos.Y() - photon_trajectory[(*it).layer].second, 2));
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) {
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 -
926 std::sort(trackingHitList.begin(), trackingHitList.end(),
932 std::vector<std::vector<HitData>> track_list;
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 <<
"]";
943 ldmx_log(trace) <<
"====== END OF Tracking hit list ======";
948 for (
int iHit = 0; iHit < trackingHitList.size(); iHit++) {
951 int currenthit{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;
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);
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 <<
"]";
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 <<
"]";
1003 if (trackLen >= 2) {
1004 std::vector<HitData> temp_track_list;
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);
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 <<
"] ";
1019 ldmx_log(trace) <<
"====== END OF Tracking hit list ======";
1021 track_list.push_back(temp_track_list);
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 <<
"]";
1043 ldmx_log(debug) <<
"Beginning track merging using " << track_list.size()
1046 for (
int track_i = 0; track_i < track_list.size(); track_i++) {
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();
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) {
1064 ldmx_log(trace) <<
" ** Compatible track found at index "
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;
1071 for (
int hit_k = 0; hit_k < checking_track.size(); hit_k++) {
1072 base_track.push_back(track_list[track_j][hit_k]);
1074 track_list[track_i] = base_track;
1075 track_list.erase(track_list.begin() + track_j);
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 <<
"]";
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)
1101 ldmx_log(info) <<
"Finding linreg tracks from a total of "
1102 << trackingHitList.size() <<
" hits using a radius of "
1103 << linreg_radius_ <<
" mm";
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++) {
1109 std::vector<int> hitsInRegion;
1115 float r_corr_best{0.0};
1121 hitsInRegion.push_back(iHit);
1123 for (
int jHit = 0; jHit < trackingHitList.size(); jHit++) {
1125 if (trackingHitList[iHit].pos(2) == trackingHitList[jHit].pos(2)) {
1129 (trackingHitList[iHit].pos - trackingHitList[jHit].pos).Mag();
1133 if (dstToHit <= 2 * linreg_radius_) {
1134 hitsInRegion.push_back(jHit);
1138 bool bestLinRegFound{
false};
1140 ldmx_log(trace) <<
"There are " << hitsInRegion.size()
1141 <<
" hits within a radius of " << linreg_radius_ <<
" mm";
1146 for (
int jHitInReg = 1; jHitInReg < hitsInRegion.size() - 1; jHitInReg++) {
1148 if (hitsInRegion.size() < 3)
break;
1149 hitNums[1] = hitsInRegion[jHitInReg];
1150 for (
int kHitReg = jHitInReg + 1; kHitReg < hitsInRegion.size();
1152 hitNums[2] = hitsInRegion[kHitReg];
1153 for (
int hInd = 0; hInd < 3; hInd++) {
1156 hmean(hInd) = (trackingHitList[hitNums[0]].pos(hInd) +
1157 trackingHitList[hitNums[1]].pos(hInd) +
1158 trackingHitList[hitNums[2]].pos(hInd)) /
1161 for (
int hInd = 0; hInd < 3; hInd++) {
1162 for (
int lInd = 0; lInd < 3; lInd++) {
1164 trackingHitList[hitNums[hInd]].pos(lInd) - hmean(lInd);
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));
1175 if (determinant == 0)
continue;
1177 TDecompSVD svdObj(hdt);
1178 bool decomposed = svdObj.Decompose();
1179 if (!decomposed)
continue;
1183 for (
int hInd = 0; hInd < 3; hInd++) {
1184 slopeVec(hInd) = Vm[0][hInd];
1187 hpoint = slopeVec + hmean;
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);
1195 if (closest_p > cellWidth or closest_e < 1.5 * cellWidth)
continue;
1198 float vrnc = (trackingHitList[hitNums[0]].pos - hmean).Mag() +
1199 (trackingHitList[hitNums[1]].pos - hmean).Mag() +
1200 (trackingHitList[hitNums[2]].pos - hmean).Mag();
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;
1210 if (r_corr > r_corr_best and r_corr > .6) {
1211 r_corr_best = r_corr;
1213 bestLinRegFound =
true;
1214 for (
int k = 0; k < 3; k++) {
1215 bestHitNums[k] = hitNums[k];
1222 if (!bestLinRegFound)
continue;
1226 for (
int finalHitIndx = 0; finalHitIndx < 3; finalHitIndx++) {
1227 ldmx_log(debug) <<
" Hit " << finalHitIndx <<
" ["
1228 << trackingHitList[bestHitNums[finalHitIndx]].pos(0)
1230 << trackingHitList[bestHitNums[finalHitIndx]].pos(1)
1232 << trackingHitList[bestHitNums[finalHitIndx]].pos(2)
1237 for (
int lHit = 0; lHit < 3; lHit++) {
1238 if (!trackingHitList.empty()) {
1239 trackingHitList.erase(trackingHitList.begin() + bestHitNums[lHit]);
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)
1252 <<
" lin-reg tracks";
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);
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)
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;
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;
1286 result.setFiducial(inside_ecal_cell);
1287 result.setTrackingFiducial(fiducial_in_tracker);
1291 if (!inverse_skim_) {
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)
1313 auto end = std::chrono::high_resolution_clock::now();
1314 auto time_diff = end - start;
1316 std::chrono::duration<float, std::milli>(time_diff).count();