LDMX Software
GSFProcessor.cxx
1#include "Tracking/Reco/GSFProcessor.h"
2
3#include <algorithm>
4
5#include "Acts/EventData/SourceLink.hpp"
6
7namespace tracking {
8namespace reco {
9
10GSFProcessor::GSFProcessor(const std::string& name, framework::Process& process)
11 : TrackingGeometryUser(name, process) {}
12
14 beam_origin_surface_ = tracking::sim::utils::unboundSurface(-700);
15 target_surface_ = tracking::sim::utils::unboundSurface(0.);
16 ecal_surface_ = tracking::sim::utils::unboundSurface(240.5);
17
18 // Custom transformation of the interpolated bfield map
19 bool debug_transform = false;
20 auto transform_pos = [debug_transform](const Acts::Vector3& pos_) {
21 Acts::Vector3 rot_pos;
22 rot_pos(0) = pos_(1);
23 rot_pos(1) = pos_(2);
24 rot_pos(2) = pos_(0) + DIPOLE_OFFSET;
25
26 // Apply A rotation around the center of the magnet. (I guess offset first
27 // and then rotation)
28
29 if (debug_transform) {
30 std::cout << "PF::DEFAULT3 TRANSFORM\n";
31 std::cout << "PF::Check:: transforming Pos\n";
32 std::cout << pos_;
33 std::cout << "\nTO\n";
34 std::cout << rot_pos << "\n";
35 }
36
37 return rot_pos;
38 };
39
40 // Reminder about coordinate system:
41 // acts x = global z
42 // acts y = global x
43 // acts z = global y
44 Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Identity();
45 double scale = 1.;
46
47 auto transform_b_field = [rotation, scale, debug_transform](
48 const Acts::Vector3& field,
49 const Acts::Vector3& /*pos_*/) {
50 // Rotate the field in tracking coordinates
51 Acts::Vector3 rot_field;
52 rot_field(0) = field(2);
53 rot_field(1) = field(0);
54 rot_field(2) = field(1);
55
56 // Scale the field
57 rot_field = scale * rot_field;
58
59 // Rotate the field
60 rot_field = rotation * rot_field;
61
62 // A distortion scaled by position.
63
64 if (debug_transform) {
65 std::cout << "PF::DEFAULT3 TRANSFORM\n";
66 std::cout << "PF::Check:: transforming\n";
67 std::cout << field;
68 std::cout << "\nTO\n";
69 std::cout << rot_field << "\n";
70 }
71
72 return rot_field;
73 };
74
75 // Setup a interpolated bfield map
76 const auto map = std::make_shared<InterpolatedMagneticField3>(
77 loadDefaultBField(field_map_,
78 // default_transformPos,
79 // default_transformBField));
80 transform_pos, transform_b_field));
81
82 auto acts_logging_level = Acts::Logging::FATAL;
83
84 if (debug_) acts_logging_level = Acts::Logging::VERBOSE;
85
86 // Setup the GSF Fitter
87
88 // Stepper
89 // Acts::MixtureReductionMethod finalReductionMethod;
90 // const auto multi_stepper = Acts::MultiEigenStepperLoop{map};
91
92 // Acts::ComponentMergeMethod reductionMethod =
93 // Acts::ComponentMergeMethod::eMaxWeight;
94 // Acts::MultiEigenStepperLoop multi_stepper(
95 // map, reductionMethod,
96 // Acts::getDefaultLogger("GSF_STEP", acts_loggingLevel));
97
98 Acts::MultiEigenStepperLoop multi_stepper(map);
99 // Detailed Stepper
100
101 // Acts::MultiEigenStepperLoop multi_stepper(map, finalReductionMethod);
102
103 // Navigator
104 Acts::Navigator::Config nav_cfg{geometry().getTG()};
105 nav_cfg.resolveMaterial = true;
106 nav_cfg.resolvePassive = false;
107 nav_cfg.resolveSensitive = true;
108 const Acts::Navigator navigator(nav_cfg);
109
110 auto gsf_propagator =
111 GsfPropagator(std::move(multi_stepper), std::move(navigator),
112 Acts::getDefaultLogger("GSF_PROP", acts_logging_level));
113
114 BetheHeitlerApprox bethe_heitler = Acts::makeDefaultBetheHeitlerApprox();
115
116 gsf_ = std::make_unique<std::decay_t<decltype(*gsf_)>>(
117 std::move(gsf_propagator), std::move(bethe_heitler),
118 Acts::getDefaultLogger("GSF", acts_logging_level));
119
120 const auto stepper = Acts::EigenStepper<>{map};
121 propagator_ = std::make_unique<Propagator>(
122 stepper, navigator,
123 Acts::getDefaultLogger("GSF_EXTRAP", acts_logging_level));
124
125 trk_extrap_ = std::make_shared<std::decay_t<decltype(*trk_extrap_)>>(
126 *propagator_, geometryContext(), magneticFieldContext());
127}
128
131 parameters.get<std::string>("out_trk_collection", "GSFTracks");
132
134 parameters.get<std::string>("track_collection", "TaggerTracks");
136 parameters.get<std::string>("meas_collection", "DigiTaggerSimHits");
137
138 track_passname_ = parameters.get<std::string>("track_passname");
139 meas_passname_ = parameters.get<std::string>("meas_passname");
141 parameters.get<std::string>("track_collection_event_passname");
143 parameters.get<std::string>("meas_collection_event_passname");
144
145 max_components_ = parameters.get<int>("maxComponents", 4);
146 abort_on_error_ = parameters.get<bool>("abortOnError", false);
148 parameters.get<bool>("disableAllMaterialHandling", false);
149 weight_cutoff_ = parameters.get<double>("weight_cutoff_", 1.0e-4);
150
151 propagator_max_steps_ = parameters.get<int>("propagator_maxSteps", 10000);
152 propagator_step_size_ = parameters.get<double>("propagator_step_size", 200.);
153 field_map_ = parameters.get<std::string>("field_map");
154 use_perigee_ = parameters.get<bool>("usePerigee", false);
155
156 debug_ = parameters.get<bool>("debug", false);
157 tagger_tracking_ = parameters.get<bool>("taggerTracking", true);
158
159 // final_reduction_method_ =
160 // parameters.get<double>("finalReductionMethod",);
161} // end of configure()
162
164 // General Setup
165
166 auto tg{geometry()};
167
168 // Retrieve the tracks
170 return;
171 auto tracks{
172 event.getCollection<ldmx::Track>(track_collection_, track_passname_)};
173
174 // Retrieve the measurements
176 auto measurements{
177 event.getCollection<ldmx::Measurement>(meas_collection_, meas_passname_)};
178
179 tracking::sim::LdmxMeasurementCalibrator calibrator{measurements};
180
181 // GSF Setup
182 Acts::GainMatrixUpdater updater;
183 Acts::GsfExtensions<Acts::VectorMultiTrajectory> gsf_extensions;
184 gsf_extensions.updater.connect<
185 &Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>(
186 &updater);
187 gsf_extensions.calibrator
189 Acts::VectorMultiTrajectory>>(&calibrator);
190
191 // Surface Accessor
192 struct SurfaceAccessor {
193 const Acts::TrackingGeometry* tracking_geometry_;
194
195 const Acts::Surface* operator()(const Acts::SourceLink& sourceLink) const {
196 const auto& index_source_link =
197 sourceLink.get<acts_examples::IndexSourceLink>();
198 return tracking_geometry_->findSurface(index_source_link.geometryId());
199 }
200 };
201
202 SurfaceAccessor m_sl_surface_accessor{tg.getTG().get()};
203 // m_slSurfaceAccessor.trackingGeometry = tg.getTG();
204 gsf_extensions.surfaceAccessor.connect<&SurfaceAccessor::operator()>(
205 &m_sl_surface_accessor);
206 gsf_extensions.mixtureReducer.connect<&Acts::reduceMixtureLargestWeights>();
207
208 // Propagator Options
209
210 // Move this at the start of the producer
211 Acts::PropagatorOptions<Acts::StepperPlainOptions,
212 Acts::NavigatorPlainOptions, ActionList, AbortList>
213 propagator_options(geometryContext(), magneticFieldContext());
214
215 propagator_options.pathLimit = std::numeric_limits<double>::max();
216
217 // Activate loop protection at some pt value
218 propagator_options.loopProtection = false;
219 //(startParameters.transverseMomentum() < cfg.ptLoopers);
220
221 // Switch the material interaction on/off & eventually into logging mode
222 auto& m_interactor =
223 propagator_options.actionList.get<Acts::MaterialInteractor>();
224 m_interactor.multipleScattering = true;
225 m_interactor.energyLoss = true;
226 m_interactor.recordInteractions = false;
227
228 // The logger can be switched to sterile, e.g. for timing logging
229 auto& s_logger =
230 propagator_options.actionList.get<Acts::detail::SteppingLogger>();
231 s_logger.sterile = true;
232 // Set a maximum step size
233 propagator_options.stepping.maxStepSize =
234 propagator_step_size_ * Acts::UnitConstants::mm;
235 propagator_options.maxSteps = propagator_max_steps_;
236
237 // Electron hypothesis
238 // propagator_options.mass = 0.511 * Acts::UnitConstants::MeV;
239
240 // GSF options will be configured per-track
241 std::shared_ptr<const Acts::Surface> gsf_ref_surface;
242 Acts::GsfOptions<Acts::VectorMultiTrajectory> gsf_options{
243 geometryContext(), magneticFieldContext(), calibrationContext()};
244 gsf_options.extensions = gsf_extensions;
245 gsf_options.propagatorPlainOptions = propagator_options;
246 gsf_options.maxComponents = max_components_;
247 gsf_options.weightCutoff = weight_cutoff_;
248 gsf_options.abortOnError = abort_on_error_;
249 gsf_options.disableAllMaterialHandling = disable_all_material_handling_;
250
251 // Output track container
252 std::vector<ldmx::Track> out_tracks;
253
254 Acts::VectorTrackContainer vtc;
255 Acts::VectorMultiTrajectory mtj;
256 Acts::TrackContainer tc{vtc, mtj};
257
258 // Loop on tracks
259 unsigned int itrk = 0;
260 ldmx_log(debug) << "Starting GSF processing of " << tracks.size()
261 << " tracks";
262
263 for (auto& track : tracks) {
264 ldmx_log(debug) << "Processing track " << itrk << " with "
265 << track.getMeasurementsIdxs().size() << " measurements";
266 // Retrieve measurements on track
267 std::vector<ldmx::Measurement> meas_on_track;
268
269 // std::vector<ActsExamples::IndexSourceLink> fit_trackSourceLinks;
270 std::vector<Acts::SourceLink> fit_track_source_links;
271
272 for (auto imeas : track.getMeasurementsIdxs()) {
273 auto meas = measurements.at(imeas);
274 meas_on_track.push_back(meas);
275
276 // Retrieve the surface
277
278 const Acts::Surface* hit_surface =
279 tg.geo::TrackingGeometry::getSurface(meas.getLayerID());
280
281 // Store the index_ source link
282 acts_examples::IndexSourceLink idx_sl(hit_surface->geometryId(), imeas);
283 fit_track_source_links.push_back(Acts::SourceLink(idx_sl));
284 }
285
286 // Reverse the order of the vectors
287 std::reverse(meas_on_track.begin(), meas_on_track.end());
288 std::reverse(fit_track_source_links.begin(), fit_track_source_links.end());
289
290 for (auto m : meas_on_track) {
291 ldmx_log(trace) << " Measurement:\n" << m << "\n";
292 }
293
294 ldmx_log(debug) << " Track bound track parameters preparation:";
295
296 // Get the track parameters
297
298 std::shared_ptr<Acts::PerigeeSurface> perigee =
299 Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3(
300 track.getPerigeeX(), track.getPerigeeY(), track.getPerigeeZ()));
301
302 Acts::BoundTrackParameters trk_btp =
303 tracking::sim::utils::boundTrackParameters(track, perigee);
304
305 Acts::BoundTrackParameters trk_btp_beam_origin =
306 tracking::sim::utils::boundTrackParameters(track, perigee);
307
308 if (tagger_tracking_) {
309 if (!track.getTrackState(ldmx::TrackStateType::AtBeamOrigin)
310 .has_value()) {
311 ldmx_log(warn) << "Failed retreiving AtBeamOrigin TrackState for "
312 "track. Skipping..";
313 continue;
314 }
315
316 auto ts = track.getTrackState(ldmx::TrackStateType::AtBeamOrigin).value();
317 trk_btp_beam_origin =
318 tracking::sim::utils::btp(ts, beam_origin_surface_, 11);
319 }
320 // Recoil tracking
321 else {
322 if (!track.getTrackState(ldmx::TrackStateType::AtTarget).has_value()) {
323 ldmx_log(warn)
324 << "Failed retreiving AtTarget TrackState for track. Skipping..";
325 continue;
326 }
327 auto ts = track.getTrackState(ldmx::TrackStateType::AtTarget).value();
328 trk_btp_beam_origin = tracking::sim::utils::btp(ts, target_surface_, 11);
329 }
330 ldmx_log(debug) << " Perigee Surface (acts-x, acts-y, acts-z) = ("
331 << track.getPerigeeX() << ", " << track.getPerigeeY()
332 << ", " << track.getPerigeeZ() << ")";
333
334 const Acts::BoundVector& trkpars = trk_btp.parameters();
335 ldmx_log(debug) << " Track parameters (d0, z0, phi, theta, q/p)= ("
336 << trkpars[Acts::eBoundLoc0] << ", "
337 << trkpars[Acts::eBoundLoc1] << ", "
338 << trkpars[Acts::eBoundPhi] << ", "
339 << trkpars[Acts::eBoundTheta] << ", "
340 << trkpars[Acts::eBoundQOverP] << ")";
341
342 Acts::Vector3 trk_pos = trk_btp.position(geometryContext());
343 ldmx_log(debug) << " Track position (acts-x, acts-y, acts-z) = ("
344 << trk_pos(0) << ", " << trk_pos(1) << ", " << trk_pos(2)
345 << ")";
346
347 const Acts::BoundVector& trk_pars_beam_origin =
348 trk_btp_beam_origin.parameters();
349 ldmx_log(debug)
350 << " BeamOrigin track parameters (d0, z0, phi, theta, q/p)= ("
351 << trk_pars_beam_origin[Acts::eBoundLoc0] << ", "
352 << trk_pars_beam_origin[Acts::eBoundLoc1] << ", "
353 << trk_pars_beam_origin[Acts::eBoundPhi] << ", "
354 << trk_pars_beam_origin[Acts::eBoundTheta] << ", "
355 << trk_pars_beam_origin[Acts::eBoundQOverP] << ")";
356
357 Acts::Vector3 trk_pos_beam_origin =
358 trk_btp_beam_origin.position(geometryContext());
359 ldmx_log(debug)
360 << " BeamOrigin track position (acts-x, acts-y, acts-z) = ("
361 << trk_pos_beam_origin(0) << ", " << trk_pos_beam_origin(1) << ", "
362 << trk_pos_beam_origin(2) << ")";
363
364 ldmx_log(debug) << " About to run GSF fit with "
365 << fit_track_source_links.size() << " source links";
366
367 // Update GSF reference surface for this track
368 if (tagger_tracking_) {
369 gsf_ref_surface = beam_origin_surface_;
370 } else {
371 gsf_ref_surface = target_surface_;
372 }
373 gsf_options.referenceSurface = &(*gsf_ref_surface);
374
375 // Use beam origin track for GSF fitting (has correct trajectory for
376 // measurements) but we'll extrapolate to (0,0,0) for final parameters
377 auto gsf_refit_result =
378 gsf_->fit(fit_track_source_links.begin(), fit_track_source_links.end(),
379 trk_btp_beam_origin, gsf_options, tc);
380
381 if (!gsf_refit_result.ok()) {
382 ldmx_log(warn) << "GSF re-fit failed: "
383 << gsf_refit_result.error().message();
384 continue;
385 }
386
387 ldmx_log(debug) << " GSF fit succeeded, tc.size() = " << tc.size();
388
389 if (tc.size() < 1) continue;
390
391 auto gsftrk = tc.getTrack(0);
392 // calculateTrackQuantities(gsftrk);
393
394 const Acts::BoundVector& perigee_pars = gsftrk.parameters();
395 const Acts::BoundMatrix& trk_cov = gsftrk.covariance();
396 const Acts::Surface& perigee_surface = gsftrk.referenceSurface();
397
398 ldmx_log(debug)
399 << " Reference Surface (acts-x, acts-y, acts-z) = ("
400 << perigee_surface.transform(geometryContext()).translation()(0) << ", "
401 << perigee_surface.transform(geometryContext()).translation()(1) << ", "
402 << perigee_surface.transform(geometryContext()).translation()(2) << ")";
403
404 ldmx_log(debug) << " Found track has " << gsftrk.nTrackStates()
405 << " track states";
406
407 ldmx_log(debug) << " Track parameters (d0, z0, phi, theta, q/p)= ("
408 << perigee_pars[Acts::eBoundLoc0] << ", "
409 << perigee_pars[Acts::eBoundLoc1] << ", "
410 << perigee_pars[Acts::eBoundPhi] << ", "
411 << perigee_pars[Acts::eBoundTheta] << ", "
412 << perigee_pars[Acts::eBoundQOverP] << ") ";
413
414 ldmx::Track trk = ldmx::Track();
415
416 bool success = false;
417 bool success_ecal = false;
418 ldmx::Track::TrackState ts_at_target_surface;
419
420 if (tagger_tracking_) {
421 ldmx_log(debug) << " Target extrapolation";
422 ldmx::Track::TrackState ts_at_target;
423
424 success = trk_extrap_->trackStateAtSurface(
425 gsftrk, target_surface_, ts_at_target,
426 ldmx::TrackStateType::AtTarget);
427
428 if (success) {
429 trk.addTrackState(ts_at_target);
430 ts_at_target_surface = ts_at_target;
431 }
432 } // end tagger tracking
433 else {
434 ldmx_log(debug) << " Ecal Extrapolation";
435 ldmx::Track::TrackState ts_at_ecal;
436 success_ecal = trk_extrap_->trackStateAtSurface(
437 gsftrk, ecal_surface_, ts_at_ecal, ldmx::TrackStateType::AtECAL);
438
439 if (success_ecal) trk.addTrackState(ts_at_ecal);
440
441 // Also get track state at target for perigee parameters
442 ldmx_log(debug) << " Target extrapolation for perigee parameters";
443 success = trk_extrap_->trackStateAtSurface(
444 gsftrk, target_surface_, ts_at_target_surface,
445 ldmx::TrackStateType::AtTarget);
446 if (success) trk.addTrackState(ts_at_target_surface);
447 } // end recoil tracking
448
449 // Use parameters at target surface (0, 0, 0) for perigee
450 trk.setPerigeeLocation(0., 0., 0.);
451 trk.setChi2(gsftrk.chi2());
452 trk.setNhits(gsftrk.nMeasurements());
453 trk.setNdf(gsftrk.nMeasurements() - 5);
454 if (success) {
455 ldmx_log(debug) << " Extrapolated track parameters at target (d0, z0, "
456 "phi, theta, q/p)= ("
457 << ts_at_target_surface.params_[Acts::eBoundLoc0] << ", "
458 << ts_at_target_surface.params_[Acts::eBoundLoc1] << ", "
459 << ts_at_target_surface.params_[Acts::eBoundPhi] << ", "
460 << ts_at_target_surface.params_[Acts::eBoundTheta] << ", "
461 << ts_at_target_surface.params_[Acts::eBoundQOverP]
462 << ")";
463 ldmx_log(debug) << " Using extrapolated parameters";
464 trk.setPerigeeParameters(ts_at_target_surface.params_);
465 std::vector<double> cov;
466 for (auto c : ts_at_target_surface.cov_) cov.push_back(c);
467 ldmx_log(debug) << " Setting extrapolated covariance, size="
468 << cov.size();
469 trk.setPerigeeCov(cov);
470 } else {
471 ldmx_log(debug) << " Extrapolation failed, using perigee parameters";
472 ldmx_log(debug) << " Perigee parameters (d0, z0, phi, theta, q/p)= ("
473 << perigee_pars[Acts::eBoundLoc0] << ", "
474 << perigee_pars[Acts::eBoundLoc1] << ", "
475 << perigee_pars[Acts::eBoundPhi] << ", "
476 << perigee_pars[Acts::eBoundTheta] << ", "
477 << perigee_pars[Acts::eBoundQOverP] << ")";
479 tracking::sim::utils::convertActsToLdmxPars(perigee_pars));
480 std::vector<double> v_trk_cov;
481 tracking::sim::utils::flatCov(trk_cov, v_trk_cov);
482 ldmx_log(debug) << " Setting perigee covariance, size="
483 << v_trk_cov.size();
484 trk.setPerigeeCov(v_trk_cov);
485 }
486 Acts::Vector3 trk_momentum = gsftrk.momentum();
487 trk.setMomentum(trk_momentum(0), trk_momentum(1), trk_momentum(2));
488
489 // truth information
490 trk.setTrackID(track.getTrackID());
491 trk.setPdgID(track.getPdgID());
492 trk.setTruthProb(track.getTruthProb());
493
494 itrk++;
495
496 ldmx_log(debug) << " Added track to output, total tracks = "
497 << (out_tracks.size() + 1);
498
499 out_tracks.push_back(trk);
500
501 } // loop on tracks
502
503 event.add(out_trk_collection_, out_tracks);
504} // end of produce()
505
508
509} // namespace reco
510} // namespace tracking
511
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Implements an event buffer system for storing event data.
Definition Event.h:42
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.
Definition Event.cxx:92
Class which represents the process under execution.
Definition Process.h:37
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
Run-specific configuration and data stored in its own output TTree alongside the event TTree in the o...
Definition RunHeader.h:57
Implementation of a track object.
Definition Track.h:53
void setPerigeeParameters(const std::vector< double > &par)
d_0 z_0 phi_0 theta q/p t
Definition Track.h:161
bool disable_all_material_handling_
Disable all material interactions during propagation.
std::unique_ptr< const Acts::GaussianSumFitter< GsfPropagator, BetheHeitlerApprox, Acts::VectorMultiTrajectory > > gsf_
Gaussian Sum Fitter instance for track refitting.
std::shared_ptr< Acts::Surface > target_surface_
Target surface at z=0 mm (recoil track initialization, perigee output)
void produce(framework::Event &event) override
Run the processor.
bool debug_
Enable verbose debug output logging.
std::string track_collection_
Collection name for input tracks to be refit.
size_t max_components_
Maximum number of mixture components in GSF fit.
std::string meas_collection_
Collection name for measurements associated with tracks.
bool abort_on_error_
Abort fit if any error occurs (strict error handling)
std::string meas_passname_
Pass name for measurement collection in event.
void onProcessEnd() override
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
double weight_cutoff_
Weight threshold below which mixture components are dropped.
std::string field_map_
Path to magnetic field map file.
void configure(framework::config::Parameters &parameters) override
Configure the processor using the given user specified parameters.
int propagator_max_steps_
Maximum number of propagation steps before aborting.
bool use_perigee_
Use perigee parameterization for tracks.
GSFProcessor(const std::string &name, framework::Process &process)
Constructor.
void onProcessStart() override
Callback for the EventProcessor to take any necessary action when the processing of events starts,...
void onNewRun(const ldmx::RunHeader &rh) override
onNewRun is the first function called for each processor after the conditions are fully configured an...
std::string track_collection_event_passname_
Pass name qualifier for track collection event key.
std::unique_ptr< const Propagator > propagator_
Propagator for track extrapolation using eigen stepper.
double propagator_step_size_
Step size for track propagation in mm.
std::shared_ptr< Acts::Surface > beam_origin_surface_
Beam origin surface at z=-700 mm (tagger track initialization)
std::string track_passname_
Pass name for track collection in event.
std::shared_ptr< Acts::Surface > ecal_surface_
ECAL surface at z=240.5 mm (ECAL scoring plane for recoil tracking)
std::string meas_collection_event_passname_
Pass name qualifier for measurement collection event key.
std::string out_trk_collection_
Collection name for output GSF-refitted tracks.
a helper base class providing some methods to shorten access to common conditions used within the tra...
void calibrate1d(const Acts::GeometryContext &, const Acts::CalibrationContext &, const Acts::SourceLink &genericSourceLink, typename traj_t::TrackStateProxy trackState) const
Find the measurement corresponding to the source link.
The measurement calibrator can be a function or a class/struct able to retrieve the sim hits containe...