ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CombinatorialKalmanFilterTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CombinatorialKalmanFilterTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/unit_test.hpp>
10 
11 #include <algorithm>
12 #include <cmath>
13 #include <random>
14 #include <vector>
15 
41 
42 using namespace Acts::UnitLiterals;
43 
44 namespace Acts {
45 namespace Test {
46 
48  size_t sourceID = 0;
49 
51 
52  bool operator==(const ExtendedMinimalSourceLink& rhs) const {
53  return meas == rhs.meas;
54  }
55 
56  const Surface& referenceSurface() const {
57  return *MeasurementHelpers::getSurface(*meas);
58  }
59 
61  return *meas;
62  }
63 };
64 
65 // A few initialisations and definitionas
66 using SourceLink = ExtendedMinimalSourceLink;
69 
70 using Resolution = std::pair<ParID_t, double>;
71 using ElementResolution = std::vector<Resolution>;
72 using VolumeResolution = std::map<GeometryID::Value, ElementResolution>;
73 using DetectorResolution = std::map<GeometryID::Value, VolumeResolution>;
74 
76 
77 std::normal_distribution<double> gauss(0., 1.);
78 std::default_random_engine generator(42);
79 
82 
83 bool debugMode = false;
84 
85 // Create a test context
89 
90 template <ParID_t... params>
91 using MeasurementType = Measurement<SourceLink, params...>;
92 
96 struct MeasurementCreator {
98  MeasurementCreator() = default;
99 
101  DetectorResolution detectorResolution;
102 
103  using result_type = std::vector<FittableMeasurement<SourceLink>>;
104 
112  template <typename propagator_state_t, typename stepper_t>
113  void operator()(propagator_state_t& state, const stepper_t& stepper,
114  result_type& result) const {
115  // monitor the current surface
116  auto surface = state.navigation.currentSurface;
117  if (surface and surface->associatedDetectorElement()) {
118  auto geoID = surface->geoID();
119  auto volumeID = geoID.volume();
120  auto layerID = geoID.layer();
121  // find volume and layer information for this
122  auto vResolution = detectorResolution.find(volumeID);
123  if (vResolution != detectorResolution.end()) {
124  // find layer resolutions
125  auto lResolution = vResolution->second.find(layerID);
126  if (lResolution != vResolution->second.end()) {
127  // Apply global to local
128  Acts::Vector2D lPos;
129  surface->globalToLocal(state.geoContext,
130  stepper.position(state.stepping),
131  stepper.direction(state.stepping), lPos);
132  if (lResolution->second.size() == 1) {
133  double sp = lResolution->second[0].second;
134  cov1D << sp * sp;
135  double dp = sp * gauss(generator);
136  if (lResolution->second[0].first == eLOC_0) {
137  // push back & move a LOC_0 measurement
138  MeasurementType<eLOC_0> m0(surface->getSharedPtr(), {}, cov1D,
139  lPos[eLOC_0] + dp);
140  result.push_back(std::move(m0));
141  } else {
142  // push back & move a LOC_1 measurement
143  MeasurementType<eLOC_1> m1(surface->getSharedPtr(), {}, cov1D,
144  lPos[eLOC_1] + dp);
145  result.push_back(std::move(m1));
146  }
147  } else if (lResolution->second.size() == 2) {
148  // Create the measurment and move it
149  double sx = lResolution->second[eLOC_0].second;
150  double sy = lResolution->second[eLOC_1].second;
151  cov2D << sx * sx, 0., 0., sy * sy;
152  double dx = sx * gauss(generator);
153  double dy = sy * gauss(generator);
154  // push back & move a LOC_0, LOC_1 measurement
155  MeasurementType<eLOC_0, eLOC_1> m01(surface->getSharedPtr(), {},
156  cov2D, lPos[eLOC_0] + dx,
157  lPos[eLOC_1] + dy);
158  result.push_back(std::move(m01));
159  }
160  }
161  }
162  }
163  }
164 };
165 
170 BOOST_AUTO_TEST_CASE(comb_kalman_filter_zero_field) {
171  // Build detector
173  auto detector = cGeometry();
174 
175  // Build navigator for the measurement creatoin
176  Navigator mNavigator(detector);
177  mNavigator.resolvePassive = false;
178  mNavigator.resolveMaterial = true;
179  mNavigator.resolveSensitive = true;
180 
181  // Use straingt line stepper to create the measurements
182  StraightLineStepper mStepper;
183 
184  // Define the measurement propagator
185  using MeasurementPropagator = Propagator<StraightLineStepper, Navigator>;
186 
187  // Build propagator for the measurement creation
188  MeasurementPropagator mPropagator(mStepper, mNavigator);
189 
190  // Create action list for the measurement creation
191  using MeasurementActions = ActionList<MeasurementCreator, DebugOutput>;
192  using MeasurementAborters = AbortList<EndOfWorldReached>;
193 
194  auto pixelResX = Resolution(eLOC_0, 25_um);
195  auto pixelResY = Resolution(eLOC_1, 50_um);
196  auto stripResX = Resolution(eLOC_0, 100_um);
197  auto stripResY = Resolution(eLOC_1, 150_um);
198 
199  ElementResolution pixelElementRes = {pixelResX, pixelResY};
200  ElementResolution stripElementResI = {stripResX};
201  ElementResolution stripElementResO = {stripResY};
202 
203  VolumeResolution pixelVolumeRes;
204  pixelVolumeRes[2] = pixelElementRes;
205  pixelVolumeRes[4] = pixelElementRes;
206 
207  VolumeResolution stripVolumeRes;
208  stripVolumeRes[2] = stripElementResI;
209  stripVolumeRes[4] = stripElementResO;
210  stripVolumeRes[6] = stripElementResI;
211  stripVolumeRes[8] = stripElementResO;
212 
213  DetectorResolution detRes;
214  detRes[2] = pixelVolumeRes;
215  detRes[3] = stripVolumeRes;
216 
217  // Set options for propagator
220  mOptions.debug = debugMode;
221  auto& mCreator = mOptions.actionList.get<MeasurementCreator>();
222  mCreator.detectorResolution = detRes;
223 
224  // This vector owns the measurements
225  std::multimap<size_t, FittableMeasurement<SourceLink>> measurements;
226 
227  // Make a vector of source links and further processed for KF inputs
228  std::vector<SourceLink> sourcelinks;
229 
230  // Set the starting positions for propagation
231  double eps = 15_mm;
232  std::map<size_t, Vector3D> startingPos;
233  startingPos.emplace(0, Vector3D{-3_m, 0., 0.});
234  startingPos.emplace(1, Vector3D{-3_m, -1.0 * eps, -1.0 * eps});
235  startingPos.emplace(2, Vector3D{-3_m, eps, eps});
236 
237  // Run the propagation for a few times such that multiple measurements exist
238  // on one surface
239  // Set the starting momentum for propagation
240  Vector3D mMom(1_GeV, 0., 0);
241  for (const auto& [trackID, mPos] : startingPos) {
242  SingleCurvilinearTrackParameters<NeutralPolicy> mStart(std::nullopt, mPos,
243  mMom, 42_ns);
244  // Launch and collect - the measurements
245  auto mResult = mPropagator.propagate(mStart, mOptions).value();
246  if (debugMode) {
247  const auto debugString =
248  mResult.template get<DebugOutput::result_type>().debugString;
249  std::cout << ">>>> Measurement creation: " << std::endl;
250  std::cout << debugString;
251  }
252 
253  // Extract measurements from result of propagation.
254  auto measurementsCreated =
255  std::move(mResult.template get<MeasurementCreator::result_type>());
256  for (auto& meas : measurementsCreated) {
257  measurements.emplace(trackID, std::move(meas));
258  }
259  }
260 
261  // Transform the measurments to sourcelinks
262  std::transform(measurements.begin(), measurements.end(),
263  std::back_inserter(sourcelinks), [](const auto& m) {
264  return SourceLink{m.first, &m.second};
265  });
266 
267  // There should be 18 source links in total
268  BOOST_CHECK_EQUAL(sourcelinks.size(), 18);
269 
270  // The CombinatorialKalmanFilter - we use the eigen stepper for covariance
271  // transport Build navigator for the measurement creatoin
272  Navigator rNavigator(detector);
273  rNavigator.resolvePassive = false;
274  rNavigator.resolveMaterial = true;
275  rNavigator.resolveSensitive = true;
276 
277  // Configure propagation with deactivated B-field
278  ConstantBField bField(Vector3D(0., 0., 0.));
279  using RecoStepper = EigenStepper<ConstantBField>;
280  RecoStepper rStepper(bField);
281  using RecoPropagator = Propagator<RecoStepper, Navigator>;
282  RecoPropagator rPropagator(rStepper, rNavigator);
283 
284  using Updater = GainMatrixUpdater<BoundParameters>;
285  using Smoother = GainMatrixSmoother<BoundParameters>;
286  using SourceLinkSelector = CKFSourceLinkSelector;
288  CombinatorialKalmanFilter<RecoPropagator, Updater, Smoother,
289  SourceLinkSelector>;
290 
291  using SourceLinkSelectorConfig = typename SourceLinkSelector::Config;
292  SourceLinkSelectorConfig sourcelinkSelectorConfig;
293  // Implement different chi2 criteria for different pixel (volumeID: 2)
294  // layers:
295  //-> layer 2: 8
296  //-> layer 4: 7
297  sourcelinkSelectorConfig.layerMaxChi2 = {{2, {{2, 8}, {4, 7}}}};
298  // Implement different chi2 criteria for pixel (volumeID: 2) and strip
299  // (volumeID: 3):
300  //-> pixel: 7
301  //-> strip: 8
302  sourcelinkSelectorConfig.volumeMaxChi2 = {{2, 7}, {3, 8}};
303  sourcelinkSelectorConfig.maxChi2 = 8;
304  // Set the allowed maximum number of source links to be large enough
305  sourcelinkSelectorConfig.maxNumSourcelinksOnSurface = 100;
306 
308  rPropagator,
309  getDefaultLogger("CombinatorialKalmanFilter", Logging::VERBOSE));
310 
311  // Run the CombinaltorialKamanFitter for track finding from different starting
312  // parameter
313  for (const auto& [trackID, pos] : startingPos) {
314  // Set initial parameters for the particle track
315  Covariance cov;
316  cov << pow(10_um, 2), 0., 0., 0., 0., 0., 0., pow(10_um, 2), 0., 0., 0., 0.,
317  0., 0., pow(0.0002, 2), 0., 0., 0., 0., 0., 0., pow(0.0002, 2), 0., 0.,
318  0., 0., 0., 0., 0.0001, 0., 0., 0., 0., 0., 0., 1.;
319 
320  Vector3D rPos =
321  pos + Vector3D{0, 10_um * gauss(generator), 10_um * gauss(generator)};
322  double rTheta = 0.0002 * gauss(generator);
323  double rPhi = 0.0002 * gauss(generator);
324  Vector3D rMom(1_GeV * cos(rTheta) * cos(rPhi),
325  1_GeV * cos(rTheta) * sin(rPhi), 1_GeV * sin(rTheta));
326 
327  SingleCurvilinearTrackParameters<ChargedPolicy> rStart(cov, rPos, rMom, 1.,
328  42.);
329 
330  const Surface* rSurface = &rStart.referenceSurface();
331 
333  tgContext, mfContext, calContext, sourcelinkSelectorConfig, rSurface);
334 
335  // Found the track(s)
336  auto combKalmanFilterRes = cKF.findTracks(sourcelinks, rStart, ckfOptions);
337  BOOST_CHECK(combKalmanFilterRes.ok());
338  auto foundTrack = *combKalmanFilterRes;
339  auto& fittedStates = foundTrack.fittedStates;
340  auto& trackTips = foundTrack.trackTips;
341 
342  for (const auto& tip : trackTips) {
343  std::vector<size_t> sourceIds;
344  fittedStates.visitBackwards(tip, [&](const auto& trackState) {
345  sourceIds.push_back(trackState.uncalibrated().sourceID);
346  });
347 
348  BOOST_CHECK_EQUAL(sourceIds.size(), 6);
349 
350  size_t numFakeHit = 0;
351  for (const auto& id : sourceIds) {
352  numFakeHit = numFakeHit + (id != trackID ? 1 : 0);
353  }
354 
355  // Check if there are fake hits from other tracks
356  BOOST_CHECK_EQUAL(numFakeHit, 0);
357  }
358  }
359 }
360 
361 } // namespace Test
362 } // namespace Acts