LDMX Software
GSFProcessor.cxx
1#include "Tracking/Reco/GSFProcessor.h"
2
3#include <algorithm>
4
5#include "Acts/EventData/SourceLink.hpp"
6#include "Tracking/Event/Track.h"
7
8namespace tracking {
9namespace reco {
10
11GSFProcessor::GSFProcessor(const std::string& name, framework::Process& process)
12 : TrackingGeometryUser(name, process) {}
13
15 beam_origin_surface_ = tracking::sim::utils::unboundSurface(-700);
16 target_surface_ = tracking::sim::utils::unboundSurface(0.);
17 ecal_surface_ = tracking::sim::utils::unboundSurface(240.5);
18
19 // Custom transformation of the interpolated bfield map
20 bool debug_transform = false;
21 auto transform_pos = [debug_transform](const Acts::Vector3& pos_) {
22 Acts::Vector3 rot_pos;
23 rot_pos(0) = pos_(1);
24 rot_pos(1) = pos_(2);
25 rot_pos(2) = pos_(0) + DIPOLE_OFFSET;
26
27 // Apply A rotation around the center of the magnet. (I guess offset first
28 // and then rotation)
29
30 if (debug_transform) {
31 std::cout << "PF::DEFAULT3 TRANSFORM\n";
32 std::cout << "PF::Check:: transforming Pos\n";
33 std::cout << pos_;
34 std::cout << "\nTO\n";
35 std::cout << rot_pos << "\n";
36 }
37
38 return rot_pos;
39 };
40
41 // Reminder about coordinate system:
42 // acts x = global z
43 // acts y = global x
44 // acts z = global y
45 Acts::RotationMatrix3 rotation = Acts::RotationMatrix3::Identity();
46 double scale = 1.;
47
48 auto transform_b_field = [rotation, scale, debug_transform](
49 const Acts::Vector3& field,
50 const Acts::Vector3& /*pos_*/) {
51 // Rotate the field in tracking coordinates
52 Acts::Vector3 rot_field;
53 rot_field(0) = field(2);
54 rot_field(1) = field(0);
55 rot_field(2) = field(1);
56
57 // Scale the field
58 rot_field = scale * rot_field;
59
60 // Rotate the field
61 rot_field = rotation * rot_field;
62
63 // A distortion scaled by position.
64
65 if (debug_transform) {
66 std::cout << "PF::DEFAULT3 TRANSFORM\n";
67 std::cout << "PF::Check:: transforming\n";
68 std::cout << field;
69 std::cout << "\nTO\n";
70 std::cout << rot_field << "\n";
71 }
72
73 return rot_field;
74 };
75
76 // Setup a interpolated bfield map
77 const auto map = std::make_shared<InterpolatedMagneticField3>(
78 loadDefaultBField(field_map_,
79 // default_transformPos,
80 // default_transformBField));
81 transform_pos, transform_b_field));
82
83 auto acts_logging_level = Acts::Logging::FATAL;
84
85 if (debug_) acts_logging_level = Acts::Logging::VERBOSE;
86
87 // Setup the GSF Fitter
88
89 // Stepper
90 // Acts::MixtureReductionMethod finalReductionMethod;
91 // const auto multi_stepper = Acts::MultiEigenStepperLoop{map};
92
93 // Acts::ComponentMergeMethod reductionMethod =
94 // Acts::ComponentMergeMethod::eMaxWeight;
95 // Acts::MultiEigenStepperLoop multi_stepper(
96 // map, reductionMethod,
97 // Acts::getDefaultLogger("GSF_STEP", acts_loggingLevel));
98
99 Acts::MultiEigenStepperLoop multi_stepper(map);
100 // Detailed Stepper
101
102 // Acts::MultiEigenStepperLoop multi_stepper(map, finalReductionMethod);
103
104 // Navigator
105 Acts::Navigator::Config nav_cfg{geometry().getTG()};
106 nav_cfg.resolveMaterial = true;
107 nav_cfg.resolvePassive = false;
108 nav_cfg.resolveSensitive = true;
109 const Acts::Navigator navigator(nav_cfg);
110
111 auto gsf_propagator =
112 GsfPropagator(std::move(multi_stepper), std::move(navigator),
113 Acts::getDefaultLogger("GSF_PROP", acts_logging_level));
114
115 BetheHeitlerApprox bethe_heitler = Acts::makeDefaultBetheHeitlerApprox();
116
117 gsf_ = std::make_unique<std::decay_t<decltype(*gsf_)>>(
118 std::move(gsf_propagator), std::move(bethe_heitler),
119 Acts::getDefaultLogger("GSF", acts_logging_level));
120
121 const auto stepper = Acts::EigenStepper<>{map};
122 propagator_ = std::make_unique<Propagator>(
123 stepper, navigator,
124 Acts::getDefaultLogger("GSF_EXTRAP", acts_logging_level));
125
126 trk_extrap_ = std::make_shared<std::decay_t<decltype(*trk_extrap_)>>(
127 *propagator_, geometryContext(), magneticFieldContext());
128}
129
132 parameters.get<std::string>("out_trk_collection", "GSFTracks");
133
135 parameters.get<std::string>("track_collection", "TaggerTracks");
137 parameters.get<std::string>("meas_collection", "DigiTaggerSimHits");
138
139 track_passname_ = parameters.get<std::string>("track_passname");
140 meas_passname_ = parameters.get<std::string>("meas_passname");
142 parameters.get<std::string>("track_collection_event_passname");
144 parameters.get<std::string>("meas_collection_event_passname");
145
146 max_components_ = parameters.get<int>("max_components", 4);
147 abort_on_error_ = parameters.get<bool>("abort_on_error", false);
149 parameters.get<bool>("disable_all_material_handling", false);
150 weight_cutoff_ = parameters.get<double>("weight_cutoff_", 1.0e-4);
151
152 propagator_max_steps_ = parameters.get<int>("propagator_max_steps", 10000);
153 propagator_step_size_ = parameters.get<double>("propagator_step_size", 200.);
154 field_map_ = parameters.get<std::string>("field_map");
155 use_perigee_ = parameters.get<bool>("usePerigee", false);
156
157 debug_ = parameters.get<bool>("debug", false);
158 tagger_tracking_ = parameters.get<bool>("tagger_tracking", true);
159
160 // final_reduction_method_ =
161 // parameters.get<double>("finalReductionMethod",);
162} // end of configure()
163
165 // General Setup
166
167 auto tg{geometry()};
168
169 // Retrieve the tracks
171 return;
172 auto tracks{
173 event.getCollection<ldmx::Track>(track_collection_, track_passname_)};
174
175 // Retrieve the measurements
177 auto measurements{
178 event.getCollection<ldmx::Measurement>(meas_collection_, meas_passname_)};
179
180 tracking::sim::LdmxMeasurementCalibrator calibrator{measurements};
181
182 // GSF Setup
183 Acts::GainMatrixUpdater updater;
184 Acts::GsfExtensions<Acts::VectorMultiTrajectory> gsf_extensions;
185 gsf_extensions.updater.connect<
186 &Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>(
187 &updater);
188 gsf_extensions.calibrator
190 Acts::VectorMultiTrajectory>>(&calibrator);
191
192 // Surface Accessor
193 struct SurfaceAccessor {
194 const Acts::TrackingGeometry* tracking_geometry_;
195
196 const Acts::Surface* operator()(const Acts::SourceLink& sourceLink) const {
197 const auto& index_source_link =
198 sourceLink.get<acts_examples::IndexSourceLink>();
199 return tracking_geometry_->findSurface(index_source_link.geometryId());
200 }
201 };
202
203 SurfaceAccessor m_sl_surface_accessor{tg.getTG().get()};
204 // m_slSurfaceAccessor.trackingGeometry = tg.getTG();
205 gsf_extensions.surfaceAccessor.connect<&SurfaceAccessor::operator()>(
206 &m_sl_surface_accessor);
207 gsf_extensions.mixtureReducer.connect<&Acts::reduceMixtureLargestWeights>();
208
209 // Propagator Options
210
211 // Move this at the start of the producer
212 Acts::PropagatorOptions<Acts::StepperPlainOptions,
213 Acts::NavigatorPlainOptions, ActionList, AbortList>
214 propagator_options(geometryContext(), magneticFieldContext());
215
216 propagator_options.pathLimit = std::numeric_limits<double>::max();
217
218 // Activate loop protection at some pt value
219 propagator_options.loopProtection = false;
220 //(startParameters.transverseMomentum() < cfg.ptLoopers);
221
222 // Switch the material interaction on/off & eventually into logging mode
223 auto& m_interactor =
224 propagator_options.actionList.get<Acts::MaterialInteractor>();
225 m_interactor.multipleScattering = true;
226 m_interactor.energyLoss = true;
227 m_interactor.recordInteractions = false;
228
229 // The logger can be switched to sterile, e.g. for timing logging
230 auto& s_logger =
231 propagator_options.actionList.get<Acts::detail::SteppingLogger>();
232 s_logger.sterile = true;
233 // Set a maximum step size
234 propagator_options.stepping.maxStepSize =
235 propagator_step_size_ * Acts::UnitConstants::mm;
236 propagator_options.maxSteps = propagator_max_steps_;
237
238 // Electron hypothesis
239 // propagator_options.mass = 0.511 * Acts::UnitConstants::MeV;
240
241 // GSF options will be configured per-track
242 std::shared_ptr<const Acts::Surface> gsf_ref_surface;
243 Acts::GsfOptions<Acts::VectorMultiTrajectory> gsf_options{
244 geometryContext(), magneticFieldContext(), calibrationContext()};
245 gsf_options.extensions = gsf_extensions;
246 gsf_options.propagatorPlainOptions = propagator_options;
247 gsf_options.maxComponents = max_components_;
248 gsf_options.weightCutoff = weight_cutoff_;
249 gsf_options.abortOnError = abort_on_error_;
250 gsf_options.disableAllMaterialHandling = disable_all_material_handling_;
251
252 // Output track container
253 std::vector<ldmx::Track> out_tracks;
254
255 Acts::VectorTrackContainer vtc;
256 Acts::VectorMultiTrajectory mtj;
257 Acts::TrackContainer tc{vtc, mtj};
258
259 // Loop on tracks
260 unsigned int itrk = 0;
261 ldmx_log(debug) << "Starting GSF processing of " << tracks.size()
262 << " tracks";
263
264 for (auto& track : tracks) {
265 ldmx_log(debug) << "Processing track " << itrk << " with "
266 << track.getMeasurementsIdxs().size() << " measurements";
267 // Retrieve measurements on track
268 std::vector<ldmx::Measurement> meas_on_track;
269
270 // std::vector<ActsExamples::IndexSourceLink> fit_trackSourceLinks;
271 std::vector<Acts::SourceLink> fit_track_source_links;
272
273 for (auto imeas : track.getMeasurementsIdxs()) {
274 auto meas = measurements.at(imeas);
275 meas_on_track.push_back(meas);
276
277 // Retrieve the surface
278
279 const Acts::Surface* hit_surface =
280 tg.geo::TrackingGeometry::getSurface(meas.getLayerID());
281
282 // Store the index_ source link
283 acts_examples::IndexSourceLink idx_sl(hit_surface->geometryId(), imeas);
284 fit_track_source_links.push_back(Acts::SourceLink(idx_sl));
285 }
286
287 // Reverse the order of the vectors
288 std::reverse(meas_on_track.begin(), meas_on_track.end());
289 std::reverse(fit_track_source_links.begin(), fit_track_source_links.end());
290
291 for (auto m : meas_on_track) {
292 ldmx_log(trace) << " Measurement:\n" << m << "\n";
293 }
294
295 ldmx_log(debug) << " Track bound track parameters preparation:";
296
297 // Reconstruct BoundTrackParameters at perigee (target) from stored params.
298 // perigee_ is stored in LDMX frame; rotate to ACTS frame for surface
299 // creation.
300 Acts::Vector3 perigee_acts = tracking::sim::utils::ldmx2Acts(Acts::Vector3(
301 track.getPerigeeX(), track.getPerigeeY(), track.getPerigeeZ()));
302 std::shared_ptr<Acts::PerigeeSurface> perigee =
303 Acts::Surface::makeShared<Acts::PerigeeSurface>(perigee_acts);
304
305 Acts::BoundTrackParameters trk_btp =
306 tracking::sim::utils::boundTrackParameters(track, perigee);
307
308 // GSF starting parameters: for tagger, extrapolate back to beam origin;
309 // for recoil, use target parameters directly.
310 Acts::BoundTrackParameters trk_btp_fit_start = trk_btp;
311
312 if (tagger_tracking_) {
313 auto opt_beam_origin =
314 trk_extrap_->extrapolate(trk_btp, beam_origin_surface_);
315 if (!opt_beam_origin) {
316 ldmx_log(warn) << "Failed extrapolating to beam origin for GSF start. "
317 "Skipping..";
318 continue;
319 }
320 trk_btp_fit_start = *opt_beam_origin;
321 }
322
323 ldmx_log(debug) << " Perigee surface (acts): (" << track.getPerigeeX()
324 << ", " << track.getPerigeeY() << ", "
325 << track.getPerigeeZ() << ")";
326
327 const Acts::BoundVector& trkpars = trk_btp.parameters();
328 ldmx_log(debug) << " Perigee parameters (d0, z0, phi, theta, q/p)= ("
329 << trkpars[Acts::eBoundLoc0] << ", "
330 << trkpars[Acts::eBoundLoc1] << ", "
331 << trkpars[Acts::eBoundPhi] << ", "
332 << trkpars[Acts::eBoundTheta] << ", "
333 << trkpars[Acts::eBoundQOverP] << ")";
334
335 const Acts::BoundVector& fit_start_pars = trk_btp_fit_start.parameters();
336 ldmx_log(debug) << " GSF start parameters (d0, z0, phi, theta, q/p)= ("
337 << fit_start_pars[Acts::eBoundLoc0] << ", "
338 << fit_start_pars[Acts::eBoundLoc1] << ", "
339 << fit_start_pars[Acts::eBoundPhi] << ", "
340 << fit_start_pars[Acts::eBoundTheta] << ", "
341 << fit_start_pars[Acts::eBoundQOverP] << ")";
342
343 ldmx_log(debug) << " About to run GSF fit with "
344 << fit_track_source_links.size() << " source links";
345
346 // Update GSF reference surface for this track
347 if (tagger_tracking_) {
348 gsf_ref_surface = beam_origin_surface_;
349 } else {
350 gsf_ref_surface = target_surface_;
351 }
352 gsf_options.referenceSurface = &(*gsf_ref_surface);
353
354 auto gsf_refit_result =
355 gsf_->fit(fit_track_source_links.begin(), fit_track_source_links.end(),
356 trk_btp_fit_start, gsf_options, tc);
357
358 if (!gsf_refit_result.ok()) {
359 ldmx_log(warn) << "GSF re-fit failed: "
360 << gsf_refit_result.error().message();
361 continue;
362 }
363
364 ldmx_log(debug) << " GSF fit succeeded, tc.size() = " << tc.size();
365
366 if (tc.size() < 1) continue;
367
368 auto gsftrk = tc.getTrack(0);
369 // calculateTrackQuantities(gsftrk);
370
371 const Acts::BoundVector& perigee_pars = gsftrk.parameters();
372 const Acts::BoundMatrix& trk_cov = gsftrk.covariance();
373 const Acts::Surface& perigee_surface = gsftrk.referenceSurface();
374
375 ldmx_log(debug)
376 << " Reference Surface (acts-x, acts-y, acts-z) = ("
377 << perigee_surface.transform(geometryContext()).translation()(0) << ", "
378 << perigee_surface.transform(geometryContext()).translation()(1) << ", "
379 << perigee_surface.transform(geometryContext()).translation()(2) << ")";
380
381 ldmx_log(debug) << " Found track has " << gsftrk.nTrackStates()
382 << " track states";
383
384 ldmx_log(debug) << " Track parameters (d0, z0, phi, theta, q/p)= ("
385 << perigee_pars[Acts::eBoundLoc0] << ", "
386 << perigee_pars[Acts::eBoundLoc1] << ", "
387 << perigee_pars[Acts::eBoundPhi] << ", "
388 << perigee_pars[Acts::eBoundTheta] << ", "
389 << perigee_pars[Acts::eBoundQOverP] << ") ";
390
391 ldmx::Track trk;
392
393 // Extrapolate GSF track to target surface to get perigee parameters
394 auto opt_target = trk_extrap_->extrapolate(gsftrk, target_surface_);
395
396 if (opt_target) {
397 ldmx_log(debug) << " GSF target extrapolation succeeded";
398 auto ts_at_target = tracking::sim::utils::makeTrackState(
399 geometryContext(), *opt_target, ldmx::AtTarget);
400 trk.addTrackState(ts_at_target);
401
402 trk.setPerigeeParameters(tracking::sim::utils::convertActsToLdmxPars(
403 opt_target->parameters()));
404 if (opt_target->covariance()) {
405 std::vector<double> cov_vec;
406 tracking::sim::utils::flatCov(*(opt_target->covariance()), cov_vec);
407 trk.setPerigeeCov(cov_vec);
408 }
409 Acts::Vector3 target_loc_ldmx = tracking::sim::utils::acts2Ldmx(
410 target_surface_->transform(geometryContext()).translation());
411 trk.setPerigeeLocation(target_loc_ldmx[0], target_loc_ldmx[1],
412 target_loc_ldmx[2]);
413
414 ldmx_log(debug)
415 << " GSF target parameters (d0, z0, phi, theta, q/p)= ("
416 << opt_target->parameters()[Acts::eBoundLoc0] << ", "
417 << opt_target->parameters()[Acts::eBoundLoc1] << ", "
418 << opt_target->parameters()[Acts::eBoundPhi] << ", "
419 << opt_target->parameters()[Acts::eBoundTheta] << ", "
420 << opt_target->parameters()[Acts::eBoundQOverP] << ")";
421 } else {
422 ldmx_log(debug) << " GSF target extrapolation failed, using GSF fit "
423 "parameters at reference surface";
424 trk.setPerigeeParameters(
425 tracking::sim::utils::convertActsToLdmxPars(perigee_pars));
426 std::vector<double> v_trk_cov;
427 tracking::sim::utils::flatCov(trk_cov, v_trk_cov);
428 trk.setPerigeeCov(v_trk_cov);
429 }
430
431 // Tagger: also add beam-origin state; Recoil: add ECAL state
432 if (tagger_tracking_) {
433 auto opt_beam_origin =
434 trk_extrap_->extrapolate(gsftrk, beam_origin_surface_);
435 if (opt_beam_origin)
436 trk.addTrackState(tracking::sim::utils::makeTrackState(
437 geometryContext(), *opt_beam_origin, ldmx::AtBeamOrigin));
438 } else {
439 ldmx_log(debug) << " ECAL extrapolation";
440 auto opt_ecal = trk_extrap_->extrapolate(gsftrk, ecal_surface_);
441 if (opt_ecal)
442 trk.addTrackState(tracking::sim::utils::makeTrackState(
443 geometryContext(), *opt_ecal, ldmx::AtECAL));
444 }
445
446 trk.setChi2(gsftrk.chi2());
447 trk.setNhits(gsftrk.nMeasurements());
448 trk.setNdf(gsftrk.nMeasurements() - 5);
449 trk.setCharge(perigee_pars[Acts::eBoundQOverP] > 0 ? 1 : -1);
450
451 // Truth information carried over from input track
452 trk.setTrackID(track.getTrackID());
453 trk.setPdgID(track.getPdgID());
454 trk.setTruthProb(track.getTruthProb());
455
456 itrk++;
457
458 ldmx_log(debug) << " Added track to output, total tracks = "
459 << (out_tracks.size() + 1);
460
461 out_tracks.push_back(trk);
462
463 } // loop on tracks
464
465 event.add(out_trk_collection_, out_tracks);
466} // end of produce()
467
470
471} // namespace reco
472} // namespace tracking
473
#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:105
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
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...