ComPWA
Common Partial-Wave-Analysis Framework
FitFractions.cpp
Go to the documentation of this file.
1 #include "FitFractions.hpp"
2 
3 #include "Core/FitResult.hpp"
4 #include "Core/Function.hpp"
5 #include "Core/Logging.hpp"
6 #include "Core/ProgressBar.hpp"
7 #include "Data/DataSet.hpp"
8 #include "Tools/Integration.hpp"
9 
10 #include <map>
11 
12 namespace ComPWA {
13 namespace Tools {
14 
15 std::ostream &operator<<(std::ostream &os, const FitFractionList &FFList) {
16  os << "\nFit Fractions:\n";
17  for (auto const &ff : FFList) {
18  os << ff.Name << ": " << ff.Value << " +- " << ff.Error << "\n";
19  }
20  return os;
21 }
22 
31  const std::vector<std::pair<IntensityComponent, IntensityComponent>>
32  &Components,
33  const ComPWA::Data::DataSet &PhspSample, const ComPWA::FitResult &Result) {
34 
36 
37  for (auto Component : Components) {
38  auto NumeratorData = getIntegralData(Component.first, PhspSample, Result);
39  auto DenominatorData =
40  getIntegralData(Component.second, PhspSample, Result);
41 
42  double FitFractionValue =
43  std::get<1>(NumeratorData) / std::get<1>(DenominatorData);
44 
45  double FitFractionError = 0.;
46  if (Result.IsValid) {
47  // FF = N/D -> calculate Jacobi matrix (because we have a single ff, this
48  // is just a vector)
49  std::vector<double> JacobiColumn;
50  std::vector<std::vector<double>> CovMatrix;
51  std::tie(JacobiColumn, CovMatrix) = buildJacobiAndCovariance(
52  std::make_tuple(std::get<1>(NumeratorData),
53  std::get<2>(NumeratorData)),
54  std::make_tuple(std::get<1>(DenominatorData),
55  std::get<2>(DenominatorData)),
56  Result);
57 
58  // calculate J^T x Cov x J
59  for (unsigned int i = 0; i < JacobiColumn.size(); ++i) {
60  for (unsigned int j = 0; j < JacobiColumn.size(); ++j) {
61  FitFractionError +=
62  Result.CovarianceMatrix[i][j] * JacobiColumn[i] * JacobiColumn[j];
63  }
64  }
65  } else {
66  LOG(INFO) << "FitFractions::"
67  "calculateFitFractionsWithCovarianceErrorPropagation() | No "
68  "valid fit result. Skip error calculation.";
69  }
70 
71  FitFractions.push_back(
72  {std::get<0>(NumeratorData) + "/" + std::get<0>(DenominatorData),
73  FitFractionValue, FitFractionError});
74  }
75 
76  // the fit fraction errors are currently the squared values, take a sqrt
77  for (auto &f : FitFractions) {
78  f.Error = std::sqrt(f.Error);
79  LOG(TRACE) << "calculateFitFractionsWithCovarianceErrorPropagation(): fit "
80  "fraction for ("
81  << f.Name << ") is " << f.Value << " +- " << f.Error;
82  }
83 
84  return FitFractions;
85 }
86 
87 std::tuple<std::vector<double>, std::vector<std::vector<double>>>
89  const std::tuple<double, std::vector<DerivativeData>> &NominatorDerivatives,
90  const std::tuple<double, std::vector<DerivativeData>>
91  &DenominatorDerivatives,
92  const ComPWA::FitResult &Result) {
93  std::vector<double> Column;
94  std::vector<size_t> ParameterPositions;
95 
96  double N = std::get<0>(NominatorDerivatives);
97  double D = std::get<0>(DenominatorDerivatives);
98 
99  auto dN = std::get<1>(NominatorDerivatives);
100  auto dD = std::get<1>(DenominatorDerivatives);
101 
102  size_t PositionCounter(0);
103  for (auto x : Result.FinalParameters) {
104  if (x.IsFixed)
105  continue;
106  auto FoundNominator =
107  std::find_if(dN.begin(), dN.end(), [&x](auto const &par) {
108  return par.ParameterName == x.Name;
109  });
110  auto FoundDenominator =
111  std::find_if(dD.begin(), dD.end(), [&x](auto const &par) {
112  return par.ParameterName == x.Name;
113  });
114  if (dN.end() != FoundNominator && dD.end() != FoundDenominator) {
115  // if both derivatives != 0
116  Column.push_back((FoundNominator->ValueAtParameterPlusEpsilon /
117  FoundDenominator->ValueAtParameterPlusEpsilon -
118  FoundNominator->ValueAtParameterMinusEpsilon /
119  FoundDenominator->ValueAtParameterMinusEpsilon) /
120  FoundNominator->StepSize);
121  } else if (dN.end() != FoundNominator) {
122  // if only nominator derivative != 0
123  Column.push_back((FoundNominator->ValueAtParameterPlusEpsilon / D -
124  FoundNominator->ValueAtParameterMinusEpsilon / D) /
125  FoundNominator->StepSize);
126  } else if (dD.end() != FoundDenominator) {
127  // if only denominator derivative != 0
128  Column.push_back((N / FoundDenominator->ValueAtParameterPlusEpsilon -
129  N / FoundDenominator->ValueAtParameterMinusEpsilon) /
130  FoundDenominator->StepSize);
131  } else {
132  ++PositionCounter;
133  continue;
134  }
135  ParameterPositions.push_back(PositionCounter);
136  ++PositionCounter;
137  }
138 
139  std::vector<std::vector<double>> SubCovarianceMatrix(
140  ParameterPositions.size(),
141  std::vector<double>(ParameterPositions.size()));
142  for (size_t i = 0; i < ParameterPositions.size(); ++i) {
143  for (size_t j = 0; j < ParameterPositions.size(); ++j) {
144  SubCovarianceMatrix[i][j] =
145  Result.CovarianceMatrix[ParameterPositions[i]][ParameterPositions[j]];
146  }
147  }
148 
149  return std::make_tuple(Column, SubCovarianceMatrix);
150 }
151 
152 std::tuple<std::string, double, std::vector<FitFractions::DerivativeData>>
154  const ComPWA::Data::DataSet &PhspSample,
155  const ComPWA::FitResult &Result) {
156  std::string Name(IntensComponent.first);
157 
158  // only calculated the integrals if they have not once before
159  auto FoundIntegrals = IntensityGradientDataMapping.find(Name);
160 
161  if (IntensityGradientDataMapping.end() == FoundIntegrals) {
162  ComPWA::initializeWithFitResult(*IntensComponent.second, Result);
163 
164  FoundIntegrals =
166  .insert({Name, calculateIntensityIntegralData(
167  *IntensComponent.second, PhspSample, Result)})
168  .first;
169  }
170  return std::tuple_cat(std::make_tuple(FoundIntegrals->first),
171  FoundIntegrals->second);
172 }
173 
174 std::tuple<double, std::vector<FitFractions::DerivativeData>>
176  ComPWA::Intensity &Intens, const ComPWA::Data::DataSet &Sample,
177  const ComPWA::FitResult &Result) {
178 
179  double Integral = ComPWA::Tools::integrate(Intens, Sample);
180 
181  std::vector<Parameter> TempParameters = Intens.getParameters();
182  std::vector<double> TempParameterValues;
183  for (auto const &x : TempParameters)
184  TempParameterValues.push_back(x.Value);
185 
186  std::vector<DerivativeData> Derivatives;
187  for (unsigned int i = 0; i < TempParameters.size(); ++i) {
188  auto found = std::find_if(Result.FinalParameters.begin(),
189  Result.FinalParameters.end(),
190  [refname = TempParameters[i].Name](
191  auto const &p) { return p.Name == refname; });
192  if (Result.FinalParameters.end() != found) {
193  if (found->IsFixed) {
194  continue;
195  }
196  double TempValue = found->Value;
197 
198  // a step size of sqrt(epsilon) * x produces small rounding errors
199  double h = std::sqrt(std::numeric_limits<double>::epsilon());
200  if (TempValue != 0.0)
201  h *= TempValue;
202 
203  DerivativeData GradientData;
204  GradientData.ParameterName = TempParameters[i].Name;
205  double up(TempValue + h);
206  TempParameterValues[i] = up;
207  Intens.updateParametersFrom(TempParameterValues);
208  GradientData.ValueAtParameterPlusEpsilon =
209  ComPWA::Tools::integrate(Intens, Sample);
210 
211  double down(TempValue - h);
212  TempParameterValues[i] = down;
213  GradientData.StepSize = up - down;
214  // if the compiler optimizes the above line with math associativity
215  // (by setting it to 2*h), then we get an additional numerical error
216  Intens.updateParametersFrom(TempParameterValues);
217  GradientData.ValueAtParameterMinusEpsilon =
218  ComPWA::Tools::integrate(Intens, Sample);
219 
220  Derivatives.push_back(GradientData);
221 
222  // reset values
223  TempParameterValues[i] = TempValue;
224  }
225  }
226  return std::make_tuple(Integral, Derivatives);
227 }
228 
229 } // namespace Tools
230 } // namespace ComPWA
std::map< std::string, std::tuple< double, std::vector< DerivativeData > > > IntensityGradientDataMapping
virtual void updateParametersFrom(const std::vector< double > &)=0
It is important to input the vector in the same length and order as defined in the getParameters() me...
std::vector< std::vector< double > > CovarianceMatrix
Definition: FitResult.hpp:29
std::tuple< std::string, double, std::vector< FitFractions::DerivativeData > > getIntegralData(IntensityComponent IntensComponent, const ComPWA::Data::DataSet &PhspSample, const ComPWA::FitResult &Result)
void initializeWithFitResult(ComPWA::Intensity &Intens, ComPWA::FitResult Result)
Definition: FitResult.cpp:166
std::tuple< double, std::vector< FitFractions::DerivativeData > > calculateIntensityIntegralData(ComPWA::Intensity &Intens, const ComPWA::Data::DataSet &PhspSample, const ComPWA::FitResult &Result)
std::vector< FitFraction > FitFractionList
FitFractionList calculateFitFractionsWithCovarianceErrorPropagation(const std::vector< std::pair< IntensityComponent, IntensityComponent >> &Components, const ComPWA::Data::DataSet &PhspSample, const ComPWA::FitResult &Result)
Calculates the fit fractions with errors via error propagation from the covariance matrix...
std::ostream & operator<<(std::ostream &os, const FitFractionList &FFList)
std::tuple< std::vector< double >, std::vector< std::vector< double > > > buildJacobiAndCovariance(const std::tuple< double, std::vector< DerivativeData >> &NominatorDerivatives, const std::tuple< double, std::vector< DerivativeData >> &DenominatorDerivatives, const ComPWA::FitResult &Result)
Data structure which resembles a general fit result.
Definition: FitResult.hpp:19
FitParameterList FinalParameters
Definition: FitResult.hpp:21
std::pair< std::string, std::shared_ptr< Intensity > > IntensityComponent
virtual std::vector< Parameter > getParameters() const =0
double integrate(ComPWA::Intensity &intensity, const ComPWA::Data::DataSet &phspsample, double phspVolume)
Definition: Integration.cpp:70
Interface template for a general Function of the form OutputType Function(InputTypes) The concept clo...
Definition: Function.hpp:24