File indexing completed on 2025-08-05 08:18:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include "DAF.h"
0021 #include "Exception.h"
0022 #include "IO.h"
0023 #include "KalmanFitterInfo.h"
0024 #include "KalmanFitter.h"
0025 #include "KalmanFitterRefTrack.h"
0026 #include "KalmanFitStatus.h"
0027 #include "Tools.h"
0028 #include "Track.h"
0029 #include "TrackPoint.h"
0030
0031 #include <assert.h>
0032 #include <cmath>
0033
0034
0035 #include <TBuffer.h>
0036 #include <TMath.h>
0037 #include <Math/QuantFuncMathCore.h>
0038
0039
0040
0041 namespace genfit {
0042
0043 DAF::DAF(bool useRefKalman, double deltaPval, double deltaWeight)
0044 : AbsKalmanFitter(10, deltaPval), deltaWeight_(deltaWeight)
0045 {
0046 if (useRefKalman) {
0047 kalman_.reset(new KalmanFitterRefTrack());
0048 static_cast<KalmanFitterRefTrack*>(kalman_.get())->setRefitAll();
0049 }
0050 else
0051 kalman_.reset(new KalmanFitter());
0052
0053 kalman_->setMultipleMeasurementHandling(weightedAverage);
0054 kalman_->setMaxIterations(1);
0055
0056 setAnnealingScheme(100, 0.1, 5);
0057 setProbCut(0.001);
0058 }
0059
0060 DAF::DAF(AbsKalmanFitter* kalman, double deltaPval, double deltaWeight)
0061 : AbsKalmanFitter(10, deltaPval), deltaWeight_(deltaWeight)
0062 {
0063 kalman_.reset(kalman);
0064 kalman_->setMultipleMeasurementHandling(weightedAverage);
0065 kalman_->setMaxIterations(1);
0066
0067 if (dynamic_cast<KalmanFitterRefTrack*>(kalman_.get()) != nullptr) {
0068 static_cast<KalmanFitterRefTrack*>(kalman_.get())->setRefitAll();
0069 }
0070
0071 setAnnealingScheme(100, 0.1, 5);
0072 setProbCut(0.01);
0073 }
0074
0075
0076 void DAF::processTrackWithRep(Track* tr, const AbsTrackRep* rep, bool resortHits) {
0077
0078 if (debugLvl_ > 0) {
0079 debugOut<<"DAF::processTrack //////////////////////////////////////////////////////////////// \n";
0080 }
0081
0082 KalmanFitStatus* status = 0;
0083 bool oneLastIter = false;
0084
0085 double lastPval = -1;
0086
0087 for(unsigned int iBeta = 0;; ++iBeta) {
0088
0089 if (debugLvl_ > 0) {
0090 debugOut<<"DAF::processTrack, trackRep " << rep << ", iteration " << iBeta+1 << ", beta = " << betas_.at(iBeta) << "\n";
0091 }
0092
0093 kalman_->processTrackWithRep(tr, rep, resortHits);
0094
0095 status = static_cast<KalmanFitStatus*>(tr->getFitStatus(rep));
0096 status->setIsFittedWithDaf();
0097 status->setNumIterations(iBeta+1);
0098
0099
0100
0101
0102 if (! status->isFitted()){
0103 if (debugLvl_ > 0) {
0104 debugOut << "DAF::Kalman could not fit!\n";
0105 }
0106 status->setIsFitted(false);
0107 break;
0108 }
0109
0110 if( oneLastIter == true){
0111 if (debugLvl_ > 0) {
0112 debugOut << "DAF::break after one last iteration\n";
0113 }
0114 status->setIsFitConvergedFully(status->getNFailedPoints() == 0);
0115 status->setIsFitConvergedPartially();
0116 break;
0117 }
0118
0119 if(iBeta >= maxIterations_-1){
0120 status->setIsFitConvergedFully(false);
0121 status->setIsFitConvergedPartially(false);
0122 if (debugLvl_ > 0) {
0123 debugOut << "DAF::number of max iterations reached!\n";
0124 }
0125 break;
0126 }
0127
0128
0129
0130 bool converged(false);
0131 try{
0132 converged = calcWeights(tr, rep, betas_.at(iBeta));
0133 if (!converged && iBeta >= minIterations_-1 &&
0134 status->getBackwardPVal() != 0 && fabs(lastPval - status->getBackwardPVal()) < this->deltaPval_) {
0135 if (debugLvl_ > 0) {
0136 debugOut << "converged by Pval = " << status->getBackwardPVal() << " even though weights changed at iBeta = " << iBeta << std::endl;
0137 }
0138 converged = true;
0139 }
0140 lastPval = status->getBackwardPVal();
0141 } catch(Exception& e) {
0142 errorOut<<e.what();
0143 e.info();
0144
0145
0146 status->setIsFitted(false);
0147 status->setIsFitConvergedFully(false);
0148 status->setIsFitConvergedPartially(false);
0149 break;
0150 }
0151
0152
0153 if (iBeta >= minIterations_-1 && converged) {
0154 if (debugLvl_ > 0) {
0155 debugOut << "DAF::convergence reached in iteration " << iBeta+1 << " -> Do one last iteration with updated weights.\n";
0156 }
0157 oneLastIter = true;
0158 status->setIsFitConvergedFully(status->getNFailedPoints() == 0);
0159 status->setIsFitConvergedPartially();
0160 }
0161
0162 }
0163
0164
0165 if (status->getForwardPVal() == 0. &&
0166 status->getBackwardPVal() == 0.) {
0167 status->setIsFitConvergedFully(false);
0168 status->setIsFitConvergedPartially(false);
0169 }
0170
0171 }
0172
0173
0174 void DAF::setProbCut(const double prob_cut){
0175 for ( int i = 1; i < 7; ++i){
0176 addProbCut(prob_cut, i);
0177 }
0178 }
0179
0180 void DAF::addProbCut(const double prob_cut, const int measDim){
0181 if ( prob_cut > 1.0 || prob_cut < 0.0){
0182 Exception exc("DAF::addProbCut prob_cut is not between 0 and 1",__LINE__,__FILE__);
0183 exc.setFatal();
0184 throw exc;
0185 }
0186 if ( measDim < 1 || measDim > 6 ){
0187 Exception exc("DAF::addProbCut measDim must be in the range [1,6]",__LINE__,__FILE__);
0188 exc.setFatal();
0189 throw exc;
0190 }
0191 chi2Cuts_[measDim] = ROOT::Math::chisquared_quantile_c( prob_cut, measDim);
0192 }
0193
0194 void DAF::setAnnealingScheme(double bStart, double bFinal, unsigned int nSteps) {
0195
0196
0197 assert(bStart > bFinal);
0198 assert(bFinal > 1.E-10);
0199 assert(nSteps > 1);
0200
0201 minIterations_ = nSteps;
0202 maxIterations_ = nSteps + 4;
0203
0204 betas_.clear();
0205
0206 for (unsigned int i=0; i<nSteps; ++i) {
0207 betas_.push_back(bStart * pow(bFinal / bStart, i / (nSteps - 1.)));
0208 }
0209
0210 betas_.resize(maxIterations_,betas_.back());
0211
0212
0213
0214
0215 }
0216
0217
0218 bool DAF::calcWeights(Track* tr, const AbsTrackRep* rep, double beta) {
0219
0220 if (debugLvl_ > 0) {
0221 debugOut<<"DAF::calcWeights \n";
0222 }
0223
0224 bool converged(true);
0225 double maxAbsChange(0);
0226
0227 const std::vector< TrackPoint* >& trackPoints = tr->getPointsWithMeasurement();
0228 for (std::vector< TrackPoint* >::const_iterator tp = trackPoints.begin(); tp != trackPoints.end(); ++tp) {
0229 if (! (*tp)->hasFitterInfo(rep)) {
0230 continue;
0231 }
0232 AbsFitterInfo* fi = (*tp)->getFitterInfo(rep);
0233 if (dynamic_cast<KalmanFitterInfo*>(fi) == nullptr){
0234 Exception exc("DAF::getWeights ==> can only use KalmanFitterInfos",__LINE__,__FILE__);
0235 throw exc;
0236 }
0237 KalmanFitterInfo* kfi = static_cast<KalmanFitterInfo*>(fi);
0238
0239 if (kfi->areWeightsFixed()) {
0240 if (debugLvl_ > 0) {
0241 debugOut<<"weights are fixed, continue \n";
0242 }
0243 continue;
0244 }
0245
0246 unsigned int nMeas = kfi->getNumMeasurements();
0247
0248 std::vector<double> phi(nMeas, 0.);
0249 double phi_sum = 0;
0250 double phi_cut = 0;
0251 for(unsigned int j=0; j<nMeas; j++) {
0252
0253 try{
0254 const MeasurementOnPlane& residual = kfi->getResidual(j, true, true);
0255 const TVectorD& resid(residual.getState());
0256 TMatrixDSym Vinv(residual.getCov());
0257 double detV;
0258 tools::invertMatrix(Vinv, &detV);
0259 int hitDim = resid.GetNrows();
0260
0261
0262
0263 double twoPiN = 2.*M_PI;
0264 if (hitDim == 2)
0265 twoPiN *= twoPiN;
0266 else if (hitDim > 2)
0267 twoPiN = pow(twoPiN, hitDim);
0268
0269 double chi2 = Vinv.Similarity(resid);
0270 if (debugLvl_ > 1) {
0271 debugOut<<"chi2 = " << chi2 << "\n";
0272 }
0273
0274
0275 double norm = 1./sqrt(twoPiN * detV);
0276
0277 phi[j] = norm*exp(-0.5*chi2/beta);
0278 phi_sum += phi[j];
0279
0280 double cutVal = chi2Cuts_[hitDim];
0281 assert(cutVal>1.E-6);
0282
0283 phi_cut += norm*exp(-0.5*cutVal/beta);
0284 }
0285 catch(Exception& e) {
0286 errorOut << e.what();
0287 e.info();
0288 }
0289 }
0290
0291 for(unsigned int j=0; j<nMeas; j++) {
0292 double weight = phi[j]/(phi_sum+phi_cut);
0293
0294
0295
0296 double absChange(fabs(weight - kfi->getMeasurementOnPlane(j)->getWeight()));
0297 if (converged && absChange > deltaWeight_) {
0298 converged = false;
0299 if (absChange > maxAbsChange)
0300 maxAbsChange = absChange;
0301 }
0302
0303 if (debugLvl_ > 0) {
0304 if (debugLvl_ > 1 || absChange > deltaWeight_) {
0305 debugOut<<"\t old weight: " << kfi->getMeasurementOnPlane(j)->getWeight();
0306 debugOut<<"\t new weight: " << weight;
0307 }
0308 }
0309
0310 kfi->getMeasurementOnPlane(j)->setWeight(weight);
0311 }
0312 }
0313
0314 if (debugLvl_ > 0) {
0315 debugOut << "\t ";
0316 debugOut << "max abs weight change = " << maxAbsChange << "\n";
0317 }
0318
0319 return converged;
0320 }
0321
0322
0323
0324 void DAF::Streamer(TBuffer &R__b)
0325 {
0326
0327
0328
0329 typedef ::genfit::DAF thisClass;
0330 UInt_t R__s, R__c;
0331 if (R__b.IsReading()) {
0332 Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
0333
0334 typedef genfit::AbsKalmanFitter baseClass0;
0335 baseClass0::Streamer(R__b);
0336 R__b >> deltaWeight_;
0337
0338 {
0339 std::vector<double> &R__stl = betas_;
0340 R__stl.clear();
0341 int R__i, R__n;
0342 R__b >> R__n;
0343 R__stl.reserve(R__n);
0344 for (R__i = 0; R__i < R__n; R__i++) {
0345 double R__t;
0346 R__b >> R__t;
0347 R__stl.push_back(R__t);
0348 }
0349 }
0350 if (R__v == 1) {
0351
0352
0353 int R__i, R__n;
0354 R__b >> R__n;
0355 for (R__i = 0; R__i < R__n; R__i++) {
0356 memset(chi2Cuts_, 0, sizeof(chi2Cuts_));
0357 int R__t;
0358 R__b >> R__t;
0359 double R__t2;
0360 R__b >> R__t2;
0361 if (R__t >= 1 && R__t <= 6)
0362 chi2Cuts_[R__t] = R__t2;
0363 }
0364 } else {
0365 char n_chi2Cuts;
0366 R__b >> n_chi2Cuts;
0367 assert(n_chi2Cuts == 6);
0368 chi2Cuts_[0] = 0;
0369 R__b.ReadFastArray(&chi2Cuts_[1], n_chi2Cuts);
0370 }
0371 AbsKalmanFitter *p;
0372 R__b >> p;
0373 kalman_.reset(p);
0374 R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
0375 } else {
0376 R__c = R__b.WriteVersion(thisClass::IsA(), kTRUE);
0377
0378 typedef genfit::AbsKalmanFitter baseClass0;
0379 baseClass0::Streamer(R__b);
0380 R__b << deltaWeight_;
0381 {
0382 std::vector<double> &R__stl = betas_;
0383 int R__n=int(R__stl.size());
0384 R__b << R__n;
0385 if(R__n) {
0386 std::vector<double>::iterator R__k;
0387 for (R__k = R__stl.begin(); R__k != R__stl.end(); ++R__k) {
0388 R__b << (*R__k);
0389 }
0390 }
0391 }
0392 {
0393 R__b << (char)6;
0394 R__b.WriteFastArray(&chi2Cuts_[1], 6);
0395 }
0396 R__b << kalman_.get();
0397 R__b.SetByteCount(R__c, kTRUE);
0398 }
0399 }
0400
0401 }