EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MultiTrajectoryTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MultiTrajectoryTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2020 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 
18 
19 #include <iostream>
20 #include <numeric>
21 #include <random>
22 
23 using std::cout;
24 using std::endl;
25 
26 namespace Acts {
27 namespace Test {
28 
30 
34 
36  // generate arbitrary positive, definite matrix
37  Covariance rnd = Covariance::Random();
38  Covariance cov = rnd.transpose() * rnd;
39  return {Vector4D(0, 0, 1, 0), Vector3D(1, 10, 40), 1000, -1, cov};
40 }
41 
44 
48  eBoundQOverP>>
50  std::optional<Measurement<SourceLink, BoundIndices, eBoundLoc0, eBoundLoc1>>
52  std::optional<BoundTrackParameters> predicted;
53  std::optional<BoundTrackParameters> filtered;
54  std::optional<BoundTrackParameters> smoothed;
56  double chi2;
57  double pathLength;
58 };
59 
70 template <typename track_state_t>
71 auto fillTrackState(track_state_t& ts, TrackStatePropMask mask,
72  size_t dim = 3) {
73  auto plane = Surface::makeShared<PlaneSurface>(Vector3D{0., 0., 0.},
74  Vector3D{0., 0., 1.});
75 
76  std::unique_ptr<FittableMeasurement<SourceLink>> fm;
78 
79  if (dim == 3) {
80  ActsMatrixD<3, 3> mCov;
81  mCov.setRandom();
82 
83  Vector3D mPar;
84  mPar.setRandom();
86  meas{plane, {}, mCov, mPar[0], mPar[1], mPar[2]};
87 
88  fm = std::make_unique<FittableMeasurement<SourceLink>>(meas);
89 
90  SourceLink sourceLink{fm.get()};
91  pc.sourceLink = sourceLink;
92  if (ACTS_CHECK_BIT(mask, TrackStatePropMask::Uncalibrated)) {
93  ts.uncalibrated() = sourceLink;
94  }
95 
96  // "calibrate", keep original source link (stack address)
97  pc.meas3d = {meas.referenceObject().getSharedPtr(),
98  sourceLink,
99  meas.covariance(),
100  meas.parameters()[0],
101  meas.parameters()[1],
102  meas.parameters()[2]};
103  if (ACTS_CHECK_BIT(mask, TrackStatePropMask::Calibrated)) {
104  ts.setCalibrated(*pc.meas3d);
105  }
106  } else if (dim == 2) {
107  ActsMatrixD<2, 2> mCov;
108  mCov.setRandom();
109 
110  Vector2D mPar;
111  mPar.setRandom();
113  plane, {}, mCov, mPar[0], mPar[1]};
114 
115  fm = std::make_unique<FittableMeasurement<SourceLink>>(meas);
116 
117  SourceLink sourceLink{fm.get()};
118  pc.sourceLink = sourceLink;
119  if (ACTS_CHECK_BIT(mask, TrackStatePropMask::Uncalibrated)) {
120  ts.uncalibrated() = sourceLink;
121  }
122 
123  // "calibrate", keep original source link (stack address)
124  pc.meas2d = {meas.referenceObject().getSharedPtr(), sourceLink,
125  meas.covariance(), meas.parameters()[0], meas.parameters()[1]};
126  if (ACTS_CHECK_BIT(mask, TrackStatePropMask::Calibrated)) {
127  ts.setCalibrated(*pc.meas2d);
128  }
129  } else {
130  throw std::runtime_error("wrong dim");
131  }
132 
133  // add parameters
134 
135  // predicted
136  ParVec_t predPar;
137  predPar << 1, 2, M_PI / 4., M_PI / 2., 5, 0.;
138  predPar.template head<2>().setRandom();
139 
140  CovMat_t predCov;
141  predCov.setRandom();
142 
143  BoundTrackParameters pred(plane, predPar, predCov);
144  pc.predicted = pred;
145  if (ACTS_CHECK_BIT(mask, TrackStatePropMask::Predicted)) {
146  ts.predicted() = pred.parameters();
147  ts.predictedCovariance() = *pred.covariance();
148  }
149 
150  // filtered
151  ParVec_t filtPar;
152  filtPar << 6, 7, M_PI / 4., M_PI / 2., 10, 0.;
153  filtPar.template head<2>().setRandom();
154 
155  CovMat_t filtCov;
156  filtCov.setRandom();
157 
158  BoundTrackParameters filt(plane, filtPar, filtCov);
159  pc.filtered = filt;
160  if (ACTS_CHECK_BIT(mask, TrackStatePropMask::Filtered)) {
161  ts.filtered() = filt.parameters();
162  ts.filteredCovariance() = *filt.covariance();
163  }
164 
165  // smoothed
166  ParVec_t smotPar;
167  smotPar << 11, 12, M_PI / 4., M_PI / 2., 15, 0.;
168  smotPar.template head<2>().setRandom();
169 
170  CovMat_t smotCov;
171  smotCov.setRandom();
172 
173  BoundTrackParameters smot(plane, smotPar, smotCov);
174  pc.smoothed = smot;
175  if (ACTS_CHECK_BIT(mask, TrackStatePropMask::Smoothed)) {
176  ts.smoothed() = smot.parameters();
177  ts.smoothedCovariance() = *smot.covariance();
178  }
179 
180  // make jacobian
181  CovMat_t jac;
182  jac.setRandom();
183  pc.jacobian = jac;
185  ts.jacobian() = jac;
186  }
187 
188  std::random_device rd;
189  std::mt19937 gen(rd());
190  std::uniform_real_distribution<> dis(1.0, 100.0);
191  pc.chi2 = dis(gen);
192  pc.pathLength = dis(gen);
193  ts.chi2() = pc.chi2;
194  ts.pathLength() = pc.pathLength;
195 
196  return std::make_tuple(pc, std::move(fm));
197 }
198 
199 BOOST_AUTO_TEST_CASE(multitrajectory_build) {
201  TrackStatePropMask mask = TrackStatePropMask::Predicted;
202 
203  // construct trajectory w/ multiple components
204  auto i0 = t.addTrackState(mask);
205  // trajectory bifurcates here into multiple hypotheses
206  auto i1a = t.addTrackState(mask, i0);
207  auto i1b = t.addTrackState(mask, i0);
208  auto i2a = t.addTrackState(mask, i1a);
209  auto i2b = t.addTrackState(mask, i1b);
210 
211  // print each trajectory component
212  std::vector<size_t> act;
213  auto collect = [&](auto p) {
214  act.push_back(p.index());
215  BOOST_CHECK(!p.hasUncalibrated());
216  BOOST_CHECK(!p.hasCalibrated());
217  BOOST_CHECK(!p.hasFiltered());
218  BOOST_CHECK(!p.hasSmoothed());
219  BOOST_CHECK(!p.hasJacobian());
220  BOOST_CHECK(!p.hasProjector());
221  };
222 
223  std::vector<size_t> exp = {i2a, i1a, i0};
224  t.visitBackwards(i2a, collect);
225  BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(), exp.end());
226 
227  act.clear();
228  exp = {i2b, i1b, i0};
229  t.visitBackwards(i2b, collect);
230  BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(), exp.end());
231 
232  act.clear();
233  t.applyBackwards(i2b, collect);
234  BOOST_CHECK_EQUAL_COLLECTIONS(act.begin(), act.end(), exp.begin(), exp.end());
235 }
236 
237 BOOST_AUTO_TEST_CASE(visit_apply_abort) {
239  TrackStatePropMask mask = TrackStatePropMask::Predicted;
240 
241  // construct trajectory with three components
242  auto i0 = t.addTrackState(mask);
243  auto i1 = t.addTrackState(mask, i0);
244  auto i2 = t.addTrackState(mask, i1);
245 
246  size_t n = 0;
247  t.applyBackwards(i2, [&](const auto&) {
248  n++;
249  return false;
250  });
251  BOOST_CHECK_EQUAL(n, 1u);
252 
253  n = 0;
254  t.applyBackwards(i2, [&](const auto& ts) {
255  n++;
256  if (ts.index() == i1) {
257  return false;
258  }
259  return true;
260  });
261  BOOST_CHECK_EQUAL(n, 2u);
262 
263  n = 0;
264  t.applyBackwards(i2, [&](const auto&) {
265  n++;
266  return true;
267  });
268  BOOST_CHECK_EQUAL(n, 3u);
269 }
270 
271 BOOST_AUTO_TEST_CASE(trackstate_add_bitmask_operators) {
272  using PM = TrackStatePropMask;
273  auto bs1 = PM::Uncalibrated;
274 
275  BOOST_CHECK(ACTS_CHECK_BIT(bs1, PM::Uncalibrated));
276  BOOST_CHECK(!ACTS_CHECK_BIT(bs1, PM::Calibrated));
277 
278  auto bs2 = PM::Calibrated;
279 
280  BOOST_CHECK(!ACTS_CHECK_BIT(bs2, PM::Uncalibrated));
281  BOOST_CHECK(ACTS_CHECK_BIT(bs2, PM::Calibrated));
282 
283  auto bs3 = PM::Calibrated | PM::Uncalibrated;
284 
285  BOOST_CHECK(ACTS_CHECK_BIT(bs3, PM::Uncalibrated));
286  BOOST_CHECK(ACTS_CHECK_BIT(bs3, PM::Calibrated));
287 
288  BOOST_CHECK(ACTS_CHECK_BIT(PM::All, PM::Uncalibrated));
289  BOOST_CHECK(ACTS_CHECK_BIT(PM::All, PM::Calibrated));
290 
291  auto bs4 = PM::Predicted | PM::Jacobian | PM::Uncalibrated;
292  BOOST_CHECK(ACTS_CHECK_BIT(bs4, PM::Predicted));
293  BOOST_CHECK(ACTS_CHECK_BIT(bs4, PM::Uncalibrated));
294  BOOST_CHECK(ACTS_CHECK_BIT(bs4, PM::Jacobian));
295  BOOST_CHECK(!ACTS_CHECK_BIT(bs4, PM::Calibrated));
296  BOOST_CHECK(!ACTS_CHECK_BIT(bs4, PM::Filtered));
297  BOOST_CHECK(!ACTS_CHECK_BIT(bs4, PM::Smoothed));
298 
299  auto cnv = [](auto a) -> std::bitset<8> {
300  return static_cast<std::underlying_type<PM>::type>(a);
301  };
302 
303  BOOST_CHECK(cnv(PM::All).all()); // all ones
304  BOOST_CHECK(cnv(PM::None).none()); // all zeros
305 
306  // test orthogonality
307  std::array<PM, 6> values{PM::Predicted, PM::Filtered, PM::Smoothed,
308  PM::Jacobian, PM::Uncalibrated, PM::Calibrated};
309  for (size_t i = 0; i < values.size(); i++) {
310  for (size_t j = 0; j < values.size(); j++) {
311  PM a = values[i];
312  PM b = values[j];
313 
314  if (i == j) {
315  BOOST_CHECK(cnv(a & b).count() == 1);
316  } else {
317  BOOST_CHECK(cnv(a & b).none());
318  }
319  }
320  }
321 
322  BOOST_CHECK(cnv(PM::Predicted ^ PM::Filtered).count() == 2);
323  BOOST_CHECK(cnv(PM::Predicted ^ PM::Predicted).none());
324  BOOST_CHECK(~(PM::Predicted | PM::Calibrated) ==
325  (PM::All ^ PM::Predicted ^ PM::Calibrated));
326 
327  PM base = PM::None;
328  BOOST_CHECK(cnv(base) == 0);
329 
330  base &= PM::Filtered;
331  BOOST_CHECK(cnv(base) == 0);
332 
333  base |= PM::Filtered;
334  BOOST_CHECK(base == PM::Filtered);
335 
336  base |= PM::Calibrated;
337  BOOST_CHECK(base == (PM::Filtered | PM::Calibrated));
338 
339  base ^= PM::All;
340  BOOST_CHECK(base == ~(PM::Filtered | PM::Calibrated));
341 }
342 
343 BOOST_AUTO_TEST_CASE(trackstate_add_bitmask_method) {
344  using PM = TrackStatePropMask;
346 
347  auto ts = t.getTrackState(t.addTrackState(PM::All));
348  BOOST_CHECK(ts.hasPredicted());
349  BOOST_CHECK(ts.hasFiltered());
350  BOOST_CHECK(ts.hasSmoothed());
351  BOOST_CHECK(ts.hasUncalibrated());
352  BOOST_CHECK(ts.hasCalibrated());
353  BOOST_CHECK(ts.hasProjector());
354  BOOST_CHECK(ts.hasJacobian());
355 
356  ts = t.getTrackState(t.addTrackState(PM::None));
357  BOOST_CHECK(!ts.hasPredicted());
358  BOOST_CHECK(!ts.hasFiltered());
359  BOOST_CHECK(!ts.hasSmoothed());
360  BOOST_CHECK(!ts.hasUncalibrated());
361  BOOST_CHECK(!ts.hasCalibrated());
362  BOOST_CHECK(!ts.hasProjector());
363  BOOST_CHECK(!ts.hasJacobian());
364 
365  ts = t.getTrackState(t.addTrackState(PM::Predicted));
366  BOOST_CHECK(ts.hasPredicted());
367  BOOST_CHECK(!ts.hasFiltered());
368  BOOST_CHECK(!ts.hasSmoothed());
369  BOOST_CHECK(!ts.hasUncalibrated());
370  BOOST_CHECK(!ts.hasCalibrated());
371  BOOST_CHECK(!ts.hasProjector());
372  BOOST_CHECK(!ts.hasJacobian());
373 
374  ts = t.getTrackState(t.addTrackState(PM::Filtered));
375  BOOST_CHECK(!ts.hasPredicted());
376  BOOST_CHECK(ts.hasFiltered());
377  BOOST_CHECK(!ts.hasSmoothed());
378  BOOST_CHECK(!ts.hasUncalibrated());
379  BOOST_CHECK(!ts.hasCalibrated());
380  BOOST_CHECK(!ts.hasProjector());
381  BOOST_CHECK(!ts.hasJacobian());
382 
383  ts = t.getTrackState(t.addTrackState(PM::Smoothed));
384  BOOST_CHECK(!ts.hasPredicted());
385  BOOST_CHECK(!ts.hasFiltered());
386  BOOST_CHECK(ts.hasSmoothed());
387  BOOST_CHECK(!ts.hasUncalibrated());
388  BOOST_CHECK(!ts.hasCalibrated());
389  BOOST_CHECK(!ts.hasProjector());
390  BOOST_CHECK(!ts.hasJacobian());
391 
392  ts = t.getTrackState(t.addTrackState(PM::Uncalibrated));
393  BOOST_CHECK(!ts.hasPredicted());
394  BOOST_CHECK(!ts.hasFiltered());
395  BOOST_CHECK(!ts.hasSmoothed());
396  BOOST_CHECK(ts.hasUncalibrated());
397  BOOST_CHECK(!ts.hasCalibrated());
398  BOOST_CHECK(!ts.hasProjector());
399  BOOST_CHECK(!ts.hasJacobian());
400 
401  ts = t.getTrackState(t.addTrackState(PM::Calibrated));
402  BOOST_CHECK(!ts.hasPredicted());
403  BOOST_CHECK(!ts.hasFiltered());
404  BOOST_CHECK(!ts.hasSmoothed());
405  BOOST_CHECK(!ts.hasUncalibrated());
406  BOOST_CHECK(ts.hasCalibrated());
407  BOOST_CHECK(ts.hasProjector());
408  BOOST_CHECK(!ts.hasJacobian());
409 
411  BOOST_CHECK(!ts.hasPredicted());
412  BOOST_CHECK(!ts.hasFiltered());
413  BOOST_CHECK(!ts.hasSmoothed());
414  BOOST_CHECK(!ts.hasUncalibrated());
415  BOOST_CHECK(!ts.hasCalibrated());
416  BOOST_CHECK(!ts.hasProjector());
417  BOOST_CHECK(ts.hasJacobian());
418 }
419 
420 BOOST_AUTO_TEST_CASE(trackstate_proxy_cross_talk) {
421  // assert expected "cross-talk" between trackstate proxies
422 
424  size_t index = t.addTrackState();
425  auto tso = t.getTrackState(index);
426  auto [pc, fm] = fillTrackState(tso, TrackStatePropMask::All);
427 
428  const auto& ct = t;
429  auto cts = ct.getTrackState(0);
430  auto ts = t.getTrackState(0);
431 
432  // assert expected value of chi2 and path length
433  BOOST_CHECK_EQUAL(cts.chi2(), pc.chi2);
434  BOOST_CHECK_EQUAL(ts.chi2(), pc.chi2);
435  BOOST_CHECK_EQUAL(cts.pathLength(), pc.pathLength);
436  BOOST_CHECK_EQUAL(ts.pathLength(), pc.pathLength);
437 
438  ParVec_t v;
439  CovMat_t cov;
440 
441  v.setRandom();
442  ts.predicted() = v;
443  BOOST_CHECK_EQUAL(cts.predicted(), v);
444  cov.setRandom();
445  ts.predictedCovariance() = cov;
446  BOOST_CHECK_EQUAL(cts.predictedCovariance(), cov);
447 
448  v.setRandom();
449  ts.filtered() = v;
450  BOOST_CHECK_EQUAL(cts.filtered(), v);
451  cov.setRandom();
452  ts.filteredCovariance() = cov;
453  BOOST_CHECK_EQUAL(cts.filteredCovariance(), cov);
454 
455  v.setRandom();
456  ts.smoothed() = v;
457  BOOST_CHECK_EQUAL(cts.smoothed(), v);
458  cov.setRandom();
459  ts.smoothedCovariance() = cov;
460  BOOST_CHECK_EQUAL(cts.smoothedCovariance(), cov);
461 
462  // make copy of fm
463  auto fm2 = std::make_unique<FittableMeasurement<SourceLink>>(*fm);
464  SourceLink sourceLink2{fm2.get()};
465  ts.uncalibrated() = sourceLink2;
466  BOOST_CHECK_EQUAL(cts.uncalibrated(), sourceLink2);
467  BOOST_CHECK_NE(cts.uncalibrated(), SourceLink{fm.get()});
468 
469  CovMat_t newMeasCov;
470  newMeasCov.setRandom();
471  ts.calibratedCovariance() = newMeasCov;
472  BOOST_CHECK_EQUAL(cts.calibratedCovariance(), newMeasCov);
473 
474  ParVec_t newMeasPar;
475  newMeasPar.setRandom();
476  ts.calibrated() = newMeasPar;
477  BOOST_CHECK_EQUAL(cts.calibrated(), newMeasPar);
478 
479  size_t measdim = ts.effectiveCalibrated().rows();
480 
481  ActsMatrixXd eff{measdim, measdim};
482  eff.setRandom();
483  ts.effectiveCalibratedCovariance() = eff;
484  BOOST_CHECK_EQUAL(cts.effectiveCalibratedCovariance(), eff);
485  newMeasCov.topLeftCorner(eff.rows(), eff.rows()) = eff;
486  BOOST_CHECK_EQUAL(cts.calibratedCovariance(), newMeasCov);
487 
488  CovMat_t jac;
489  jac.setRandom();
490  ts.jacobian() = jac;
491  BOOST_CHECK_EQUAL(cts.jacobian(), jac);
492 
493  ts.chi2() = 98;
494  BOOST_CHECK_EQUAL(cts.chi2(), 98u);
495 
496  ts.pathLength() = 66;
497  BOOST_CHECK_EQUAL(cts.pathLength(), 66u);
498 }
499 
500 BOOST_AUTO_TEST_CASE(trackstate_reassignment) {
501  constexpr size_t maxmeasdim = MultiTrajectory<SourceLink>::MeasurementSizeMax;
502 
504  size_t index = t.addTrackState();
505  auto tso = t.getTrackState(index);
506  auto [pc, fm] = fillTrackState(tso, TrackStatePropMask::All);
507 
508  auto ts = t.getTrackState(0);
509 
510  // assert measdim and contents of original measurement (just to be safe)
511  BOOST_CHECK_EQUAL(ts.calibratedSize(), pc.meas3d->size());
512  BOOST_CHECK_EQUAL(ts.effectiveCalibrated(), pc.meas3d->parameters());
513  BOOST_CHECK_EQUAL(ts.effectiveCalibratedCovariance(),
514  pc.meas3d->covariance());
515  BOOST_CHECK_EQUAL(ts.effectiveProjector(), pc.meas3d->projector());
516 
517  // create new measurement
518  SymMatrix2D mCov;
519  mCov.setRandom();
520  Vector2D mPar;
521  mPar.setRandom();
523  pc.meas3d->referenceObject().getSharedPtr(), {}, mCov, mPar[0], mPar[1]};
524 
525  ts.setCalibrated(m2);
526 
527  BOOST_CHECK_EQUAL(ts.calibratedSize(), 2u);
528  BOOST_CHECK_EQUAL(ts.effectiveCalibrated(), mPar);
529  BOOST_CHECK_EQUAL(ts.effectiveCalibratedCovariance(), mCov);
530  BOOST_CHECK_EQUAL(ts.effectiveProjector(), m2.projector());
531 
532  // check if overallocated part is zeroed correctly
533  ActsVectorD<maxmeasdim> mParFull;
534  mParFull.setZero();
535  mParFull.head(2) = mPar;
536  BOOST_CHECK_EQUAL(ts.calibrated(), mParFull);
537 
538  BoundSymMatrix mCovFull;
539  mCovFull.setZero();
540  mCovFull.topLeftCorner(2, 2) = mCov;
541  BOOST_CHECK_EQUAL(ts.calibratedCovariance(), mCovFull);
542 
544  projFull.setZero();
545  projFull.topLeftCorner(m2.size(), eBoundSize) = m2.projector();
546  BOOST_CHECK_EQUAL(ts.projector(), projFull);
547 }
548 
549 BOOST_AUTO_TEST_CASE(storage_consistency) {
551  size_t index = t.addTrackState();
552  auto ts = t.getTrackState(index);
553  auto [pc, fm] = fillTrackState(ts, TrackStatePropMask::All);
554 
555  // now investigate the proxy
556  // parameters
557  BOOST_CHECK(ts.hasPredicted());
558  BOOST_CHECK_EQUAL(pc.predicted->parameters(), ts.predicted());
559  BOOST_CHECK_EQUAL(*pc.predicted->covariance(), ts.predictedCovariance());
560 
561  BOOST_CHECK(ts.hasFiltered());
562  BOOST_CHECK_EQUAL(pc.filtered->parameters(), ts.filtered());
563  BOOST_CHECK_EQUAL(*pc.filtered->covariance(), ts.filteredCovariance());
564 
565  BOOST_CHECK(ts.hasSmoothed());
566  BOOST_CHECK_EQUAL(pc.smoothed->parameters(), ts.smoothed());
567  BOOST_CHECK_EQUAL(*pc.smoothed->covariance(), ts.smoothedCovariance());
568 
569  BOOST_CHECK_EQUAL(&ts.referenceSurface(), &pc.sourceLink.referenceSurface());
570 
571  BOOST_CHECK(ts.hasJacobian());
572  BOOST_CHECK_EQUAL(ts.jacobian(), pc.jacobian);
573 
574  BOOST_CHECK(ts.hasProjector());
575  BOOST_CHECK_EQUAL(ts.effectiveProjector(), pc.meas3d->projector());
576  // measurement properties
577  BOOST_CHECK(ts.hasCalibrated());
578  BOOST_CHECK_EQUAL(pc.meas3d->parameters(), ts.effectiveCalibrated());
579  ParVec_t mParFull;
580  mParFull.setZero();
581  mParFull.head(pc.meas3d->size()) = pc.meas3d->parameters();
582  BOOST_CHECK_EQUAL(mParFull, ts.calibrated());
583 
584  BOOST_CHECK_EQUAL(pc.meas3d->covariance(),
585  ts.effectiveCalibratedCovariance());
586  CovMat_t mCovFull;
587  mCovFull.setZero();
588  mCovFull.topLeftCorner(pc.meas3d->size(), pc.meas3d->size()) =
589  pc.meas3d->covariance();
590  BOOST_CHECK_EQUAL(mCovFull, ts.calibratedCovariance());
591 
592  // calibrated links to original measurement
593  BOOST_CHECK_EQUAL(pc.meas3d->sourceLink(), ts.calibratedSourceLink());
594 
595  // uncalibrated **is** a SourceLink
596  BOOST_CHECK(ts.hasUncalibrated());
597  BOOST_CHECK_EQUAL(pc.meas3d->sourceLink(), ts.uncalibrated());
598 
599  // full projector, should be exactly equal
601  fullProj;
602  fullProj.setZero();
603  fullProj.topLeftCorner(pc.meas3d->size(), eBoundSize) =
604  pc.meas3d->projector();
605  BOOST_CHECK_EQUAL(ts.projector(), fullProj);
606 
607  // projector with dynamic rows
608  // should be exactly equal
609  BOOST_CHECK_EQUAL(ts.effectiveProjector(), pc.meas3d->projector());
610 }
611 
612 BOOST_AUTO_TEST_CASE(add_trackstate_allocations) {
614 
615  // this should allocate for all the components in the trackstate, plus
616  // filtered
617  size_t i = t.addTrackState(
618  TrackStatePropMask::Predicted | TrackStatePropMask::Filtered |
619  TrackStatePropMask::Uncalibrated | TrackStatePropMask::Jacobian);
620  auto tso = t.getTrackState(i);
621  fillTrackState(tso, TrackStatePropMask::Predicted);
622  fillTrackState(tso, TrackStatePropMask::Filtered);
623  fillTrackState(tso, TrackStatePropMask::Uncalibrated);
625 
626  BOOST_CHECK(tso.hasPredicted());
627  BOOST_CHECK(tso.hasFiltered());
628  BOOST_CHECK(!tso.hasSmoothed());
629  BOOST_CHECK(tso.hasUncalibrated());
630  BOOST_CHECK(!tso.hasCalibrated());
631  BOOST_CHECK(tso.hasJacobian());
632 
633  // remove some parts
634 }
635 
636 BOOST_AUTO_TEST_CASE(trackstateproxy_getmask) {
637  using PM = TrackStatePropMask;
639 
640  std::array<PM, 6> values{PM::Predicted, PM::Filtered, PM::Smoothed,
641  PM::Jacobian, PM::Uncalibrated, PM::Calibrated};
642 
643  PM all = std::accumulate(values.begin(), values.end(), PM::None,
644  [](auto a, auto b) { return a | b; });
645 
646  auto ts = mj.getTrackState(mj.addTrackState(PM::All));
647  BOOST_CHECK(ts.getMask() == all);
648 
649  ts = mj.getTrackState(mj.addTrackState(PM::Filtered | PM::Calibrated));
650  BOOST_CHECK(ts.getMask() == (PM::Filtered | PM::Calibrated));
651 
652  ts = mj.getTrackState(
653  mj.addTrackState(PM::Filtered | PM::Smoothed | PM::Predicted));
654  BOOST_CHECK(ts.getMask() == (PM::Filtered | PM::Smoothed | PM::Predicted));
655 
656  for (PM mask : values) {
657  ts = mj.getTrackState(mj.addTrackState(mask));
658  BOOST_CHECK(ts.getMask() == mask);
659  }
660 }
661 
662 BOOST_AUTO_TEST_CASE(trackstateproxy_copy) {
663  using PM = TrackStatePropMask;
665  auto mkts = [&](PM mask) { return mj.getTrackState(mj.addTrackState(mask)); };
666 
667  std::array<PM, 6> values{PM::Predicted, PM::Filtered, PM::Smoothed,
668  PM::Jacobian, PM::Uncalibrated, PM::Calibrated};
669 
670  // orthogonal ones
671 
672  for (PM a : values) {
673  for (PM b : values) {
674  auto tsa = mkts(a);
675  auto tsb = mkts(b);
676  // doesn't work
677  if (a != b) {
678  BOOST_CHECK_THROW(tsa.copyFrom(tsb), std::runtime_error);
679  BOOST_CHECK_THROW(tsb.copyFrom(tsa), std::runtime_error);
680  } else {
681  tsa.copyFrom(tsb);
682  tsb.copyFrom(tsa);
683  }
684  }
685  }
686 
687  auto ts1 = mkts(PM::Filtered | PM::Predicted); // this has both
688  ts1.filtered().setRandom();
689  ts1.filteredCovariance().setRandom();
690  ts1.predicted().setRandom();
691  ts1.predictedCovariance().setRandom();
692 
693  // ((src XOR dst) & src) == 0
694  auto ts2 = mkts(PM::Predicted);
695  ts2.predicted().setRandom();
696  ts2.predictedCovariance().setRandom();
697 
698  // they are different before
699  BOOST_CHECK(ts1.predicted() != ts2.predicted());
700  BOOST_CHECK(ts1.predictedCovariance() != ts2.predictedCovariance());
701 
702  // ts1 -> ts2 fails
703  BOOST_CHECK_THROW(ts2.copyFrom(ts1), std::runtime_error);
704  BOOST_CHECK(ts1.predicted() != ts2.predicted());
705  BOOST_CHECK(ts1.predictedCovariance() != ts2.predictedCovariance());
706 
707  // ts2 -> ts1 is ok
708  ts1.copyFrom(ts2);
709  BOOST_CHECK(ts1.predicted() == ts2.predicted());
710  BOOST_CHECK(ts1.predictedCovariance() == ts2.predictedCovariance());
711 
712  size_t i0 = mj.addTrackState();
713  size_t i1 = mj.addTrackState();
714  ts1 = mj.getTrackState(i0);
715  ts2 = mj.getTrackState(i1);
716  auto [rts1, fm1] = fillTrackState(ts1, TrackStatePropMask::All, 2);
717  auto [rts2, fm2] = fillTrackState(ts2, TrackStatePropMask::All, 3);
718 
719  auto ots1 = mkts(PM::All);
720  auto ots2 = mkts(PM::All);
721  // make full copy for later. We prove full copy works right below
722  ots1.copyFrom(ts1);
723  ots2.copyFrom(ts2);
724 
725  BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
726  BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
727  BOOST_CHECK_NE(ts1.filtered(), ts2.filtered());
728  BOOST_CHECK_NE(ts1.filteredCovariance(), ts2.filteredCovariance());
729  BOOST_CHECK_NE(ts1.smoothed(), ts2.smoothed());
730  BOOST_CHECK_NE(ts1.smoothedCovariance(), ts2.smoothedCovariance());
731 
732  BOOST_CHECK_NE(ts1.uncalibrated(), ts2.uncalibrated());
733 
734  BOOST_CHECK_NE(ts1.calibratedSourceLink(), ts2.calibratedSourceLink());
735  BOOST_CHECK_NE(ts1.calibrated(), ts2.calibrated());
736  BOOST_CHECK_NE(ts1.calibratedCovariance(), ts2.calibratedCovariance());
737  BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
738  BOOST_CHECK_NE(ts1.projector(), ts2.projector());
739 
740  BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
741  BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
742  BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
743  BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
744 
745  ts1.copyFrom(ts2);
746 
747  BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
748  BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
749  BOOST_CHECK_EQUAL(ts1.filtered(), ts2.filtered());
750  BOOST_CHECK_EQUAL(ts1.filteredCovariance(), ts2.filteredCovariance());
751  BOOST_CHECK_EQUAL(ts1.smoothed(), ts2.smoothed());
752  BOOST_CHECK_EQUAL(ts1.smoothedCovariance(), ts2.smoothedCovariance());
753 
754  BOOST_CHECK_EQUAL(ts1.uncalibrated(), ts2.uncalibrated());
755 
756  BOOST_CHECK_EQUAL(ts1.calibratedSourceLink(), ts2.calibratedSourceLink());
757  BOOST_CHECK_EQUAL(ts1.calibrated(), ts2.calibrated());
758  BOOST_CHECK_EQUAL(ts1.calibratedCovariance(), ts2.calibratedCovariance());
759  BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
760  BOOST_CHECK_EQUAL(ts1.projector(), ts2.projector());
761 
762  BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
763  BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2());
764  BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength());
765  BOOST_CHECK_EQUAL(&ts1.referenceSurface(), &ts2.referenceSurface());
766 
767  // full copy proven to work. now let's do partial copy
768  ts2 = mkts(PM::Predicted | PM::Jacobian | PM::Calibrated);
769  ts2.copyFrom(ots2, PM::Predicted | PM::Jacobian |
770  PM::Calibrated); // copy into empty ts, only copy some
771  ts1.copyFrom(ots1); // reset to original
772  // is different again
773  BOOST_CHECK_NE(ts1.predicted(), ts2.predicted());
774  BOOST_CHECK_NE(ts1.predictedCovariance(), ts2.predictedCovariance());
775 
776  BOOST_CHECK_NE(ts1.calibratedSourceLink(), ts2.calibratedSourceLink());
777  BOOST_CHECK_NE(ts1.calibrated(), ts2.calibrated());
778  BOOST_CHECK_NE(ts1.calibratedCovariance(), ts2.calibratedCovariance());
779  BOOST_CHECK_NE(ts1.calibratedSize(), ts2.calibratedSize());
780  BOOST_CHECK_NE(ts1.projector(), ts2.projector());
781 
782  BOOST_CHECK_NE(ts1.jacobian(), ts2.jacobian());
783  BOOST_CHECK_NE(ts1.chi2(), ts2.chi2());
784  BOOST_CHECK_NE(ts1.pathLength(), ts2.pathLength());
785  BOOST_CHECK_NE(&ts1.referenceSurface(), &ts2.referenceSurface());
786 
787  ts1.copyFrom(ts2);
788 
789  // some components are same now
790  BOOST_CHECK_EQUAL(ts1.predicted(), ts2.predicted());
791  BOOST_CHECK_EQUAL(ts1.predictedCovariance(), ts2.predictedCovariance());
792 
793  BOOST_CHECK_EQUAL(ts1.calibratedSourceLink(), ts2.calibratedSourceLink());
794  BOOST_CHECK_EQUAL(ts1.calibrated(), ts2.calibrated());
795  BOOST_CHECK_EQUAL(ts1.calibratedCovariance(), ts2.calibratedCovariance());
796  BOOST_CHECK_EQUAL(ts1.calibratedSize(), ts2.calibratedSize());
797  BOOST_CHECK_EQUAL(ts1.projector(), ts2.projector());
798 
799  BOOST_CHECK_EQUAL(ts1.jacobian(), ts2.jacobian());
800  BOOST_CHECK_EQUAL(ts1.chi2(), ts2.chi2()); // always copied
801  BOOST_CHECK_EQUAL(ts1.pathLength(), ts2.pathLength()); // always copied
802  BOOST_CHECK_EQUAL(&ts1.referenceSurface(),
803  &ts2.referenceSurface()); // always copied
804 }
805 
806 } // namespace Test
807 
808 } // namespace Acts