ATLAS Offline Software
MultiComponentStateCombiner.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
15 //
16 #include "CxxUtils/phihelper.h"
17 #include "CxxUtils/inline_hints.h"
19 
20 namespace {
21 
22 struct MeanAndCovariance {
23  AmgVector(5) mean;
24  AmgSymMatrix(5) covariance;
25  double sumW = 0;
26 };
27 
38 MeanAndCovariance
39 findMeanAndCovariance(const Trk::MultiComponentState& uncombinedState) {
40 
41  MeanAndCovariance toReturn;
42  toReturn.mean.setZero();
43  AmgSymMatrix(5) covariancePart1;
44  covariancePart1.setZero();
45  AmgSymMatrix(5) covariancePart2;
46  covariancePart2.setZero();
47  const double phiOfFirst = uncombinedState[0].params->parameters()[2];
48  const size_t numComponents = uncombinedState.size();
49  for (size_t i = 0; i < numComponents; ++i) {
50  const Trk::TrackParameters* trackParameters = uncombinedState[i].params.get();
51  const double weight = uncombinedState[i].weight;
52  AmgVector(5) parameters = trackParameters->parameters();
53  // Ensure that we don't have any problems with the cyclical nature of phi
54  // Use first state as reference poin
55  const double deltaPhi = phiOfFirst - parameters[2];
56  if (deltaPhi > M_PI) {
57  parameters[2] += 2 * M_PI;
58  } else if (deltaPhi < -M_PI) {
59  parameters[2] -= 2 * M_PI;
60  }
61  toReturn.sumW += weight;
62  toReturn.mean += weight * parameters;
63  // Extract local error matrix: Must make sure track parameters are
64  // measured, ie have an associated error matrix.
65  const AmgSymMatrix(5)* measuredCov = trackParameters->covariance();
66  // Calculate the combined covariance matrix
67  if (measuredCov) {
68  covariancePart1 += weight * (*measuredCov);
69  // Loop over all remaining components to find the second part of the
70  // covariance
71  for (size_t j = i + 1; j < numComponents; ++j) {
72  AmgVector(5) parameterDifference =
73  parameters - uncombinedState[j].params->parameters();
74  const double remainingWeight = uncombinedState[j].weight;
75  covariancePart2 += weight * remainingWeight * parameterDifference *
76  parameterDifference.transpose();
77 
78  } // end loop over remaining components
79  } // end clause if errors are involved
80  } // end loop over all components
81  toReturn.mean /= toReturn.sumW;
82  // Ensure that phi is between -pi and pi
83  toReturn.mean[2] = CxxUtils::wrapToPi(toReturn.mean[2]);
84  toReturn.covariance = covariancePart1 / toReturn.sumW + covariancePart2 / (toReturn.sumW * toReturn.sumW);
85  return toReturn;
86 }
87 
88 // Actual implementation method for combining
89 // a multi component state.
90 // Imoplements the mode option
91 Trk::ComponentParameters combineToSingleImpl(
92  const Trk::MultiComponentState& uncombinedState, const bool useMode) {
93 
94  if (uncombinedState.empty()) {
95  return {};
96  }
97  const Trk::TrackParameters* firstParameters = uncombinedState.front().params.get();
98 
99  if (uncombinedState.size() == 1) {
100  return {uncombinedState.front().params->uniqueClone(),
101  uncombinedState.front().weight};
102  }
103 
104  MeanAndCovariance res = findMeanAndCovariance (uncombinedState);
105 
106  const int dimension = (uncombinedState.front()).params->parameters().rows();
107  if (useMode && dimension == 5) {
108  // Calculate the mode of the q/p distribution
109  std::array<double, 10> modes =
111  // Replace res.mean with mode if qOverP mode is not 0
112  if (modes[4] != 0) {
113  res.mean[0] = modes[0];
114  res.mean[1] = modes[1];
115  res.mean[2] = modes[2];
116  res.mean[3] = modes[3];
117  res.mean[4] = modes[4];
118 
119  if (modes[5 + 0] > 0) {
120  double currentErr = sqrt((res.covariance)(0, 0));
121  currentErr = modes[5 + 0] / currentErr;
122  (res.covariance)(0, 0) = modes[5 + 0] * modes[5 + 0];
123  res.covariance.fillSymmetric(1, 0, (res.covariance)(1, 0) * currentErr);
124  res.covariance.fillSymmetric(2, 0, (res.covariance)(2, 0) * currentErr);
125  res.covariance.fillSymmetric(3, 0, (res.covariance)(3, 0) * currentErr);
126  res.covariance.fillSymmetric(4, 0, (res.covariance)(4, 0) * currentErr);
127  }
128  if (modes[5 + 1] > 0) {
129  double currentErr = sqrt((res.covariance)(1, 1));
130  currentErr = modes[5 + 1] / currentErr;
131  res.covariance.fillSymmetric(1, 0, (res.covariance)(1, 0) * currentErr);
132  (res.covariance)(1, 1) = modes[5 + 1] * modes[5 + 1];
133  res.covariance.fillSymmetric(2, 1, (res.covariance)(2, 1) * currentErr);
134  res.covariance.fillSymmetric(3, 1, (res.covariance)(3, 1) * currentErr);
135  res.covariance.fillSymmetric(4, 1, (res.covariance)(4, 1) * currentErr);
136  }
137  if (modes[5 + 2] > 0) {
138  double currentErr = sqrt((res.covariance)(2, 2));
139  currentErr = modes[5 + 2] / currentErr;
140  res.covariance.fillSymmetric(2, 0, (res.covariance)(2, 0) * currentErr);
141  res.covariance.fillSymmetric(2, 1, (res.covariance)(2, 1) * currentErr);
142  (res.covariance)(2, 2) = modes[5 + 2] * modes[5 + 2];
143  res.covariance.fillSymmetric(3, 2, (res.covariance)(3, 2) * currentErr);
144  res.covariance.fillSymmetric(4, 2, (res.covariance)(4, 2) * currentErr);
145  }
146  if (modes[5 + 3] > 0) {
147  double currentErr = sqrt((res.covariance)(3, 3));
148  currentErr = modes[5 + 3] / currentErr;
149  res.covariance.fillSymmetric(3, 0, (res.covariance)(3, 0) * currentErr);
150  res.covariance.fillSymmetric(3, 1, (res.covariance)(3, 1) * currentErr);
151  res.covariance.fillSymmetric(3, 2, (res.covariance)(3, 2) * currentErr);
152  (res.covariance)(3, 3) = modes[5 + 3] * modes[5 + 3];
153  res.covariance.fillSymmetric(4, 3, (res.covariance)(4, 3) * currentErr);
154  }
155  if (modes[5 + 4] > 0) {
156  double currentErr = sqrt((res.covariance)(4, 4));
157  currentErr = modes[5 + 4] / currentErr;
158  res.covariance.fillSymmetric(4, 0, (res.covariance)(4, 0) * currentErr);
159  res.covariance.fillSymmetric(4, 1, (res.covariance)(4, 1) * currentErr);
160  res.covariance.fillSymmetric(4, 2, (res.covariance)(4, 2) * currentErr);
161  res.covariance.fillSymmetric(4, 3, (res.covariance)(4, 3) * currentErr);
162  (res.covariance)(4, 4) = modes[5 + 4] * modes[5 + 4];
163  }
164 
165  } // modes[4]!=0
166  } // useMode && dimensions==5
167 
168  std::unique_ptr<Trk::TrackParameters> combinedTrackParameters = nullptr;
169  double const loc1 = res.mean[Trk::loc1];
170  double const loc2 = res.mean[Trk::loc2];
171  double const phi = res.mean[Trk::phi];
172  double const theta = res.mean[Trk::theta];
173  double const qoverp = res.mean[Trk::qOverP];
174  const AmgSymMatrix(5)* firstMeasuredCov = firstParameters->covariance();
175  if (firstMeasuredCov) {
176  combinedTrackParameters =
178  loc1, loc2, phi, theta, qoverp, std::move(res.covariance));
179  } else {
180  combinedTrackParameters =
182  loc1, loc2, phi, theta, qoverp, std::nullopt);
183  }
184 
185  return {std::move(combinedTrackParameters), res.sumW};
186 }
187 } // end anonymous namespace
188 
189 std::unique_ptr<Trk::TrackParameters>
191 const Trk::MultiComponentState& uncombinedState, const bool useMode) {
192  Trk::ComponentParameters combinedComponent = combineToSingleImpl(uncombinedState, useMode);
193  return std::move(combinedComponent.params);
194 }
195 
196 
197 // The following does heave use of Eigen
198 // for covariance. Avoid out-of-line calls.
200 void
202  AmgVector(5) & firstParameters,
203  double& firstWeight,
204  const AmgVector(5) & secondParameters,
205  const double secondWeight)
206 {
207  double const totalWeight = firstWeight + secondWeight;
208  double const invTotalWeight = 1.0/totalWeight;
209  double const deltaPhi = firstParameters[2] - secondParameters[2];
210  if (deltaPhi > M_PI) {
211  firstParameters[2] -= 2 * M_PI;
212  } else if (deltaPhi < -M_PI) {
213  firstParameters[2] += 2 * M_PI;
214  }
215  firstParameters =
216  (firstWeight * firstParameters + secondWeight * secondParameters) *
217  invTotalWeight;
218  // Ensure that phi is between -pi and pi
219  firstParameters[2] = CxxUtils::wrapToPi(firstParameters[2]);
220  firstWeight = totalWeight;
221 }
222 
223 // The following does heave use of Eigen
224 // for covariance. Avoid out-of-line calls.
226 void
228  const AmgVector(5) & firstParameters,
229  AmgSymMatrix(5) & firstMeasuredCov,
230  const double firstWeight,
231  const AmgVector(5) & secondParameters,
232  const AmgSymMatrix(5) & secondMeasuredCov,
233  const double secondWeight)
234 {
235  double const invTotalWeight = 1.0/(firstWeight + secondWeight);
236  AmgVector(5) parameterDifference = firstParameters - secondParameters;
237  parameterDifference[2] = CxxUtils::wrapToPi(parameterDifference[2]);
238  parameterDifference *= invTotalWeight;
239  firstMeasuredCov = (firstWeight * firstMeasuredCov + secondWeight * secondMeasuredCov) * invTotalWeight;
240  firstMeasuredCov += firstWeight * secondWeight * parameterDifference * parameterDifference.transpose();
241 }
242 
MultiComponentStateCombiner.h
mean
void mean(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
Definition: dependence.cxx:254
inline_hints.h
TrackParameters.h
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:67
Trk::ParametersBase::associatedSurface
virtual const Surface & associatedSurface() const override=0
Access to the Surface associated to the Parameters.
Trk::ParametersBase::uniqueClone
std::unique_ptr< ParametersBase< DIM, T > > uniqueClone() const
clone method for polymorphic deep copy returning unique_ptr; it is not overriden, but uses the existi...
Definition: ParametersBase.h:97
xAOD::deltaPhi
setSAddress setEtaMS setDirPhiMS setDirZMS setBarrelRadius setEndcapAlpha setEndcapRadius setInterceptInner setEtaMap setEtaBin setIsTgcFailure setDeltaPt deltaPhi
Definition: L2StandAloneMuon_v1.cxx:161
CxxUtils::wrapToPi
T wrapToPi(T phi)
Wrap angle in radians to [-pi, pi].
Definition: phihelper.h:24
theta
Scalar theta() const
theta method
Definition: AmgMatrixBasePlugin.h:75
M_PI
#define M_PI
Definition: ActiveFraction.h:11
Trk::loc2
@ loc2
generic first and second local coordinate
Definition: ParamDefs.h:35
Trk::MultiComponentStateCombiner::combineToSingle
std::unique_ptr< Trk::TrackParameters > combineToSingle(const MultiComponentState &, const bool useMode=false)
@bried Calculate combined state of many components
Definition: MultiComponentStateCombiner.cxx:190
const
bool const RAWDATA *ch2 const
Definition: LArRodBlockPhysicsV0.cxx:560
AmgSymMatrix
#define AmgSymMatrix(dim)
Definition: EventPrimitives.h:50
Trk::MultiComponentStateModeCalculator::calculateMode
std::array< double, 10 > calculateMode(const MultiComponentState &)
Method to calculate mode with MultiComponentState state as input.
Definition: MultiComponentStateModeCalculator.cxx:386
Trk::MultiComponentStateCombiner::combineCovWithWeight
void combineCovWithWeight(const AmgVector(5) &firstParameters, AmgSymMatrix(5) &firstMeasuredCov, const double firstWeight, const AmgVector(5) &secondParameters, const AmgSymMatrix(5) &secondMeasuredCov, const double secondWeight)
Combine cov matrices based on their relevant weights.
Definition: MultiComponentStateCombiner.cxx:227
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:190
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
lumiFormat.i
int i
Definition: lumiFormat.py:85
Trk::Surface::createUniqueTrackParameters
virtual ChargedTrackParametersUniquePtr createUniqueTrackParameters(double l1, double l2, double phi, double theat, double qop, std::optional< AmgSymMatrix(5)> cov=std::nullopt) const =0
Use the Surface as a ParametersBase constructor, from local parameters - charged.
ATH_FLATTEN
#define ATH_FLATTEN
Definition: inline_hints.h:52
Trk::theta
@ theta
Definition: ParamDefs.h:66
AmgVector
AmgVector(4) T2BSTrackFilterTool
Definition: T2BSTrackFilterTool.cxx:114
CxxUtils
Definition: aligned_vector.h:29
res
std::pair< std::vector< unsigned int >, bool > res
Definition: JetGroupProductTest.cxx:11
Trk::MultiComponentState
std::vector< ComponentParameters > MultiComponentState
Definition: ComponentParameters.h:27
MultiComponentStateModeCalculator.h
Trk::ParametersBase
Definition: ParametersBase.h:55
Trk
Ensure that the ATLAS eigen extensions are properly loaded.
Definition: FakeTrackBuilder.h:9
Trk::MultiComponentStateCombiner::combineParametersWithWeight
void combineParametersWithWeight(AmgVector(5) &firstParameters, double &firstWeight, const AmgVector(5) &secondParameters, const double secondWeight)
Combine parameters based on their relevant weigths.
Definition: MultiComponentStateCombiner.cxx:201
phihelper.h
Helper for azimuthal angle calculations.
Trk::ComponentParameters
Definition: ComponentParameters.h:22
Trk::qOverP
@ qOverP
perigee
Definition: ParamDefs.h:67
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:567
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
Trk::phi
@ phi
Definition: ParamDefs.h:75
PowhegControl_ttFCNC_NLO.params
params
Definition: PowhegControl_ttFCNC_NLO.py:226
Trk::loc1
@ loc1
Definition: ParamDefs.h:34
Trk::ComponentParameters::params
std::unique_ptr< Trk::TrackParameters > params
Definition: ComponentParameters.h:23