GENFIT Rev: NoNumberAvailable
Loading...
Searching...
No Matches
DAF.cc
Go to the documentation of this file.
1/* Copyright 2008-2013, Technische Universitaet Muenchen, Ludwig-Maximilians-Universität München
2 Authors: Christian Hoeppner & Sebastian Neubert & Johannes Rauch & Tobias Schlüter
3
4 This file is part of GENFIT.
5
6 GENFIT is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 GENFIT is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with GENFIT. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "DAF.h"
21#include "Exception.h"
22#include "IO.h"
23#include "KalmanFitterInfo.h"
24#include "KalmanFitter.h"
26#include "KalmanFitStatus.h"
27#include "Tools.h"
28#include "Track.h"
29#include "TrackPoint.h"
30
31#include <assert.h>
32#include <cmath>
33
34// ROOT headers
35#include <TBuffer.h>
36#include <TMath.h>
37#include <Math/QuantFuncMathCore.h>
38
39
40
41namespace genfit {
42
43DAF::DAF(const std::tuple<double, double, int>& annealingScheme, int minIter, int maxIter, int minIterForPval, bool useRefKalman, double deltaPval, double deltaWeight, double probCut)
44 : AbsKalmanFitter(10, deltaPval), minIterForPval_(minIterForPval), deltaWeight_(deltaWeight)
45{
46 if (useRefKalman) {
47 kalman_.reset(new KalmanFitterRefTrack());
48 static_cast<KalmanFitterRefTrack*>(kalman_.get())->setRefitAll();
49 }
50 else
51 kalman_.reset(new KalmanFitter());
52
53 kalman_->setMultipleMeasurementHandling(weightedAverage);
54 kalman_->setMaxIterations(1);
55
56 setAnnealingScheme(std::get<0>(annealingScheme),
57 std::get<1>(annealingScheme),
58 std::get<2>(annealingScheme),
59 minIter, maxIter); // also sets maxIterations_
60 setProbCut(probCut);
61}
62
63DAF::DAF(bool useRefKalman, double deltaPval, double deltaWeight)
64 : AbsKalmanFitter(10, deltaPval), deltaWeight_(deltaWeight)
65{
66 if (useRefKalman) {
67 kalman_.reset(new KalmanFitterRefTrack());
68 static_cast<KalmanFitterRefTrack*>(kalman_.get())->setRefitAll();
69 }
70 else
71 kalman_.reset(new KalmanFitter());
72
73 kalman_->setMultipleMeasurementHandling(weightedAverage);
74 kalman_->setMaxIterations(1);
75
76 setAnnealingScheme(100, 0.1, 5); // also sets maxIterations_
77 setProbCut(0.001);
78}
79
80DAF::DAF(AbsKalmanFitter* kalman, double deltaPval, double deltaWeight)
81 : AbsKalmanFitter(10, deltaPval), deltaWeight_(deltaWeight)
82{
83 kalman_.reset(kalman);
84 kalman_->setMultipleMeasurementHandling(weightedAverage); // DAF makes no sense otherwise
85 kalman_->setMaxIterations(1);
86
87 if (dynamic_cast<KalmanFitterRefTrack*>(kalman_.get()) != nullptr) {
88 static_cast<KalmanFitterRefTrack*>(kalman_.get())->setRefitAll();
89 }
90
91 setAnnealingScheme(100, 0.1, 5); // also sets maxIterations_
92 setProbCut(0.01);
93}
94
95
96void DAF::processTrackWithRep(Track* tr, const AbsTrackRep* rep, bool resortHits) {
97
98 if (debugLvl_ > 0) {
99 debugOut<<"DAF::processTrack //////////////////////////////////////////////////////////////// \n";
100 }
101
102 KalmanFitStatus* status = 0;
103 bool oneLastIter = false;
104
105 double lastPval = -1;
106
107 for(unsigned int iBeta = 0; /* */ ; ++iBeta) {
108
109 if (debugLvl_ > 0) {
110 debugOut<<"DAF::processTrack, trackRep " << rep << ", iteration " << iBeta+1 << ", beta = " << betas_.at(iBeta) << "\n";
111 }
112
113 kalman_->processTrackWithRep(tr, rep, resortHits);
114
115 status = static_cast<KalmanFitStatus*>(tr->getFitStatus(rep));
116 status->setIsFittedWithDaf();
117 status->setNumIterations(iBeta+1);
118
119
120 // check break conditions
121
122 if (! status->isFitted()){
123 if (debugLvl_ > 0) {
124 debugOut << "DAF::Kalman could not fit!\n";
125 }
126 status->setIsFitted(false);
127 break;
128 }
129
130 if( oneLastIter == true){
131 if (debugLvl_ > 0) {
132 debugOut << "DAF::break after one last iteration\n";
133 }
134 status->setIsFitConvergedFully(status->getNFailedPoints() == 0);
136 break;
137 }
138
139 if(iBeta >= maxIterations_ - 1){
140 status->setIsFitConvergedFully(false);
141 status->setIsFitConvergedPartially(false);
142 if (debugLvl_ > 0) {
143 debugOut << "DAF::number of max iterations reached!\n";
144 }
145 break;
146 }
147
148
149 // get and update weights
150 bool converged(false);
151 try{
152 converged = calcWeights(tr, rep, betas_.at(iBeta));
153 if (!converged && iBeta >= static_cast<unsigned int>(minIterForPval_ - 1) &&
154 status->getBackwardPVal() > 1e-10 && lastPval > 1e-10 && fabs(lastPval - status->getBackwardPVal()) < this->deltaPval_) {
155 if (debugLvl_ > 0) {
156 debugOut << "converged by Pval = " << status->getBackwardPVal() << " even though weights changed at iBeta = " << iBeta << std::endl;
157 }
158 converged = true;
159 }
160 lastPval = status->getBackwardPVal();
161 } catch(Exception& e) {
162 errorOut<<e.what();
163 e.info();
164 //errorOut << "calc weights failed" << std::endl;
165 //mini_trk->getTrackRep(0)->setStatusFlag(1);
166 status->setIsFitted(false);
167 status->setIsFitConvergedFully(false);
168 status->setIsFitConvergedPartially(false);
169 break;
170 }
171
172 // check if converged
173 if (iBeta >= minIterations_-1 && converged) {
174 if (debugLvl_ > 0) {
175 debugOut << "DAF::convergence reached in iteration " << iBeta+1 << " -> Do one last iteration with updated weights.\n";
176 }
177 oneLastIter = true;
178 status->setIsFitConvergedFully(status->getNFailedPoints() == 0);
180 }
181
182 } // end loop over betas
183
184
185 if (status->getForwardPVal() == 0. &&
186 status->getBackwardPVal() == 0.) {
187 status->setIsFitConvergedFully(false);
188 status->setIsFitConvergedPartially(false);
189 }
190
191}
192
193
194void DAF::setProbCut(const double prob_cut){
195 for ( int i = 1; i < 7; ++i){
196 addProbCut(prob_cut, i);
197 }
198}
199
200void DAF::addProbCut(const double prob_cut, const int measDim){
201 if ( prob_cut > 1.0 || prob_cut < 0.0){
202 Exception exc("DAF::addProbCut prob_cut is not between 0 and 1",__LINE__,__FILE__);
203 exc.setFatal();
204 throw exc;
205 }
206 if ( measDim < 1 || measDim > 6 ){
207 Exception exc("DAF::addProbCut measDim must be in the range [1,6]",__LINE__,__FILE__);
208 exc.setFatal();
209 throw exc;
210 }
211 chi2Cuts_[measDim] = ROOT::Math::chisquared_quantile_c( prob_cut, measDim);
212}
213
214void DAF::setAnnealingScheme(double bStart, double bFinal, unsigned int nSteps) {
215 // The betas are calculated as a geometric series that takes nSteps
216 // steps to go from bStart to bFinal.
217 assert(bStart > bFinal);
218 assert(bFinal > 1.E-10);
219 assert(nSteps > 1);
220
221 minIterations_ = nSteps;
222 maxIterations_ = nSteps + 4;
223 minIterForPval_ = nSteps;
224
225 betas_.clear();
226
227 for (unsigned int i=0; i<nSteps; ++i) {
228 betas_.push_back(bStart * pow(bFinal / bStart, i / (nSteps - 1.)));
229 }
230
231 betas_.resize(maxIterations_,betas_.back()); //make sure main loop has a maximum of 10 iterations and also make sure the last beta value is used for if more iterations are needed then the ones set by the user.
232
233}
234
235void DAF::setAnnealingScheme(double bStart, double bFinal, unsigned int nSteps, unsigned int minIter, unsigned int maxIter) {
236 // The betas are calculated as a geometric series that takes nSteps
237 // steps to go from bStart to bFinal.
238 assert(bStart > bFinal);
239 assert(bFinal > 1.E-10);
240 assert(nSteps > 1);
241
242 minIterations_ = minIter;
243 maxIterations_ = maxIter;
244
245 betas_.clear();
246
247 for (unsigned int i=0; i<nSteps; ++i) {
248 betas_.push_back(bStart * pow(bFinal / bStart, i / (nSteps - 1.)));
249 }
250
251 betas_.resize(maxIterations_,betas_.back()); //make sure main loop has a maximum of 10 iterations and also make sure the last beta value is used for if more iterations are needed then the ones set by the user.
252
253}
254
255
256bool DAF::calcWeights(Track* tr, const AbsTrackRep* rep, double beta) {
257
258 if (debugLvl_ > 0) {
259 debugOut<<"DAF::calcWeights \n";
260 }
261
262 bool converged(true);
263 double maxAbsChange(0);
264
265 const std::vector< TrackPoint* >& trackPoints = tr->getPointsWithMeasurement();
266 for (std::vector< TrackPoint* >::const_iterator tp = trackPoints.begin(); tp != trackPoints.end(); ++tp) {
267 if (! (*tp)->hasFitterInfo(rep)) {
268 continue;
269 }
270 AbsFitterInfo* fi = (*tp)->getFitterInfo(rep);
271 if (dynamic_cast<KalmanFitterInfo*>(fi) == nullptr){
272 Exception exc("DAF::getWeights ==> can only use KalmanFitterInfos",__LINE__,__FILE__);
273 throw exc;
274 }
275 KalmanFitterInfo* kfi = static_cast<KalmanFitterInfo*>(fi);
276
277 if (kfi->areWeightsFixed()) {
278 if (debugLvl_ > 0) {
279 debugOut<<"weights are fixed, continue \n";
280 }
281 continue;
282 }
283
284 unsigned int nMeas = kfi->getNumMeasurements();
285
286 std::vector<double> phi(nMeas, 0.);
287 double phi_sum = 0;
288 double phi_cut = 0;
289 for(unsigned int j=0; j<nMeas; j++) {
290
291 try{
292 const MeasurementOnPlane& residual = kfi->getResidual(j, true, true);
293 const TVectorD& resid(residual.getState());
294 TMatrixDSym Vinv(residual.getCov());
295 double detV;
296 tools::invertMatrix(Vinv, &detV); // can throw an Exception
297 int hitDim = resid.GetNrows();
298 // Needed for normalization, special cases for the two common cases,
299 // shouldn't matter, but the original code made some efforts to make
300 // this calculation faster, and it's not complex ...
301 double twoPiN = 2.*M_PI;
302 if (hitDim == 2)
303 twoPiN *= twoPiN;
304 else if (hitDim > 2)
305 twoPiN = pow(twoPiN, hitDim);
306
307 double chi2 = Vinv.Similarity(resid);
308 if (debugLvl_ > 1) {
309 debugOut<<"chi2 = " << chi2 << "\n";
310 }
311
312 // The common factor beta is eliminated.
313 double norm = 1./sqrt(twoPiN * detV);
314
315 phi[j] = norm*exp(-0.5*chi2/beta);
316 phi_sum += phi[j];
317 //errorOut << "hitDim " << hitDim << " fchi2Cuts[hitDim] " << fchi2Cuts[hitDim] << std::endl;
318 double cutVal = chi2Cuts_[hitDim];
319 assert(cutVal>1.E-6);
320 //the following assumes that in the competing hits could have different V otherwise calculation could be simplified
321 phi_cut += norm*exp(-0.5*cutVal/beta);
322 }
323 catch(Exception& e) {
324 errorOut << e.what();
325 e.info();
326 }
327 }
328
329 for(unsigned int j=0; j<nMeas; j++) {
330 double weight = phi[j]/(phi_sum+phi_cut);
331 //debugOut << phi_sum << " " << phi_cut << " " << weight << std::endl;
332
333 // check convergence
334 double absChange(fabs(weight - kfi->getMeasurementOnPlane(j)->getWeight()));
335 if (converged && absChange > deltaWeight_) {
336 converged = false;
337 if (absChange > maxAbsChange)
338 maxAbsChange = absChange;
339 }
340
341 if (debugLvl_ > 0) {
342 if (debugLvl_ > 1 || absChange > deltaWeight_) {
343 debugOut<<"\t old weight: " << kfi->getMeasurementOnPlane(j)->getWeight();
344 debugOut<<"\t new weight: " << weight;
345 }
346 }
347
348 kfi->getMeasurementOnPlane(j)->setWeight(weight);
349 }
350 }
351
352 if (debugLvl_ > 0) {
353 debugOut << "\t ";
354 debugOut << "max abs weight change = " << maxAbsChange << "\n";
355 }
356
357 return converged;
358}
359
360
361// Customized from generated Streamer.
362void DAF::Streamer(TBuffer &R__b)
363{
364 // Stream an object of class genfit::DAF.
365
366 //This works around a msvc bug and should be harmless on other platforms
367 typedef ::genfit::DAF thisClass;
368 UInt_t R__s, R__c;
369 if (R__b.IsReading()) {
370 Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
371 //This works around a msvc bug and should be harmless on other platforms
372 typedef genfit::AbsKalmanFitter baseClass0;
373 baseClass0::Streamer(R__b);
374 R__b >> deltaWeight_;
375 // weights_ are only of intermediate use -> not saved
376 {
377 std::vector<double> &R__stl = betas_;
378 R__stl.clear();
379 int R__i, R__n;
380 R__b >> R__n;
381 R__stl.reserve(R__n);
382 for (R__i = 0; R__i < R__n; R__i++) {
383 double R__t;
384 R__b >> R__t;
385 R__stl.push_back(R__t);
386 }
387 }
388 if (R__v == 1) {
389 // Old versions kept the chi2Cuts_ in a map.
390 // We ignore non-sensical dimensionalities when reading it again.
391 int R__i, R__n;
392 R__b >> R__n;
393 for (R__i = 0; R__i < R__n; R__i++) {
394 memset(chi2Cuts_, 0, sizeof(chi2Cuts_));
395 int R__t;
396 R__b >> R__t;
397 double R__t2;
398 R__b >> R__t2;
399 if (R__t >= 1 && R__t <= 6)
400 chi2Cuts_[R__t] = R__t2;
401 }
402 } else {
403 char n_chi2Cuts; // should be six
404 R__b >> n_chi2Cuts;
405 assert(n_chi2Cuts == 6); // Cannot be different as long as sanity prevails.
406 chi2Cuts_[0] = 0; // nonsensical.
407 R__b.ReadFastArray(&chi2Cuts_[1], n_chi2Cuts);
408 }
410 R__b >> p;
411 kalman_.reset(p);
412 R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
413 } else {
414 R__c = R__b.WriteVersion(thisClass::IsA(), kTRUE);
415 //This works around a msvc bug and should be harmless on other platforms
416 typedef genfit::AbsKalmanFitter baseClass0;
417 baseClass0::Streamer(R__b);
418 R__b << deltaWeight_;
419 {
420 std::vector<double> &R__stl = betas_;
421 int R__n=int(R__stl.size());
422 R__b << R__n;
423 if(R__n) {
424 std::vector<double>::iterator R__k;
425 for (R__k = R__stl.begin(); R__k != R__stl.end(); ++R__k) {
426 R__b << (*R__k);
427 }
428 }
429 }
430 {
431 R__b << (char)6; // Number of chi2Cuts_
432 R__b.WriteFastArray(&chi2Cuts_[1], 6);
433 }
434 R__b << kalman_.get();
435 R__b.SetByteCount(R__c, kTRUE);
436 }
437}
438
439} /* End of namespace genfit */
unsigned int debugLvl_
Definition AbsFitter.h:55
This class collects all information needed and produced by a specific AbsFitter and is specific to on...
Abstract base class for Kalman fitter and derived fitting algorithms.
unsigned int maxIterations_
Maximum number of iterations to attempt. Forward and backward are counted as one iteration.
unsigned int minIterations_
Minimum number of iterations to attempt. Forward and backward are counted as one iteration.
AbsKalmanFitter(unsigned int maxIterations=4, double deltaPval=1e-3, double blowUpFactor=1e3)
Abstract base class for a track representation.
Definition AbsTrackRep.h:66
Determinstic Annealing Filter (DAF) implementation.
Definition DAF.h:50
std::vector< double > betas_
Definition DAF.h:159
bool calcWeights(Track *trk, const AbsTrackRep *rep, double beta)
Calculate and set the weights for the next fitting pass. Return if convergence is met....
Definition DAF.cc:256
void setAnnealingScheme(double bStart, double bFinal, unsigned int nSteps)
Configure the annealing scheme.
Definition DAF.cc:214
void processTrackWithRep(Track *tr, const AbsTrackRep *rep, bool resortHits=false) override
Process a track using the DAF.
Definition DAF.cc:96
void addProbCut(const double prob_cut, const int measDim)
Set the probability cut for the weight calculation for the hits for a specific measurement dimensiona...
Definition DAF.cc:200
double chi2Cuts_[7]
Definition DAF.h:160
DAF(const DAF &)
double deltaWeight_
Definition DAF.h:158
int minIterForPval_
Definition DAF.h:157
std::unique_ptr< AbsKalmanFitter > kalman_
Definition DAF.h:165
void setProbCut(const double prob_cut)
Set the probability cut for the weight calculation for the hits.
Definition DAF.cc:194
Exception class for error handling in GENFIT (provides storage for diagnostic information)
Definition Exception.h:48
void setFatal(bool b=true)
Set fatal flag.
Definition Exception.h:61
virtual const char * what() const noexcept
Standard error message handling for exceptions. use like "std::cerr << e.what();".
Definition Exception.cc:52
void info()
Print information in the exception object.
Definition Exception.cc:56
int getNFailedPoints() const
Definition FitStatus.h:112
void setIsFitConvergedPartially(bool fitConverged=true)
Definition FitStatus.h:132
bool isFitted() const
Has the track been fitted?
Definition FitStatus.h:94
void setIsFitted(bool fitted=true)
Definition FitStatus.h:130
void setIsFitConvergedFully(bool fitConverged=true)
Definition FitStatus.h:131
FitStatus for use with AbsKalmanFitter implementations.
double getForwardPVal() const
void setNumIterations(unsigned int numIterations)
double getBackwardPVal() const
void setIsFittedWithDaf(bool fittedWithDaf=true)
Simple Kalman filter implementation.
Collects information needed and produced by a AbsKalmanFitter implementations and is specific to one ...
unsigned int getNumMeasurements() const
MeasurementOnPlane getResidual(unsigned int iMeasurement=0, bool biased=false, bool onlyMeasurementErrors=true) const override
Get unbiased (default) or biased residual from ith measurement.
bool areWeightsFixed() const
Are the weights fixed?
MeasurementOnPlane * getMeasurementOnPlane(int i=0) const
Kalman filter implementation with linearization around a reference track.
void setRefitAll(bool refit=true)
If true always refit all points, otherwise fit points only if reference states have changed.
const TMatrixDSym & getCov() const
Measured coordinates on a plane.
void setWeight(double weight)
const TVectorD & getState() const
Collection of TrackPoint objects, AbsTrackRep objects and FitStatus objects.
Definition Track.h:71
FitStatus * getFitStatus(const AbsTrackRep *rep=nullptr) const
Get FitStatus for a AbsTrackRep. Per default, return FitStatus for cardinalRep.
Definition Track.h:154
const std::vector< genfit::TrackPoint * > & getPointsWithMeasurement() const
Definition Track.h:113
void invertMatrix(const TMatrixDSym &mat, TMatrixDSym &inv, double *determinant=nullptr)
Invert a matrix, throwing an Exception when inversion fails. Optional calculation of determinant.
Definition Tools.cc:38
Defines for I/O streams used for error and debug printing.
std::ostream debugOut
std::ostream errorOut