23 profiling_map_[
"setup"] = 0.;
24 profiling_map_[
"hits"] = 0.;
25 profiling_map_[
"seeds"] = 0.;
26 profiling_map_[
"ckf_setup"] = 0.;
27 profiling_map_[
"ckf_run"] = 0.;
28 profiling_map_[
"result_loop"] = 0.;
31 Acts::Vector3 b_field(0., 0., bfield_ * Acts::UnitConstants::T);
34 const auto constBField = std::make_shared<Acts::ConstantBField>(b_field);
42 surf_rotation = Acts::RotationMatrix3::Zero();
44 surf_rotation(1, 0) = 1;
46 surf_rotation(2, 1) = 1;
48 surf_rotation(0, 2) = 1;
50 Acts::Vector3 target_pos(0., 0., 0.);
51 Acts::Translation3 target_translation(target_pos);
52 Acts::Transform3 target_transform(target_translation * surf_rotation);
56 Acts::Surface::makeShared<Acts::PlaneSurface>(target_transform);
59 bool debugTransform =
false;
60 auto transformPos = [
this, debugTransform](
const Acts::Vector3& pos) {
61 Acts::Vector3 rot_pos;
64 rot_pos(2) = pos(0) + DIPOLE_OFFSET;
67 rot_pos(0) += this->map_offset_[0];
68 rot_pos(1) += this->map_offset_[1];
69 rot_pos(2) += this->map_offset_[2];
75 std::cout <<
"PF::DEFAULT3 TRANSFORM" << std::endl;
76 std::cout <<
"PF::Check:: transforming Pos" << std::endl;
77 std::cout << pos << std::endl;
78 std::cout <<
"TO" << std::endl;
79 std::cout << rot_pos << std::endl;
85 Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Identity();
88 auto transformBField = [rotation, scale, debugTransform](
89 const Acts::Vector3& field,
90 const Acts::Vector3& ) {
92 Acts::Vector3 rot_field;
93 rot_field(0) = field(2);
94 rot_field(1) = field(0);
95 rot_field(2) = field(1);
98 rot_field = scale * rot_field;
101 rot_field = rotation * rot_field;
104 if (debugTransform) {
105 std::cout <<
"PF::DEFAULT3 TRANSFORM" << std::endl;
106 std::cout <<
"PF::Check:: transforming" << std::endl;
107 std::cout << field << std::endl;
108 std::cout <<
"TO" << std::endl;
109 std::cout << rot_field << std::endl;
116 const auto map = std::make_shared<InterpolatedMagneticField3>(
117 loadDefaultBField(field_map_,
120 transformPos, transformBField));
122 auto acts_loggingLevel = Acts::Logging::FATAL;
123 if (debug_acts_) acts_loggingLevel = Acts::Logging::VERBOSE;
126 const auto stepper = Acts::EigenStepper<>{map};
127 const auto const_stepper = Acts::EigenStepper<>{constBField};
128 const auto multi_stepper = Acts::MultiEigenStepperLoop{map};
131 Acts::Navigator::Config navCfg{geometry().getTG()};
132 navCfg.resolveMaterial =
true;
133 navCfg.resolvePassive =
true;
134 navCfg.resolveSensitive =
true;
135 const Acts::Navigator navigator(navCfg);
140 ? std::make_unique<CkfPropagator>(const_stepper, navigator)
141 : std::make_unique<CkfPropagator>(
143 Acts::getDefaultLogger(
"ACTS_PROP", acts_loggingLevel));
146 ckf_ = std::make_unique<std::decay_t<
decltype(*ckf_)>>(
147 *propagator_, Acts::getDefaultLogger(
"CKF", acts_loggingLevel));
148 trk_extrap_ = std::make_shared<std::decay_t<
decltype(*trk_extrap_)>>(
149 *propagator_, geometry_context(), magnetic_field_context());
159 std::vector<ldmx::Track> tracks;
161 auto start = std::chrono::high_resolution_clock::now();
165 auto loggingLevel = Acts::Logging::DEBUG;
167 Acts::getDefaultLogger(
"LDMX Tracking Geometry Maker", loggingLevel));
170 Acts::PropagatorOptions<Acts::StepperPlainOptions,
171 Acts::NavigatorPlainOptions, ActionList, AbortList>
172 propagator_options(geometry_context(), magnetic_field_context());
174 propagator_options.pathLimit = std::numeric_limits<double>::max();
176 propagator_options.loopProtection =
false;
181 propagator_options.actionList.get<Acts::MaterialInteractor>();
182 mInteractor.multipleScattering =
true;
183 mInteractor.energyLoss =
true;
184 mInteractor.recordInteractions =
false;
188 propagator_options.actionList.get<Acts::detail::SteppingLogger>();
189 sLogger.sterile =
true;
191 propagator_options.stepping.maxStepSize =
192 propagator_step_size_ * Acts::UnitConstants::mm;
193 propagator_options.maxSteps = propagator_maxSteps_;
203 auto setup = std::chrono::high_resolution_clock::now();
204 profiling_map_[
"setup"] +=
205 std::chrono::duration<double, std::milli>(setup - start).count();
207 const std::vector<ldmx::Measurement> measurements =
212 std::shared_ptr<tracking::sim::TruthMatchingTool> truthMatchingTool =
nullptr;
213 std::map<int, ldmx::SimParticle> particleMap;
215 if (event.
exists(
"SimParticles")) {
216 ldmx_log(debug) <<
"Setting up track truth matching tool";
218 truthMatchingTool = std::make_shared<tracking::sim::TruthMatchingTool>(
219 particleMap, measurements);
224 const auto geoId_sl_map = makeGeoIdSourceLinkMap(tg, measurements);
226 auto hits = std::chrono::high_resolution_clock::now();
227 profiling_map_[
"hits"] +=
228 std::chrono::duration<double, std::milli>(hits - setup).count();
233 const std::vector<ldmx::Track> seed_tracks =
234 event.getCollection<
ldmx::Track>(seed_coll_name_, input_pass_name_);
236 ldmx_log(info) <<
"Number of " << seed_coll_name_
237 <<
" seed tracks = " << seed_tracks.size();
239 if (seed_tracks.empty()) {
240 std::vector<ldmx::Track> empty;
241 ldmx_log(info) <<
"No seed tracks, returning...";
242 event.add(out_trk_collection_, empty);
247 std::vector<Acts::BoundTrackParameters> startParameters;
249 ldmx_log(debug) <<
"Transform the seed track to bound parameters";
250 int seed_track_index{0};
251 for (
auto& seed : seed_tracks) {
253 std::shared_ptr<Acts::PerigeeSurface> perigeeSurface =
254 Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3(
255 seed.getPerigeeX(), seed.getPerigeeY(), seed.getPerigeeZ()));
257 Acts::BoundVector paramVec;
258 paramVec << seed.getD0(), seed.getZ0(), seed.getPhi(), seed.getTheta(),
259 seed.getQoP(), seed.getT();
261 Acts::BoundSquareMatrix covMat =
262 tracking::sim::utils::unpackCov(seed.getPerigeeCov());
264 ldmx_log(debug) <<
" For seed index = " << seed_track_index
265 <<
": Perigee X / Y / Z = " << seed.getPerigeeX() <<
" / "
266 << seed.getPerigeeY() <<
" / " << seed.getPerigeeZ()
267 <<
", D0 = " << paramVec[0] <<
", Z0 = " << paramVec[1]
268 <<
", Phi = " << paramVec[2] <<
", Theta = " << paramVec[3]
269 <<
", QoP = " << paramVec[4] <<
", Time = " << paramVec[5];
271 ldmx_log(debug) <<
" Cov matrix diagonal (" << covMat(0, 0) <<
", "
272 << covMat(1, 1) <<
", " << covMat(2, 2) <<
")";
275 auto partHypo{Acts::SinglyChargedParticleHypothesis::electron()};
276 startParameters.push_back(
277 Acts::BoundTrackParameters(perigeeSurface, paramVec, covMat, partHypo));
285 auto seeds = std::chrono::high_resolution_clock::now();
286 profiling_map_[
"seeds"] +=
287 std::chrono::duration<double, std::milli>(seeds - hits).count();
289 Acts::GainMatrixUpdater kfUpdater;
294 Acts::MeasurementSelector::Config measurementSelectorCfg = {
296 {Acts::GeometryIdentifier(), {{}, {outlier_pval_}, {1u}}},
299 Acts::MeasurementSelector measSel{measurementSelectorCfg};
303 Acts::CombinatorialKalmanFilterExtensions<TrackContainer> ckf_extensions;
305 if (use1Dmeasurements_) {
306 ckf_extensions.calibrator
308 Acts::VectorMultiTrajectory>>(&calibrator);
310 ckf_extensions.calibrator
312 Acts::VectorMultiTrajectory>>(&calibrator);
315 ckf_extensions.updater.connect<
316 &Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>(
319 ckf_extensions.measurementSelector
320 .connect<&Acts::MeasurementSelector::select<Acts::VectorMultiTrajectory>>(
323 ldmx_log(debug) <<
"SourceLinkAccessor...";
326 struct SourceLinkAccIt {
327 using BaseIt =
decltype(geoId_sl_map.begin());
330#pragma GCC diagnostic push
331#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
333 using difference_type =
typename BaseIt::difference_type;
334 using iterator_category =
typename BaseIt::iterator_category;
336 using value_type = Acts::SourceLink;
337 using pointer =
typename BaseIt::pointer;
338 using reference = value_type&;
339#pragma GCC diagnostic pop
341 SourceLinkAccIt& operator++() {
345 bool operator==(
const SourceLinkAccIt& other)
const {
346 return it == other.it;
348 bool operator!=(
const SourceLinkAccIt& other)
const {
349 return !(*
this == other);
354 value_type operator*()
const {
return value_type{it->second}; }
357 auto sourceLinkAccessor = [&](
const Acts::Surface& surface)
358 -> std::pair<SourceLinkAccIt, SourceLinkAccIt> {
359 auto [begin, end] = geoId_sl_map.equal_range(surface.geometryId());
360 return {SourceLinkAccIt{begin}, SourceLinkAccIt{end}};
363 Acts::SourceLinkAccessorDelegate<SourceLinkAccIt> sourceLinkAccessorDelegate;
364 sourceLinkAccessorDelegate.connect<&
decltype(sourceLinkAccessor)::operator(),
365 decltype(sourceLinkAccessor)>(
366 &sourceLinkAccessor);
368 ldmx_log(debug) <<
"Setting up surfaces...";
370 std::shared_ptr<const Acts::PerigeeSurface> origin_surface =
371 Acts::Surface::makeShared<Acts::PerigeeSurface>(
372 Acts::Vector3(0., 0., 0.));
374 ldmx_log(debug) <<
"About to run CKF...";
377 auto ckf_setup = std::chrono::high_resolution_clock::now();
378 profiling_map_[
"ckf_setup"] +=
379 std::chrono::duration<double, std::milli>(ckf_setup - seeds).count();
381 Acts::VectorTrackContainer vtc;
382 Acts::VectorMultiTrajectory mtj;
383 Acts::TrackContainer tc{vtc, mtj};
387 ldmx_log(debug) <<
"Loop on the track candidates";
388 for (
size_t trackId = 0u; trackId < startParameters.size(); ++trackId) {
389 ldmx_log(debug) <<
"---------------------------";
390 ldmx_log(debug) <<
"Candidate Track ID = " << trackId;
392 const Acts::CombinatorialKalmanFilterOptions<SourceLinkAccIt,
394 ckfOptions(TrackingGeometryUser::geometry_context(),
395 TrackingGeometryUser::magnetic_field_context(),
396 TrackingGeometryUser::calibration_context(),
397 sourceLinkAccessorDelegate, ckf_extensions,
398 propagator_options,
true ,
401 ldmx_log(debug) <<
" Checking options: multiple scattering = "
402 << ckfOptions.multipleScattering
403 <<
" energy loss = " << ckfOptions.energyLoss;
405 ckf_->findTracks(startParameters.at(trackId), ckfOptions, tc);
407 auto start_params = startParameters.at(trackId).parameters().transpose();
409 <<
" Checking CKF success for track candidate with params: "
410 <<
" D0 = " << start_params[0] <<
" Z0 = " << start_params[1]
411 <<
", Phi = " << start_params[2] <<
" Theta = " << start_params[3]
412 <<
", QoP = " << start_params[4] <<
" Time = " << start_params[5];
413 if (not results.ok()) {
414 ldmx_log(debug) <<
" CKF failed!";
417 ldmx_log(debug) <<
" CKF succeded!";
420 auto& tracksFromSeed = results.value();
421 if (tracksFromSeed.size() != 1) {
422 ldmx_log(info) <<
" tracksFromSeed.size = " << tracksFromSeed.size();
425 for (
auto& track : tracksFromSeed) {
427 Acts::smoothTrack(geometry_context(), track);
433 bool success = trk_extrap_->TrackStateAtSurface(
434 track, target_surface, tsAtTarget, ldmx::TrackStateType::AtTarget);
437 ldmx_log(debug) <<
" Successfully obtained TrackState at target";
439 ldmx_log(debug) <<
" Parameters At Target: Loc0 = "
440 << tsAtTarget.params[0] <<
", Loc1 "
441 << tsAtTarget.params[1]
442 <<
", phi = " << tsAtTarget.params[2]
443 <<
", theta = " << tsAtTarget.params[3] <<
", QoP "
444 << tsAtTarget.params[4];
446 trk.addTrackState(tsAtTarget);
448 ldmx_log(info) <<
" Could not extrapolate to target! nhits = "
449 << track.nMeasurements() <<
" Printing track states: ";
450 for (
const auto ts : track.trackStatesReversed()) {
451 if (ts.hasSmoothed()) {
452 ldmx_log(info) <<
" Track momentum for smoothed track state = "
453 << 1 / ts.smoothed()[Acts::eBoundQOverP];
454 ldmx_log(info) <<
" Parameters: " << ts.smoothed().transpose();
456 ldmx_log(info) <<
" Track state not smoothed!";
459 ldmx_log(info) <<
" ...skipping this track candidate...";
470 Acts::BoundTrackParameters boundStateAtTarget =
471 tracking::sim::utils::btp(tsAtTarget, target_surface, 11);
472 track.setReferenceSurface(target_surface);
473 track.parameters() = boundStateAtTarget.parameters();
477 const Acts::BoundVector& track_pars = track.parameters();
480 ldmx_log(debug) <<
" Track parameters (at target): Loc0 = "
481 << track_pars[Acts::eBoundLoc0]
482 <<
", Loc1 = " << track_pars[Acts::eBoundLoc1]
483 <<
", Theta = " << track_pars[Acts::eBoundTheta]
484 <<
", Phi = " << track_pars[Acts::eBoundPhi]
485 <<
", chi2 = " << track.chi2()
486 <<
", nHits = " << track.nMeasurements();
489 trk.setPerigeeLocation(0, 0, 0);
491 trk.setPerigeeCov(tsAtTarget.cov);
493 trk.setChi2(track.chi2());
494 trk.setNhits(track.nMeasurements());
497 trk.setNdf(track.nMeasurements() - 5);
498 trk.setNsharedHits(track.nSharedHits());
500 ldmx_log(debug) <<
" Track momentum: px = " << track.momentum()[0]
501 <<
" py = " << track.momentum()[1]
502 <<
" pz = " << track.momentum()[2];
503 trk.setMomentum(track.momentum()[0], track.momentum()[1],
504 track.momentum()[2]);
507 if ((trk.getNhits() <= min_hits_) || (abs(1. / trk.getQoP()) <= 0.05)) {
509 <<
" > Track candidate did NOT meet the requirements: Nhits = "
510 << trk.getNhits() <<
" and p = " << abs(1. / trk.getQoP())
518 ldmx_log(debug) <<
" Add measurements to the final track from "
519 << track.nTrackStates() <<
" TrackStates with "
520 << track.nMeasurements() <<
" measurements";
522 int trk_state_index{0};
523 for (
const auto ts : track.trackStatesReversed()) {
525 ldmx_log(debug) <<
" Checking Track State index = "
526 << trk_state_index <<
" at location "
527 << ts.referenceSurface()
528 .transform(geometry_context())
532 if (ts.hasSmoothed()) {
533 ldmx_log(debug) <<
" Smoothed track parameters: "
534 << ts.smoothed().transpose();
540 auto typeFlags = ts.typeFlags();
542 if (typeFlags.test(Acts::TrackStateFlag::MeasurementFlag) &&
543 ts.hasUncalibratedSourceLink()) {
545 ts.getUncalibratedSourceLink()
546 .template get<ActsExamples::IndexSourceLink>();
549 ldmx_log(debug) <<
" Adding measurement to ldmx::track with "
550 "source link index = "
552 ldmx_log(trace) <<
" Measurement:\n" << ldmx_meas;
553 trk.addMeasurementIndex(sl.
index());
555 ldmx_log(debug) <<
" This TrackState is not a measurement";
560 ldmx_log(debug) <<
" Starting extrapolations";
563 const double ECAL_SCORING_PLANE = 240.5;
564 Acts::Vector3 pos(ECAL_SCORING_PLANE, 0., 0.);
565 Acts::Translation3 surf_translation(pos);
566 Acts::Transform3 surf_transform(surf_translation * surf_rotation);
567 const std::shared_ptr<Acts::PlaneSurface> ecal_surface =
568 Acts::Surface::makeShared<Acts::PlaneSurface>(surf_transform);
572 Acts::Vector3 pos_hcal(540.0, 0., 0.);
573 Acts::Translation3 surf_translation_hcal(pos_hcal);
574 Acts::Transform3 surf_transform_hcal(surf_translation_hcal *
576 const std::shared_ptr<Acts::PlaneSurface> hcal_surface =
577 Acts::Surface::makeShared<Acts::PlaneSurface>(surf_transform_hcal);
580 const std::shared_ptr<Acts::Surface> beamOrigin_surface =
581 tracking::sim::utils::unboundSurface(-700);
583 if (taggerTracking_) {
584 ldmx_log(debug) <<
" Beam Origin Extrapolation";
586 success = trk_extrap_->TrackStateAtSurface(
587 track, beamOrigin_surface, tsAtBeamOrigin,
588 ldmx::TrackStateType::AtBeamOrigin);
591 trk.addTrackState(tsAtBeamOrigin);
593 <<
" Successfully obtained TrackState at beam origin";
598 if (!taggerTracking_) {
599 ldmx_log(debug) <<
" Ecal Extrapolation";
601 success = trk_extrap_->TrackStateAtSurface(
602 track, ecal_surface, tsAtEcal, ldmx::TrackStateType::AtECAL);
605 trk.addTrackState(tsAtEcal);
606 ldmx_log(debug) <<
" Successfully obtained TrackState at Ecal";
607 ldmx_log(debug) <<
" Parameters At Ecal: Loc0 = "
608 << tsAtEcal.params[0]
609 <<
", Loc1 = " << tsAtEcal.params[1]
610 <<
", phi = " << tsAtEcal.params[2]
611 <<
", theta = " << tsAtEcal.params[3]
612 <<
", QoP = " << tsAtEcal.params[4];
614 ldmx_log(info) <<
" Could not extrapolate to ECAL!! Please check "
620 if (!taggerTracking_) {
621 ldmx_log(debug) <<
" Hcal Extrapolation";
623 success = trk_extrap_->TrackStateAtSurface(
624 track, hcal_surface, tsAtHcal, ldmx::TrackStateType::AtHCAL);
627 trk.addTrackState(tsAtHcal);
628 ldmx_log(debug) <<
" Successfully obtained TrackState at Hcal";
629 ldmx_log(debug) <<
" Parameters At Hcal: Loc0 = "
630 << tsAtHcal.params[0]
631 <<
", Loc1 = " << tsAtHcal.params[1]
632 <<
", phi = " << tsAtHcal.params[2]
633 <<
", theta = " << tsAtHcal.params[3]
634 <<
", QoP = " << tsAtHcal.params[4];
636 ldmx_log(info) <<
" Could not extrapolate to HCAL!! Please check "
642 if (truthMatchingTool) {
643 auto truthInfo = truthMatchingTool->TruthMatch(trk);
644 trk.setTrackID(truthInfo.trackID);
645 trk.setPdgID(truthInfo.pdgID);
646 trk.setTruthProb(truthInfo.truthProb);
651 <<
" > Adding the track candidate to the track collection";
652 tracks.push_back(trk);
657 ldmx_log(info) <<
"Number of CKF tracks " << tracks.size();
659 auto ckf_run = std::chrono::high_resolution_clock::now();
660 profiling_map_[
"ckf_run"] +=
661 std::chrono::duration<double, std::milli>(ckf_run - ckf_setup).count();
664 auto sharedHits = computeSharedHits(tracks, measurements, tg,
665 tracking::sim::utils::sourceLinkHash,
666 tracking::sim::utils::sourceLinkEquality);
667 for (std::size_t iTrack = 0; iTrack < sharedHits.size(); ++iTrack) {
668 tracks[iTrack].setNsharedHits(sharedHits[iTrack].size());
669 for (
auto idx : sharedHits[iTrack]) {
670 tracks[iTrack].addSharedIndex(idx);
674 auto result_loop = std::chrono::high_resolution_clock::now();
675 profiling_map_[
"result_loop"] +=
676 std::chrono::duration<double, std::milli>(result_loop - ckf_run).count();
679 event.add(out_trk_collection_, tracks);
681 auto end = std::chrono::high_resolution_clock::now();
684 auto diff = end - start;
685 processing_time_ += std::chrono::duration<double, std::milli>(diff).count();