diff --git a/examples/Test_Dpipi.cc b/examples/Test_Dpipi.cc index 1f3d47c..3c771be 100644 --- a/examples/Test_Dpipi.cc +++ b/examples/Test_Dpipi.cc @@ -1,398 +1,422 @@ #include using std::cout; using std::cerr; using std::endl; #include #include #include #include "TFile.h" #include "TH2.h" #include "TRandom.h" #include "TString.h" #include "TSystem.h" #include "LauDaughters.hh" #include "LauDecayTimePdf.hh" #include "LauEffModel.hh" #include "LauIsobarDynamics.hh" #include "LauMagPhaseCoeffSet.hh" #include "LauRandom.hh" #include "LauRealImagCoeffSet.hh" #include "LauTimeDepFitModel.hh" #include "LauVetoes.hh" #include "LauFlavTag.hh" #include "Lau1DHistPdf.hh" #include "Lau1DCubicSpline.hh" void usage(const TString& progName) { cerr<<"Usage:"< vector_argv{argv, argc+argv}; - enum efficiencyInputMethod {Spline, Hist}; - efficiencyInputMethod effiMethod = efficiencyInputMethod::Spline; + LauDecayTimePdf::EfficiencyMethod effiMethod = LauDecayTimePdf::EfficiencyMethod::Spline; auto histTest = std::find(std::begin(vector_argv), std::end(vector_argv), "--hist"); if(histTest != std::end(vector_argv)) { - effiMethod = efficiencyInputMethod::Hist; + effiMethod = LauDecayTimePdf::EfficiencyMethod::Binned; + vector_argv.erase(histTest); + } + histTest = std::find(std::begin(vector_argv), std::end(vector_argv), "--flat"); + if(histTest != std::end(vector_argv)) + { + effiMethod = LauDecayTimePdf::EfficiencyMethod::Flat; vector_argv.erase(histTest); } const TString dtype = vector_argv[2]; Int_t port = 0; Int_t iFit = 0; Int_t firstExpt = 0; Int_t firstExptGen = 0; Int_t nExpt = 1; Int_t nExptGen = 1; LauTimeDepFitModel::CPEigenvalue eigenvalue = LauTimeDepFitModel::CPEven; Bool_t fixPhiMix(kFALSE); Bool_t useSinCos(kTRUE); // check the command line arguments if (argc<1) { usage(vector_argv[0]); return EXIT_FAILURE; } TString command = vector_argv[1]; if (command != "gen" && command != "fit") { usage(vector_argv[0]); return EXIT_FAILURE; } if (command == "fit") { if (argc>3) { port = atoi(vector_argv[3]); if (argc>4) { iFit = atoi(vector_argv[4]); if (argc>5) { firstExpt = atoi(vector_argv[5]); if (argc>6) { nExpt = atoi(vector_argv[6]); if (argc>7) { nExptGen = atoi(vector_argv[7]); } } } } } for (firstExptGen = 0; firstExptGen<(firstExpt+nExpt); firstExptGen+=nExptGen) { } firstExptGen -= nExptGen; if ( (nExpt > nExptGen) || (nExptGen%nExpt != 0) ) { cerr<<"Error, nExpt must be a factor of nExptGen."<3) { firstExptGen = atoi(vector_argv[3]); if (argc>4) { nExptGen = atoi(vector_argv[4]); if (argc>5) { Int_t eigval = atoi(vector_argv[5]); if ( eigval == 1 ) { eigenvalue = LauTimeDepFitModel::CPOdd; } else { eigenvalue = LauTimeDepFitModel::CPEven; } } } } } cout<<"dtype "<addMassVeto( 2, 2.00776, 2.01276 ); daughtersB0bar = new LauDaughters("B0_bar", "pi+", "pi-", "D0"); daughtersB0 = new LauDaughters("B0", "pi+", "pi-", "D0_bar"); // efficiency effModelB0bar = new LauEffModel(daughtersB0bar, vetoes); effModelB0 = new LauEffModel(daughtersB0, vetoes); LauIsobarDynamics* sigModelB0bar(0); LauIsobarDynamics* sigModelB0(0); LauTimeDepFitModel* fitModel(0); std::vector params; LauFlavTag* flavTag = new LauFlavTag(); flavTag->setTrueTagVarName("trueTag"); // Use alternative tagging calibration parameters? //flavTag->useAveOmegaDeltaOmega(); TFile* etafile(0); TH1* etahist(0); Lau1DHistPdf* etahistpdf(0); //if (command == "gen"){ etafile = TFile::Open("histogram.root"); etahist = dynamic_cast(etafile->Get("htemp")); etahistpdf = new Lau1DHistPdf("eta",etahist,0.0,0.54,kTRUE,kFALSE); //} // signal dynamics sigModelB0bar = new LauIsobarDynamics(daughtersB0bar, effModelB0bar); sigModelB0bar->setIntFileName("integ_B0bar.dat"); sigModelB0bar->addResonance("D*+_2", 2, LauAbsResonance::RelBW); sigModelB0bar->addResonance("D*+_0", 2, LauAbsResonance::RelBW); sigModelB0bar->addResonance("rho0(770)", 3, LauAbsResonance::RelBW); sigModelB0bar->addResonance("f_0(980)", 3, LauAbsResonance::RelBW); sigModelB0bar->addResonance("f_2(1270)", 3, LauAbsResonance::RelBW); sigModelB0 = new LauIsobarDynamics(daughtersB0, effModelB0); sigModelB0->setIntFileName("integ_B0.dat"); sigModelB0->addResonance("D*-_2", 1, LauAbsResonance::RelBW); sigModelB0->addResonance("D*-_0", 1, LauAbsResonance::RelBW); sigModelB0->addResonance("rho0(770)", 3, LauAbsResonance::RelBW); sigModelB0->addResonance("f_0(980)", 3, LauAbsResonance::RelBW); sigModelB0->addResonance("f_2(1270)", 3, LauAbsResonance::RelBW); // fit model fitModel = new LauTimeDepFitModel(sigModelB0bar,sigModelB0,flavTag); fitModel->setASqMaxValue(1.45); std::vector coeffset; coeffset.push_back( new LauRealImagCoeffSet("D*-_2", 1.00, 0.00, kTRUE, kTRUE) ); coeffset.push_back( new LauRealImagCoeffSet("D*-_0", 0.53*TMath::Cos( 3.00), 0.53*TMath::Sin( 3.00), kFALSE, kFALSE) ); coeffset.push_back( new LauRealImagCoeffSet("rho0(770)", 1.22*TMath::Cos( 2.25), 1.22*TMath::Sin( 2.25), kFALSE, kFALSE) ); coeffset.push_back( new LauRealImagCoeffSet("f_0(980)", 0.19*TMath::Cos(-2.48), 0.19*TMath::Sin(-2.48), kFALSE, kFALSE) ); coeffset.push_back( new LauRealImagCoeffSet("f_2(1270)", 0.75*TMath::Cos( 2.97), 0.75*TMath::Sin( 2.97), kFALSE, kFALSE) ); for (std::vector::iterator iter=coeffset.begin(); iter!=coeffset.end(); ++iter) { fitModel->setAmpCoeffSet(*iter); } fitModel->setCPEigenvalue( eigenvalue ); fitModel->setPhiMix( 2.0*LauConstants::beta, fixPhiMix, useSinCos ); fitModel->setAsymmetries(0.0,kTRUE); // Tag cat fractions, dilutions and Delta dilutions flavTag->addTagger("OSTagger","tagVal_OS","mistagVal_OS", etahistpdf,0.20,0.5,1.0,0.20,0.5,1.0); flavTag->addTagger("SSTagger","tagVal_SS","mistagVal_SS", etahistpdf,0.30,0.5,1.0,0.30,0.5,1.0); // Delta t PDFs const Double_t minDt(0.0); const Double_t maxDt(20.0); const Double_t minDtErr(0.0); const Double_t maxDtErr(2.5); const Int_t nGauss(3); std::vector scale(nGauss); scale[0] = kTRUE; scale[1] = kTRUE; scale[2] = kFALSE; std::vector dtPars(10); TString mean0Name("dt_"); mean0Name += "_mean_0"; TString mean1Name("dt_"); mean1Name += "_mean_1"; TString mean2Name("dt_"); mean2Name += "_mean_2"; TString sigma0Name("dt_"); sigma0Name += "_sigma_0"; TString sigma1Name("dt_"); sigma1Name += "_sigma_1"; TString sigma2Name("dt_"); sigma2Name += "_sigma_2"; TString frac1Name("dt_"); frac1Name += "_frac_1"; TString frac2Name("dt_"); frac2Name += "_frac_2"; TString tauName("dt_"); tauName += "_tau"; TString freqName("dt_"); freqName += "_deltaM"; LauParameter * mean1 = new LauParameter(mean1Name, -1.27); LauParameter * mean2 = new LauParameter(mean2Name, 0.0); LauParameter * sigma1 = new LauParameter(sigma1Name, 3.0); LauParameter * sigma2 = new LauParameter(sigma2Name, 8.0); LauParameter * frac1 = new LauParameter(frac1Name, 0.0930); LauParameter * frac2 = new LauParameter(frac2Name, 0.0036); LauParameter * tau = new LauParameter(tauName, 1.520); LauParameter * freq = new LauParameter(freqName, 0.5064); TString mean0tagcat63Name("dt_"); mean0tagcat63Name += 63; mean0tagcat63Name += "_mean_0"; TString sigma0tagcat63Name("dt_"); sigma0tagcat63Name += 63; sigma0tagcat63Name += "_sigma_0"; LauParameter * mean0tagcat63 = new LauParameter(mean0tagcat63Name, -0.031); LauParameter * sigma0tagcat63 = new LauParameter(sigma0tagcat63Name, 0.972); //Decay time acceptance spline - same for all tag cats (though doesn't have to be) std::vector dtvals; dtvals.push_back(0.0); dtvals.push_back(1.0); dtvals.push_back(2.0); dtvals.push_back(4.0); dtvals.push_back(6.0); dtvals.push_back(8.0); dtvals.push_back(11.0); dtvals.push_back(14.0); dtvals.push_back(17.0); dtvals.push_back(20.0); std::vector effvals; effvals.push_back(0.0); effvals.push_back(0.15); effvals.push_back(0.25); effvals.push_back(0.33); effvals.push_back(0.38); effvals.push_back(0.4); effvals.push_back(0.43); effvals.push_back(0.45); effvals.push_back(0.47); effvals.push_back(0.50); //Lau1DCubicSpline* dtEffSpline = new Lau1DCubicSpline(dtvals,effvals); Lau1DCubicSpline* dtEffSpline = nullptr; TH1D* dtEffHist = nullptr; switch(effiMethod) { - case efficiencyInputMethod::Spline: - dtEffSpline = new Lau1DCubicSpline(dtvals,effvals,Lau1DCubicSpline::StandardSpline,Lau1DCubicSpline::Natural,Lau1DCubicSpline::Natural); - break; - - case efficiencyInputMethod::Hist: - const Int_t nBins = 9; - const Double_t edges[nBins + 1] = {0,1,2,4,6,8,11,14,17,20}; - const Double_t binFilling[nBins] = {0.0075,0.02,0.029,0.655,0.69,0.715,0.74,0.76,0.785}; - dtEffHist = new TH1D("dtEffHist","Histogram of efficiencies", nBins, edges); - for( Int_t i = 1 ; i <= nBins ; ++i ){ dtEffHist->SetBinContent(i, binFilling[i-1]); } - break; + case LauDecayTimePdf::EfficiencyMethod::Spline: + { + dtEffSpline = new Lau1DCubicSpline(dtvals,effvals,Lau1DCubicSpline::StandardSpline,Lau1DCubicSpline::Natural,Lau1DCubicSpline::Natural); + break; + } + + case LauDecayTimePdf::EfficiencyMethod::Binned: + { + const Int_t nBins = dtvals.size() - 1; + Double_t edges[nBins + 1]; + for(size_t i = 0; i < dtvals.size(); ++i){edges[i] = dtvals[i];} + Double_t binFilling[nBins]; + for(size_t i = 1; i < effvals.size(); ++i){binFilling[i-1] = 0.5*(effvals[i] + effvals[i-1]);} + dtEffHist = new TH1D("dtEffHist","Histogram of efficiencies", nBins, edges); + for( Int_t i = 1 ; i <= nBins ; ++i ){ dtEffHist->SetBinContent(i, binFilling[i-1]); }//Fill histogram with averages of the values of the default spline + break; + } + + case LauDecayTimePdf::EfficiencyMethod::Flat: + {break;} } dtPars[0] = mean0tagcat63; dtPars[1] = mean1->createClone(); dtPars[2] = mean2->createClone(); dtPars[3] = sigma0tagcat63; dtPars[4] = sigma1->createClone(); dtPars[5] = sigma2->createClone(); dtPars[6] = frac1->createClone(); dtPars[7] = frac2->createClone(); dtPars[8] = tau->createClone(); dtPars[9] = freq->createClone(); if (dtype=="CPEven"){ - LauDecayTimePdf * dtPdf = new LauDecayTimePdf( "deltaTAvg", "deltaTAvgErr", dtPars, minDt, maxDt, minDtErr, maxDtErr, LauDecayTimePdf::SimFitSigBd, nGauss, scale, LauDecayTimePdf::DecayTime ); + LauDecayTimePdf * dtPdf = new LauDecayTimePdf( "deltaTAvg", "deltaTAvgErr", dtPars, minDt, maxDt, minDtErr, maxDtErr, LauDecayTimePdf::SimFitSigBd, nGauss, scale, LauDecayTimePdf::DecayTime, effiMethod ); dtPdf->doSmearing(kFALSE); switch(effiMethod) { - case efficiencyInputMethod::Spline: + case LauDecayTimePdf::EfficiencyMethod::Spline: dtPdf->setEffiSpline(dtEffSpline); break; - case efficiencyInputMethod::Hist: + case LauDecayTimePdf::EfficiencyMethod::Binned: dtPdf->setEffiHist(dtEffHist); break; + + case LauDecayTimePdf::EfficiencyMethod::Flat: + break; } fitModel->setSignalDtPdf( dtPdf ); } else { - LauDecayTimePdf * dtPdf = new LauDecayTimePdf( "deltaTAvg", "deltaTAvgErr", dtPars, minDt, maxDt, minDtErr, maxDtErr, LauDecayTimePdf::SimFitNormBd, nGauss, scale, LauDecayTimePdf::DecayTime ); + LauDecayTimePdf * dtPdf = new LauDecayTimePdf( "deltaTAvg", "deltaTAvgErr", dtPars, minDt, maxDt, minDtErr, maxDtErr, LauDecayTimePdf::SimFitNormBd, nGauss, scale, LauDecayTimePdf::DecayTime, effiMethod ); dtPdf->doSmearing(kFALSE); switch(effiMethod) { - case efficiencyInputMethod::Spline: + case LauDecayTimePdf::EfficiencyMethod::Spline: dtPdf->setEffiSpline(dtEffSpline); break; - case efficiencyInputMethod::Hist: + case LauDecayTimePdf::EfficiencyMethod::Binned: dtPdf->setEffiHist(dtEffHist); break; + + case LauDecayTimePdf::EfficiencyMethod::Flat: + break; } fitModel->setSignalDtPdf( dtPdf ); } // set the number of signal events cout<<"nSigEvents = "<setNSigEvents(nSigPar); // set the number of experiments if (command == "fit") { fitModel->setNExpts(nExpt, firstExpt); } else { fitModel->setNExpts(nExptGen, firstExptGen); } fitModel->useAsymmFitErrors(kFALSE); //fitModel->useRandomInitFitPars(kTRUE); fitModel->useRandomInitFitPars(kFALSE); fitModel->doPoissonSmearing(kFALSE); fitModel->doEMLFit(kFALSE); fitModel->writeLatexTable(kFALSE); TString dataFile(""); TString treeName("fitTree"); TString rootFileName(""); TString tableFileName(""); TString fitToyFileName(""); TString splotFileName(""); if (command == "fit") { dataFile = "TEST-Dpipi_"+dtype; dataFile += "_expts"; dataFile += firstExptGen; dataFile += "-"; dataFile += firstExptGen+nExptGen-1; dataFile += "_CP"; if ( eigenvalue == LauTimeDepFitModel::CPEven ) { dataFile += "even"; } else { dataFile += "odd"; } dataFile += ".root"; rootFileName = "fits/fit"; rootFileName += iFit; rootFileName += "_expts"; rootFileName += firstExpt; rootFileName += "-"; rootFileName += firstExpt+nExpt-1; rootFileName += ".root"; tableFileName = "fitResults_"; tableFileName += iFit; tableFileName += "_expts"; tableFileName += firstExpt; tableFileName += "-"; tableFileName += firstExpt+nExpt-1; fitToyFileName = "fitToyMC_"+dtype; fitToyFileName += iFit; fitToyFileName += "_expts"; fitToyFileName += firstExpt; fitToyFileName += "-"; fitToyFileName += firstExpt+nExpt-1; fitToyFileName += ".root"; splotFileName = "splot_"; splotFileName += iFit; splotFileName += "_expts"; splotFileName += firstExpt; splotFileName += "-"; splotFileName += firstExpt+nExpt-1; splotFileName += ".root"; } else { dataFile = "TEST-Dpipi"; switch(effiMethod) { - case efficiencyInputMethod::Spline: + case LauDecayTimePdf::EfficiencyMethod::Spline: dataFile += "_Spline"; break; - case efficiencyInputMethod::Hist: + case LauDecayTimePdf::EfficiencyMethod::Binned: dataFile += "_Hist"; break; + case LauDecayTimePdf::EfficiencyMethod::Flat: + dataFile += "_Flat"; + break; } dataFile += "_"+dtype+"_expts"; dataFile += firstExptGen; dataFile += "-"; dataFile += firstExptGen+nExptGen-1; dataFile += "_CP"; if ( eigenvalue == LauTimeDepFitModel::CPEven ) { dataFile += "even"; } else { dataFile += "odd"; } dataFile += ".root"; rootFileName = "dummy.root"; tableFileName = "genResults"; } // Generate toy from the fitted parameters fitModel->compareFitData(1, fitToyFileName); // Write out per-event likelihoods and sWeights //fitModel->writeSPlotData(splotFileName, "splot", kFALSE); // Execute the generation/fit if ( command == "fit" ){ fitModel->runSlave( dataFile, treeName, rootFileName, tableFileName, "localhost", port ); } else { fitModel->run( command, dataFile, treeName, rootFileName, tableFileName ); } return EXIT_SUCCESS; } diff --git a/src/LauDecayTimePdf.cc b/src/LauDecayTimePdf.cc index 3b5b446..e68a9ad 100644 --- a/src/LauDecayTimePdf.cc +++ b/src/LauDecayTimePdf.cc @@ -1,1323 +1,1338 @@ /* Copyright 2006 University of Warwick Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /* Laura++ package authors: John Back Paul Harrison Thomas Latham */ /*! \file LauDecayTimePdf.cc \brief File containing implementation of LauDecayTimePdf class. */ #include #include using std::cout; using std::cerr; using std::endl; #include using std::complex; #include "TMath.h" #include "TRandom.h" #include "TSystem.h" #include "TH1.h" #include "RooMath.h" #include "Lau1DCubicSpline.hh" #include "Lau1DHistPdf.hh" #include "LauConstants.hh" #include "LauComplex.hh" #include "LauDecayTimePdf.hh" #include "LauFitDataTree.hh" #include "LauParameter.hh" #include "LauRandom.hh" ClassImp(LauDecayTimePdf) LauDecayTimePdf::LauDecayTimePdf(const TString& theVarName, const TString& theVarErrName, const std::vector& params, Double_t minAbscissaVal, Double_t maxAbscissaVal, Double_t minAbscissaErr, Double_t maxAbscissaErr, FuncType type, UInt_t nGauss, const std::vector& scale, const TimeMeasurementMethod method, const EfficiencyMethod effMethod) : varName_(theVarName), varErrName_(theVarErrName), param_(params), smear_(kTRUE), minAbscissa_(minAbscissaVal), maxAbscissa_(maxAbscissaVal), minAbscissaError_(minAbscissaErr), maxAbscissaError_(maxAbscissaErr), abscissaError_(0.0), abscissaErrorGenerated_(kFALSE), errorDistMPV_(0.230), // for signal 0.234, for qqbar 0.286 errorDistSigma_(0.075), // for signal 0.073, for qqbar 0.102 nGauss_(nGauss), mean_(nGauss_,0), sigma_(nGauss_,0), frac_(nGauss_-1,0), tau_(0), deltaM_(0), deltaGamma_(0), fracPrompt_(0), type_(type), method_(method), effMethod_(effMethod), scaleMeans_(scale), scaleWidths_(scale), expTerm_(0.0), cosTerm_(0.0), sinTerm_(0.0), coshTerm_(0.0), sinhTerm_(0.0), normTermExp_(0.0), normTermCosh_(0.0), normTermSinh_(0.0), errTerm_(0.0), pdfTerm_(0.0), effiTerm_(0.0), state_(Good), errHist_(nullptr), pdfHist_(nullptr), effiFun_(nullptr), effiHist_(nullptr), effiPars_(0) { this->initialise(); // Calculate the integrals of the decay time independent of the t // TODO - this is almost certainly the wrong place to do this - this->calcNorm(); + switch(effMethod) + { + case EfficiencyMethod::Binned: break; + default: + this->calcNorm(); + break; + } } LauDecayTimePdf::LauDecayTimePdf(const TString& theVarName, const TString& theVarErrName, const std::vector& params, Double_t minAbscissaVal, Double_t maxAbscissaVal, Double_t minAbscissaErr, Double_t maxAbscissaErr, FuncType type, UInt_t nGauss, const std::vector& scaleMeans, const std::vector& scaleWidths, const TimeMeasurementMethod method, const EfficiencyMethod effMethod) : varName_(theVarName), varErrName_(theVarErrName), param_(params), smear_(kTRUE), minAbscissa_(minAbscissaVal), maxAbscissa_(maxAbscissaVal), minAbscissaError_(minAbscissaErr), maxAbscissaError_(maxAbscissaErr), abscissaError_(0.0), abscissaErrorGenerated_(kFALSE), errorDistMPV_(0.230), // for signal 0.234, for qqbar 0.286 errorDistSigma_(0.075), // for signal 0.073, for qqbar 0.102 nGauss_(nGauss), mean_(nGauss_,0), sigma_(nGauss_,0), frac_(nGauss_-1,0), tau_(0), deltaM_(0), deltaGamma_(0), fracPrompt_(0), type_(type), method_(method), effMethod_(effMethod), scaleMeans_(scaleMeans), scaleWidths_(scaleWidths), expTerm_(0.0), cosTerm_(0.0), sinTerm_(0.0), coshTerm_(0.0), sinhTerm_(0.0), normTermExp_(0.0), normTermCosh_(0.0), normTermSinh_(0.0), errTerm_(0.0), pdfTerm_(0.0), effiTerm_(0.0), state_(Good), errHist_(nullptr), pdfHist_(nullptr), effiFun_(nullptr), effiHist_(nullptr), effiPars_(0) { this->initialise(); // Calculate the integrals of the decay time independent of the t // TODO - this is almost certainly the wrong place to do this - this->calcNorm(); + switch(effMethod) + { + case EfficiencyMethod::Binned: break; + default: + this->calcNorm(); + break; + } } LauDecayTimePdf::~LauDecayTimePdf() { // Destructor delete errHist_; errHist_ = nullptr; delete pdfHist_; pdfHist_ = nullptr; delete effiFun_; effiFun_ = nullptr; delete effiHist_; effiHist_ = nullptr; for( auto& par : effiPars_ ){ delete par; par = nullptr; } effiPars_.clear(); } void LauDecayTimePdf::initialise() { // The parameters are: // - the mean and the sigma (bias and spread in resolution) of the gaussian(s) // - the mean lifetime, denoted tau, of the exponential decay // - the frequency of oscillation, denoted Delta m, of the cosine and sine terms // - the decay width difference, denoted Delta Gamma, of the hyperbolic cosine and sine terms // // The next two arguments specify the range in which the PDF is defined, // and the PDF will be normalised w.r.t. these limits. // // The final three arguments define the type of Delta t PDF (Delta, Exp, ExpTrig or ExpHypTrig ), the number of gaussians // and whether or not the gaussian parameters should be scaled by the per-event errors on Delta t // First check whether the scale vector is nGauss in size if (nGauss_ != scaleMeans_.size() || nGauss_ != scaleWidths_.size()) { cerr<<"ERROR in LauDecayTimePdf::initialise : scale vector size not the same as nGauss."<Exit(EXIT_FAILURE); } if (type_ == Hist){ if (this->nParameters() != 0){ cerr<<"ERROR in LauDecayTimePdf::initialise : Hist PDF should have 0 parameters"<Exit(EXIT_FAILURE); } }else{ TString meanName("mean_"); TString sigmaName("sigma_"); TString fracName("frac_"); Bool_t foundParams(kTRUE); for (UInt_t i(0); ifindParameter(tempName); foundParams &= (mean_[i] != 0); sigma_[i] = this->findParameter(tempName2); foundParams &= (sigma_[i] != 0); if (i!=0) { frac_[i-1] = this->findParameter(tempName3); foundParams &= (frac_[i-1] != 0); } } if (type_ == Delta) { if ((this->nParameters() != (3*nGauss_-1)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : Delta type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == Exp) { tau_ = this->findParameter("tau"); foundParams &= (tau_ != 0); if ((this->nParameters() != (3*nGauss_-1+1)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : Exp type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == ExpTrig) { tau_ = this->findParameter("tau"); deltaM_ = this->findParameter("deltaM"); foundParams &= (tau_ != 0); foundParams &= (deltaM_ != 0); if ((this->nParameters() != (3*nGauss_-1+2)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : ExpTrig type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == ExpHypTrig) { tau_ = this->findParameter("tau"); deltaM_ = this->findParameter("deltaM"); deltaGamma_ = this->findParameter("deltaGamma"); foundParams &= (tau_ != 0); foundParams &= (deltaM_ != 0); foundParams &= (deltaGamma_ != 0); if ((this->nParameters() != (3*nGauss_-1+3)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : ExpHypTrig type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == DeltaExp) { tau_ = this->findParameter("tau"); fracPrompt_ = this->findParameter("frac_prompt"); foundParams &= (tau_ != 0); foundParams &= (fracPrompt_ != 0); if ((this->nParameters() != (3*nGauss_-1+2)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : DeltaExp type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == SimFitNormBd) { tau_ = this->findParameter("tau"); deltaM_ = this->findParameter("deltaM"); foundParams &= (tau_ != 0); foundParams &= (deltaM_ != 0); if ((this->nParameters() != (3*nGauss_-1+2)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : SimFitNormBd type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == SimFitSigBd) { tau_ = this->findParameter("tau"); deltaM_ = this->findParameter("deltaM"); foundParams &= (tau_ != 0); foundParams &= (deltaM_ != 0); if ((this->nParameters() != (3*nGauss_-1+2)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : SimFitSigBd type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == SimFitNormBs) { tau_ = this->findParameter("tau"); deltaM_ = this->findParameter("deltaM"); deltaGamma_ = this->findParameter("deltaGamma"); foundParams &= (tau_ != 0); foundParams &= (deltaM_ != 0); foundParams &= (deltaGamma_ != 0); if ((this->nParameters() != (3*nGauss_-1+3)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : SimFitNormBs type PDF requires:"<Exit(EXIT_FAILURE); } } else if (type_ == SimFitSigBs) { tau_ = this->findParameter("tau"); deltaM_ = this->findParameter("deltaM"); deltaGamma_ = this->findParameter("deltaGamma"); foundParams &= (tau_ != 0); foundParams &= (deltaM_ != 0); foundParams &= (deltaGamma_ != 0); if ((this->nParameters() != (3*nGauss_-1+3)) || (!foundParams)) { cerr<<"ERROR in LauDecayTimePdf::initialise : SimFitSigBs type PDF requires:"<Exit(EXIT_FAILURE); } } } // Cache the normalisation factor //this->calcNorm(); } void LauDecayTimePdf::cacheInfo(const LauFitDataTree& inputData) { Bool_t hasBranch = inputData.haveBranch(this->varName()); if (!hasBranch) { cerr<<"ERROR in LauDecayTimePdf::cacheInfo : Input data does not contain variable \""<varName()<<"\"."<varErrName()); if (!hasBranch) { cerr<<"ERROR in LauDecayTimePdf::cacheInfo : Input data does not contain variable \""<varErrName()<<"\"."<cacheInfo(inputData); } if (type_ == Hist){ // Pass the data to the decay-time PDF for caching if ( pdfHist_ ) { pdfHist_->cacheInfo(inputData); } }else{ // determine whether we are caching our PDF value //TODO //Bool_t doCaching( this->nFixedParameters() == this->nParameters() ); //this->cachePDF( doCaching ); // clear the vectors and reserve enough space const UInt_t nEvents = inputData.nEvents(); abscissas_.clear(); abscissas_.reserve(nEvents); abscissaErrors_.clear(); abscissaErrors_.reserve(nEvents); expTerms_.clear(); expTerms_.reserve(nEvents); cosTerms_.clear(); cosTerms_.reserve(nEvents); sinTerms_.clear(); sinTerms_.reserve(nEvents); coshTerms_.clear(); coshTerms_.reserve(nEvents); sinhTerms_.clear(); sinhTerms_.reserve(nEvents); normTermsExp_.clear(); normTermsExp_.reserve(nEvents); normTermsCosh_.clear(); normTermsCosh_.reserve(nEvents); normTermsSinh_.clear(); normTermsSinh_.reserve(nEvents); effiTerms_.clear(); effiTerms_.reserve(nEvents); for (UInt_t iEvt = 0; iEvt < nEvents; iEvt++) { const LauFitData& dataValues = inputData.getData(iEvt); LauFitData::const_iterator iter = dataValues.find(this->varName()); const Double_t abscissa = iter->second; if (abscissa > this->maxAbscissa() || abscissa < this->minAbscissa()) { cerr<<"ERROR in LauDecayTimePdf::cacheInfo : Given value of the decay time: "<minAbscissa()<<","<maxAbscissa()<<"]."<Exit(EXIT_FAILURE); } abscissas_.push_back( abscissa ); iter = dataValues.find(this->varErrName()); Double_t abscissaErr = iter->second; if (abscissaErr > this->maxAbscissaError() || abscissaErr < this->minAbscissaError()) { cerr<<"ERROR in LauDecayTimePdf::cacheInfo : Given value of the decay-time error: "<minAbscissaError()<<","<maxAbscissaError()<<"]."<Exit(EXIT_FAILURE); } abscissaErrors_.push_back(abscissaErr); this->calcLikelihoodInfo(abscissa, abscissaErr); expTerms_.push_back(expTerm_); cosTerms_.push_back(cosTerm_); sinTerms_.push_back(sinTerm_); coshTerms_.push_back(coshTerm_); sinhTerms_.push_back(sinhTerm_); normTermsExp_.push_back(normTermExp_); normTermsCosh_.push_back(normTermCosh_); normTermsSinh_.push_back(normTermSinh_); effiTerms_.push_back(effiTerm_); } } } void LauDecayTimePdf::calcLikelihoodInfo(UInt_t iEvt) { if (type_ == Hist){ if ( pdfHist_ ) { pdfHist_->calcLikelihoodInfo(iEvt); pdfTerm_ = pdfHist_->getLikelihood(); } else { pdfTerm_ = 1.0; } }else{ expTerm_ = expTerms_[iEvt]; cosTerm_ = cosTerms_[iEvt]; sinTerm_ = sinTerms_[iEvt]; coshTerm_ = coshTerms_[iEvt]; sinhTerm_ = sinhTerms_[iEvt]; normTermExp_ = normTermsExp_[iEvt]; normTermCosh_ = normTermsCosh_[iEvt]; normTermSinh_ = normTermsSinh_[iEvt]; } if ( errHist_ ) { errHist_->calcLikelihoodInfo(iEvt); errTerm_ = errHist_->getLikelihood(); } else { errTerm_ = 1.0; } const Double_t abscissa = abscissas_[iEvt]; //Parameters will change in some cases update things! if (type_ == SimFitNormBd || type_ == SimFitSigBd || type_ == SimFitNormBs || type_ == SimFitSigBs){ const Double_t abscissaErr = abscissaErrors_[iEvt]; this->calcLikelihoodInfo(abscissa,abscissaErr); } switch( effMethod_ ) /* < If you're going to add an effMethod, extend this switch*/ { case EfficiencyMethod::Spline : if ( effiFun_ ) { this->updateEffiSpline(effiPars_); effiTerm_ = effiFun_->evaluate(abscissa); //EDITED XXX if (effiTerm_>1.0){effiTerm_=1.0;} if (effiTerm_<0.0){effiTerm_=0.0;} } else { effiTerm_ = 1.0; } break; default : effiTerm_ = effiTerms_[iEvt]; break; } // TODO need a check in here that none of the floating parameter values have changed // If they have, then we need to recalculate all or some of the terms /* if ( parsChanged ) { const Double_t abscissa = abscissas_[iEvt][0]; const Double_t abscissaErr = abscissaErrors_[iEvt]; this->calcLikelihoodInfo(abscissa, abscissaErr); } */ } void LauDecayTimePdf::calcLikelihoodInfo(Double_t abscissa) { // Check whether any of the gaussians should be scaled - if any of them should we need the per-event error Bool_t scale(kFALSE); for (std::vector::const_iterator iter = scaleMeans_.begin(); iter != scaleMeans_.end(); ++iter) { scale |= (*iter); } for (std::vector::const_iterator iter = scaleWidths_.begin(); iter != scaleWidths_.end(); ++iter) { scale |= (*iter); } if (scale) { cerr<<"ERROR in LauDecayTimePdf::calcLikelihoodInfo : Per-event error on Delta t not provided, cannot calculate anything."<calcLikelihoodInfo(abscissa, 0.0); } } void LauDecayTimePdf::calcLikelihoodInfo(Double_t abscissa, Double_t abscissaErr) { if (abscissa > this->maxAbscissa() || abscissa < this->minAbscissa()) { cerr<<"ERROR in LauDecayTimePdf::calcLikelihoodInfo : Given value of the decay time: "<minAbscissa()<<","<maxAbscissa()<<"]."<Exit(EXIT_FAILURE); } if (abscissaErr > this->maxAbscissaError() || abscissaErr < this->minAbscissaError()) { cerr<<"ERROR in LauDecayTimePdf::calcLikelihoodInfo : Given value of Delta t error: "<minAbscissaError()<<","<maxAbscissaError()<<"]."<Exit(EXIT_FAILURE); } switch( effMethod_ ) { case EfficiencyMethod::Spline : effiTerm_ = effiFun_ ? effiFun_ -> evaluate(abscissa) : 1.0 ; break; case EfficiencyMethod::Binned : effiTerm_ = effiHist_ ? effiHist_-> GetBinContent(effiHist_-> FindFixBin(abscissa)) : 1.0 ; break; case EfficiencyMethod::Flat : effiTerm_ = 1.0 ; break; // default : cerr << "Warning: EFFICIENCY INPUT METHOD NOT SET" << endl; effiTerms_.push_back( 1.0 ); } // Initialise the various terms to zero if (type_ == Hist){ if ( pdfHist_ ) { pdfHist_->calcLikelihoodInfo(abscissa); pdfTerm_ = pdfHist_->getLikelihood(); } else { pdfTerm_ = 1.0; } }else{ // Reset the state to Good this->state(Good); // If we're not using the resolution function calculate the simple terms and return if (!this->doSmearing()) { this->calcNonSmearedTerms(abscissa); return; } //TODO how much to be added below for SimFitNormBd/SimFitNormBs/SimFitSigBd/SimFitSigBs // Get all the up to date parameter values std::vector frac(nGauss_); std::vector mean(nGauss_); std::vector sigma(nGauss_); Double_t tau(0.0); Double_t deltaM(0.0); Double_t fracPrompt(0.0); Double_t Delta_gamma(0.0); frac[0] = 1.0; for (UInt_t i(0); ivalue(); sigma[i] = sigma_[i]->value(); if (i != 0) { frac[i] = frac_[i-1]->value(); frac[0] -= frac[i]; } } if (type_ != Delta) { tau = tau_->value(); if (type_ == ExpTrig) { deltaM = deltaM_->value(); } if (type_ == DeltaExp) { fracPrompt = fracPrompt_->value(); } if (type_ == ExpHypTrig){ deltaM = deltaM_->value(); Delta_gamma = deltaGamma_->value(); } } // Scale the gaussian parameters by the per-event error on Delta t (if appropriate) for (UInt_t i(0); i x(nGauss_); const Double_t xMax = this->maxAbscissa(); const Double_t xMin = this->minAbscissa(); for (UInt_t i(0); i 1e-10) { Double_t exponent(0.0); Double_t norm(0.0); Double_t scale = LauConstants::root2*sigma[i]; Double_t scale2 = LauConstants::rootPiBy2*sigma[i]; exponent = -0.5*x[i]*x[i]/(sigma[i]*sigma[i]); norm = scale2*(TMath::Erf((xMax - mean[i])/scale) - TMath::Erf((xMin - mean[i])/scale)); value += frac[i]*TMath::Exp(exponent)/norm; } } } if (type_ != Delta) { std::vector expTerms(nGauss_); std::vector cosTerms(nGauss_); std::vector sinTerms(nGauss_); std::vector coshTerms(nGauss_); std::vector sinhTerms(nGauss_); std::vector expTermsNorm(nGauss_); // TODO - TEL changed this name to make it compile - please check! std::vector SinhTermsNorm(nGauss_); // Calculate values of the PDF convoluated with each Gaussian for a given value of the abscsissa for (UInt_t i(0); icalcTrigExponent(deltaM, tau, x[i], sigma[i], exponentTermRe, exponentTermIm); // Elements related to the trigonometric function, i.e. convolution of Exp*Sin or Cos with Gauss Double_t sinTrigTermRe, sinTrigTermIm, cosTrigTermRe, cosTrigTermIm; this->calcTrigConv(deltaM, tau, x[i], sigma[i], sinTrigTermRe, sinTrigTermIm, kFALSE); this->calcTrigConv(deltaM, tau, x[i], sigma[i], cosTrigTermRe, cosTrigTermIm, kTRUE); // Combining elements of the full pdf LauComplex zExp(exponentTermRe, exponentTermIm); LauComplex zTrigSin(sinTrigTermRe, sinTrigTermIm); LauComplex zTrigCos(cosTrigTermRe, cosTrigTermIm); LauComplex sinConv = zExp * zTrigSin; LauComplex cosConv = zExp * zTrigCos; sinConv.scale(1.0/4.0); cosConv.scale(1.0/4.0); // Cosine*Exp and Sine*Exp terms cosTerms[i] = cosConv.re(); sinTerms[i] = sinConv.im(); // Normalisation Double_t umax = xMax - mean[i]; Double_t umin = xMin - mean[i]; expTermsNorm[i] = (1.0/2.0) * tau * (-1.0 + TMath::Erf(umax/(LauConstants::root2 * sigma[i])) + TMath::Erfc(umin/(LauConstants::root2 * sigma[i])) + TMath::Exp((pow(sigma[i], 2) - 2.0 * tau * (xMax + xMin - mean[i]))/(2.0 * pow(tau, 2))) * (TMath::Exp(xMax/tau) * TMath::Erfc((pow(sigma[i], 2) - xMin)/(LauConstants::root2 * tau))) + (TMath::Exp(xMin/tau) * TMath::Erfc((pow(sigma[i], 2) - xMax)/(LauConstants::root2 * tau)))); } else { } } // Typical case (2): B0s/B0sbar if (type_ == ExpHypTrig) { // LHCb convention if (method_ == DecayTime) { // Convolution of Exp*cosh (Exp*sinh) with a gaussian //Double_t OverallExpFactor = 0.25*TMath::Exp(-(x[i]-mean[i])*(x[i]-mean[i])/(2*sigma[i]*sigma[i])); //Double_t ExpFirstTerm = TMath::Exp((2*(x[i]-mean[i])*tau+sigma[i]*sigma[i]*(-2+Delta_gamma*tau))*(2*(x[i]-mean[i])*tau+sigma[i]*sigma[i]*(-2+Delta_gamma*tau))/(8*sigma[i]*sigma[i]*tau*tau)); //Double_t ExpSecondTerm = TMath::Exp((2*(-x[i]+mean[i])*tau+sigma[i]*sigma[i]*(2+Delta_gamma*tau))*(2*(-x[i]+mean[i])*tau+sigma[i]*sigma[i]*(2+Delta_gamma*tau))/(8*sigma[i]*sigma[i]*tau*tau)); //Double_t ErfFirstTerm = TMath::Erf((2*(x[i]-mean[i])*tau+sigma[i]*sigma[i]*(-2+Delta_gamma*tau))/(2*TMath::Sqrt(2)*sigma[i]*tau)); //Double_t ErfSecondTerm = TMath::Erf((2*(-x[i]+mean[i])*tau+sigma[i]*sigma[i]*(2+Delta_gamma*tau))/(2*TMath::Sqrt(2)*sigma[i]*tau)); //Double_t sinhConv = OverallExpFactor*(ExpFirstTerm*(1+ErfFirstTerm) + ExpSecondTerm*(-1+ErfSecondTerm)); //Double_t coshConv = OverallExpFactor*(ExpFirstTerm*(1+ErfFirstTerm) - ExpSecondTerm*(-1+ErfSecondTerm)); //cosTerms[i] = sinhConv; // sinTerms[i] = coshConv; //TODO: check this formula and try to simplify it! double OverallExpTerm_max = (1/(2*(-4 + Delta_gamma*Delta_gamma*tau*tau)))*tau*TMath::Exp(-0.5*Delta_gamma*(xMax + mean[i]) - xMax/tau); double ErfTerm_max = -2*Delta_gamma*tau*TMath::Exp(0.5*Delta_gamma*(xMax+mean[i])+xMax/tau)*TMath::Erf((xMax-mean[i])/(TMath::Sqrt(2)*sigma[i])); double ExpFirstTerm_max = TMath::Exp(xMax*Delta_gamma+(sigma[i]*sigma[i]*(-2 + Delta_gamma*tau)*(-2 + Delta_gamma*tau))/(8*tau*tau)); double ErfcFirstTerm_max = TMath::Erfc((2*(-xMax + mean[i])*tau + sigma[i]*sigma[i]*(2 - Delta_gamma*tau))/(2*TMath::Sqrt(2)*sigma[i]*tau)); double ExpSecondTerm_max = TMath::Exp(Delta_gamma*mean[i] + (sigma[i]*sigma[i]*(2 + Delta_gamma*tau)*(2 + Delta_gamma*tau))/(8*tau*tau)); double ErfcSecondTerm_max = TMath::Erfc((2*(-xMax + mean[i])*tau + sigma[i]*sigma[i]*(2 + Delta_gamma*tau))/(2*TMath::Sqrt(2)*sigma[i]*tau)); double MaxVal= OverallExpTerm_max*(ErfTerm_max + TMath::Exp(mean[i]/tau)*(ExpFirstTerm_max*(2+Delta_gamma*tau)* ErfcFirstTerm_max + ExpSecondTerm_max*(-2+Delta_gamma*tau)* ErfcSecondTerm_max)); double OverallExpTerm_min = (1/(2*(-4 + Delta_gamma*Delta_gamma*tau*tau)))*tau*TMath::Exp(-0.5*Delta_gamma*(xMin + mean[i]) - xMin/tau); double ErfTerm_min = -2*Delta_gamma*tau*TMath::Exp(0.5*Delta_gamma*(xMin+mean[i])+xMin/tau)*TMath::Erf((xMin-mean[i])/(TMath::Sqrt(2)*sigma[i])); double ExpFirstTerm_min = TMath::Exp(xMin*Delta_gamma+(sigma[i]*sigma[i]*(-2 + Delta_gamma*tau)*(-2 + Delta_gamma*tau))/(8*tau*tau)); double ErfcFirstTerm_min = TMath::Erfc((2*(-xMin + mean[i])*tau + sigma[i]*sigma[i]*(2 - Delta_gamma*tau))/(2*TMath::Sqrt(2)*sigma[i]*tau)); // TODO - TEL added this (currently identical to ExpSecondTerm_max) to get this to compile - please check!! double ExpSecondTerm_min = TMath::Exp(Delta_gamma*mean[i] + (sigma[i]*sigma[i]*(2 + Delta_gamma*tau)*(2 + Delta_gamma*tau))/(8*tau*tau)); double ErfcSecondTerm_min = TMath::Erfc((2*(-xMin + mean[i])*tau + sigma[i]*sigma[i]*(2 + Delta_gamma*tau))/(2*TMath::Sqrt(2)*sigma[i]*tau)); double minVal= OverallExpTerm_min*(ErfTerm_min + TMath::Exp(mean[i]/tau)*(ExpFirstTerm_min*(2+Delta_gamma*tau)* ErfcFirstTerm_min + ExpSecondTerm_min*(-2+Delta_gamma*tau)* ErfcSecondTerm_min)); SinhTermsNorm[i] = MaxVal - minVal; } else { } } } for (UInt_t i(0); icalcLikelihoodInfo(abscissaErr); errTerm_ = errHist_->getLikelihood(); } else { errTerm_ = 1.0; } } void LauDecayTimePdf::calcTrigExponent(Double_t deltaM, Double_t tau, Double_t x, Double_t sigma, Double_t& reTerm, Double_t& imTerm) { Double_t exponentTerm = TMath::Exp(-(2.0 * tau * x + pow(sigma, 2) * (pow(deltaM, 2) * pow(tau, 2) - 1.0))/(2.0 * pow(tau,2))); reTerm = exponentTerm * TMath::Cos(deltaM * (x - pow(sigma,2)/tau)); imTerm = - exponentTerm * TMath::Sin(deltaM * (x - pow(sigma,2)/tau)); } void LauDecayTimePdf::calcTrigConv(Double_t deltaM, Double_t tau, Double_t x, Double_t sigma, Double_t& reOutTerm, Double_t& imOutTerm, Bool_t trig) { Double_t reExpTerm, imExpTerm; LauComplex zExp; LauComplex zTrig1; LauComplex zTrig2; // Calculation for the sine or cosine term if (!trig) { reExpTerm = TMath::Sin(2.0 * deltaM * (x + pow(sigma,2)/tau)); imExpTerm = 2.0 * TMath::Sin(pow(deltaM * (x + pow(sigma,2)/tau), 2)); } else { reExpTerm = TMath::Cos(2.0 * deltaM * (x + pow(sigma,2)/tau)); imExpTerm = TMath::Sin(2.0 * deltaM * (x + pow(sigma,2)/tau)); } // Exponential term in front of Erfc/Erfi terms zExp.setRealPart(reExpTerm); zExp.setImagPart(imExpTerm); // Nominal Erfc term (common to both sine and cosine expressions zTrig1.setRealPart(-(tau * x - pow(sigma,2))/(LauConstants::root2 * tau * sigma)); zTrig1.setImagPart(-(deltaM * sigma)/ LauConstants::root2); // Second term for sine (Erfi) or cosine (Erfc) - notice the re-im swap and sign change zTrig2.setRealPart(-zTrig1.im()); zTrig2.setImagPart(-zTrig1.re()); // Calculation of Erfc and Erfi (if necessary) LauComplex term1 = ComplexErfc(zTrig1.re(), zTrig1.im()); LauComplex term2; if (!trig) { term2 = Erfi(zTrig2.re(), zTrig2.im()); } else { term2 = ComplexErfc(zTrig2.re(), zTrig2.im()); } // Multiplying all elemnets of the convolution LauComplex output = zExp * term1 + term2; reOutTerm = output.re(); imOutTerm = output.im(); } LauComplex LauDecayTimePdf::ComplexErf(Double_t x, Double_t y) { // Evaluate Erf(x + iy) using an infinite series approximation // From Abramowitz & Stegun (http://people.math.sfu.ca/~cbm/aands/page_299.htm) if (x==0){ // cout << "WARNING: Set x value to 1e-100 to avoid division by 0." << endl; x = 1e-100; } int n = 20; // this cotrols the number of iterations of the sum LauComplex ErfTerm(TMath::Erf(x),0.); LauComplex CosSineTerm(1-cos(2*x*y), sin(2*x*y)); CosSineTerm.rescale(TMath::Exp(-x*x)/(2*TMath::Pi()*x)); LauComplex firstPart = ErfTerm + CosSineTerm; LauComplex SumTerm(0,0); for (int k = 1; k<=n; k++){ Double_t f_k = 2*x*(1 - cos(2*x*y)*cosh(k*y)) + k*sin(2*x*y)*sinh(k*y); Double_t g_k = 2*x*sin(2*x*y)*cosh(k*y) + k*cos(2*x*y)*sinh(k*y); LauComplex fgTerm(f_k, g_k); fgTerm.rescale(TMath::Exp(-0.25*k*k)/(k*k + 4*x*x)); SumTerm += fgTerm; } SumTerm.rescale((2/TMath::Pi())*TMath::Exp(-x*x)); LauComplex result = firstPart + SumTerm; return result; } LauComplex LauDecayTimePdf::Erfi(Double_t x, Double_t y) { // Erfi(z) = -I*Erf(I*z) where z = x + iy double x_prime = -y; double y_prime = x; LauComplex a = ComplexErf(x_prime, y_prime); LauComplex result(a.im(), -a.re()); return result; } LauComplex LauDecayTimePdf::ComplexErfc(Double_t x, Double_t y) { // Erfc(z) = 1 - Erf(z) (z = x + iy) LauComplex one(1., 0.); LauComplex result = one - ComplexErf(x,y); return result; } void LauDecayTimePdf::calcNonSmearedTerms(Double_t abscissa) { if (type_ == Hist ){ cerr << "It is a histogrammed PDF" << endl; return; } if (type_ == Delta) { return; } Double_t tau = tau_->value(); Double_t deltaM = deltaM_->value(); // Calculate the terms related to cosine and sine not normalised if (type_ == ExpTrig) { if (method_ == DecayTime) { expTerm_ = TMath::Exp(-abscissa/tau)/(2.0*tau); } if (method_ == DecayTimeDiff) { expTerm_ = TMath::Exp(-TMath::Abs(abscissa)/tau)/(2.0*tau); } cosTerm_ = TMath::Cos(deltaM*abscissa)*expTerm_; sinTerm_ = TMath::Sin(deltaM*abscissa)*expTerm_; coshTerm_ = expTerm_; sinhTerm_ = 0.0; } // Calculate the terms related to cosine not normalised if (type_ == SimFitNormBd || type_ == SimFitNormBs) { if (method_ == DecayTime) { expTerm_ = TMath::Exp(-abscissa/tau)/(2.0*tau); } if (method_ == DecayTimeDiff) { expTerm_ = TMath::Exp(-TMath::Abs(abscissa)/tau)/(2.0*tau); } cosTerm_ = TMath::Cos(deltaM*abscissa)*expTerm_; sinTerm_ = 0.0; coshTerm_ = expTerm_; sinhTerm_ = 0.0; if (type_ == SimFitNormBs){ Double_t deltaGamma = deltaGamma_->value(); coshTerm_ *= TMath::CosH(deltaGamma*abscissa/2.0); } } // Calculate the terms related to cosine and sine not normalised if (type_ == SimFitSigBd || type_ == SimFitSigBs) { if (method_ == DecayTime) { expTerm_ = TMath::Exp(-abscissa/tau)/(2.0*tau); } if (method_ == DecayTimeDiff) { expTerm_ = TMath::Exp(-TMath::Abs(abscissa)/tau)/(2.0*tau); } cosTerm_ = TMath::Cos(deltaM*abscissa)*expTerm_; sinTerm_ = TMath::Sin(deltaM*abscissa)*expTerm_; coshTerm_ = expTerm_; sinhTerm_ = 0.0; if (type_ == SimFitNormBs){ Double_t deltaGamma = deltaGamma_->value(); coshTerm_ *= TMath::CosH(deltaGamma*abscissa/2.0); sinhTerm_ = TMath::SinH(deltaGamma*abscissa/2.0)*expTerm_; } } // Calculate the terms related to cosine, sine, cosh and sinh not normalised (no decayTimeDiff implemented) if (type_ == ExpHypTrig) { Double_t deltaGamma = deltaGamma_->value(); expTerm_ = TMath::Exp(-abscissa/tau)/(2.0*tau); cosTerm_ = TMath::Cos(deltaM*abscissa)*expTerm_; sinTerm_ = TMath::Sin(deltaM*abscissa)*expTerm_; coshTerm_ = TMath::CosH(deltaGamma*abscissa/2.0)*expTerm_; sinhTerm_ = TMath::SinH(deltaGamma*abscissa/2.0)*expTerm_; } } Double_t LauDecayTimePdf::normExpHypTerm(Double_t Abs) { Double_t tau = tau_->value(); Double_t deltaGamma = deltaGamma_->value(); Double_t y = tau*deltaGamma/2; Double_t nonTrigTerm = -(TMath::Exp(-Abs/tau))/(1 - y*y); Double_t cosHTerm = TMath::CosH(deltaGamma*Abs/2); Double_t sinHTerm = TMath::SinH(deltaGamma*Abs/2); Double_t normTerm = nonTrigTerm*(cosHTerm + y*sinHTerm); return normTerm; } Double_t LauDecayTimePdf::normExpHypTermDep(Double_t Abs) { Double_t tau = tau_->value(); Double_t deltaGamma = deltaGamma_->value(); Double_t y = tau*deltaGamma/2; Double_t nonTrigTerm = -(TMath::Exp(-Abs/tau))/(1 - y*y); Double_t cosHTerm = TMath::CosH(deltaGamma*Abs/2); Double_t sinHTerm = TMath::SinH(deltaGamma*Abs/2); Double_t normTerm = nonTrigTerm*(sinHTerm + y*cosHTerm); return normTerm; } std::pair LauDecayTimePdf::nonSmearedCosSinIntegral(Double_t minAbs, Double_t maxAbs) { // From 1407.0748, not clear whether complex is faster in this case Double_t gamma = 1. / this->tau_->value(); LauComplex denom = LauComplex(gamma, -this->deltaM_->value()); LauComplex exponent = LauComplex(-gamma, this->deltaM_->value()); LauComplex num0 = -exponent.scale(minAbs).exp(); LauComplex num1 = -exponent.scale(maxAbs).exp(); LauComplex integral = (num1 - num0) / denom; return {integral.re(), integral.im()}; } std::pair LauDecayTimePdf::smearedCosSinIntegral(Double_t minAbs, Double_t maxAbs, Double_t sigma) { Double_t mu = 0.; // Placeholder Double_t gamma = 1. / this->tau_->value(); Double_t x1 = (maxAbs - mu) / (LauConstants::root2 * sigma); Double_t x0 = (minAbs - mu) / (LauConstants::root2 * sigma); std::complex z = std::complex(gamma * sigma / LauConstants::root2, -this->deltaM_->value() * sigma / LauConstants::root2); std::complex arg1 = (z - x1); std::complex arg0 = (z - x0); std::complex integral = RooMath::erf(x1) - TMath::Exp(-(x1 * x1)) * RooMath::faddeeva(arg1); integral -= RooMath::erf(x0) - TMath::Exp(-(x0 * x0)) * RooMath::faddeeva(arg0); integral *= (sigma / (2. * LauConstants::root2 * z)); Double_t cos_integral = integral.real(); Double_t sin_integral = integral.imag(); return {cos_integral, sin_integral}; } std::pair LauDecayTimePdf::nonSmearedCoshSinhIntegral(Double_t minAbs, Double_t maxAbs) { // Use exponential formualtion rather than cosh, sinh. // Fewer terms (reused for each), but not guaranteed to be faster. Double_t gamma = 1. / this->tau_->value(); Double_t gammaH = gamma - 0.5 * deltaGamma_->value(); Double_t gammaL = gamma - 0.5 * deltaGamma_->value(); Double_t nL1 = -TMath::Exp(-gammaL * maxAbs) / gammaL; Double_t nH1 = -TMath::Exp(-gammaH * maxAbs) / gammaH; Double_t nL0 = -TMath::Exp(-gammaL * minAbs) / gammaL; Double_t nH0 = -TMath::Exp(-gammaH * minAbs) / gammaH; Double_t cosh_integral = 0.5 * ( (nH1 + nL1) - (nH0 + nL0) ); Double_t sinh_integral = 0.5 * ( (nH1 - nL1) - (nH0 - nL0) ); return {cosh_integral, sinh_integral}; } std::pair LauDecayTimePdf::smearedCoshSinhIntegral(Double_t minAbs, Double_t maxAbs, Double_t sigma) { Double_t mu = 0.; // Placeholder Double_t gamma = 1. / this->tau_->value(); Double_t x1 = (maxAbs - mu) / (LauConstants::root2 * sigma); Double_t x0 = (minAbs - mu) / (LauConstants::root2 * sigma); Double_t z_H = ((gamma - deltaGamma_->value() / 2.) * sigma) / LauConstants::root2; std::complex arg1_H(0., z_H - x1); std::complex arg0_H(0., z_H - x0); std::complex integral_H = RooMath::erf(x1) - TMath::Exp(-(x1 * x1)) * RooMath::faddeeva(arg1_H); integral_H -= RooMath::erf(x0) - TMath::Exp(-(x0 * x0)) * RooMath::faddeeva(arg0_H); integral_H *= (sigma / (2. * LauConstants::root2 * z_H)); // Same for light (L) Double_t z_L = ((gamma + deltaGamma_->value() / 2.) * sigma) / LauConstants::root2; std::complex arg1_L(0., z_L - x1); std::complex arg0_L(0., z_L - x0); std::complex integral_L = RooMath::erf(x1) - TMath::Exp(-(x1 * x1)) * RooMath::faddeeva(arg1_L); integral_L -= RooMath::erf(x0) - TMath::Exp(-(x0 * x0)) * RooMath::faddeeva(arg0_L); integral_L *= (sigma / (2. * LauConstants::root2 * z_L)); std::complex cosh_integral = 0.5 * (integral_H + integral_L); std::complex sinh_integral = 0.5 * (integral_H - integral_L); return {cosh_integral.real(), sinh_integral.real()}; } void LauDecayTimePdf::calcNorm() { // first reset integrals to zero normTermExp_ = 0.0; normTermCos_ = 0.0; normTermSin_ = 0.0; normTermCosh_ = 0.0; normTermSinh_ = 0.0; switch ( effMethod_ ) { case EfficiencyMethod::Flat : // No efficiency variation // Simply calculate integrals over full range this->calcPartialIntegrals( minAbscissa_, maxAbscissa_ ); break; case EfficiencyMethod::Binned : // Efficiency varies as piecewise constant // Total integral is sum of integrals in each bin, each weighted by efficiency in that bin for ( Int_t bin{1}; bin <= effiHist_->GetNbinsX(); ++bin ) { const Double_t loEdge {effiHist_->GetBinLowEdge(bin)}; const Double_t hiEdge {loEdge + effiHist_->GetBinWidth(bin)}; const Double_t effVal {effiHist_->GetBinContent(bin)}; this->calcPartialIntegrals( loEdge, hiEdge, effVal ); } break; case EfficiencyMethod::Spline : // Efficiency varies as piecewise polynomial // TODO - to be worked out what to do here std::cerr << "WARNING in LauDecayTimePdf::calcNorm : normalisation integrals for spline acceptance not yet implemented - effect of acceptance will be neglected!" << std::endl; this->calcPartialIntegrals( minAbscissa_, maxAbscissa_ ); break; } // TODO - should we check here that all terms we expect to use are now non-zero? } void LauDecayTimePdf::calcPartialIntegrals(const Double_t minAbs, const Double_t maxAbs, const Double_t weight) { const Double_t tau = tau_->value(); const Double_t Gamma = 1.0 / tau; // TODO - this is all neglecting resolution at the moment // Normalisation factor for B0 decays if (type_ == ExpTrig || type_ == SimFitNormBd || type_ == SimFitSigBd ) { if (method_ == DecayTime) { normTermExp_ += weight * tau * ( TMath::Exp(-minAbs*Gamma) - TMath::Exp(-maxAbs*Gamma) ); auto [cosIntegral, sinIntegral] = this->nonSmearedCosSinIntegral(minAbs, maxAbs); normTermCos_ += weight * cosIntegral; normTermSin_ += weight * sinIntegral; } else if (method_ == DecayTimeDiff) { normTermExp_ += weight * tau * (2.0 - TMath::Exp(-maxAbs*Gamma) - TMath::Exp(-minAbs*Gamma)); // TODO - the other terms } } // Do more business here, with RooFit libs turned on: // std::complex c(0.1, 0.1); // RooMath::faddeeva(c); // Normalisation factor for Bs decays // TODO HACKATHON - to be replaced if (type_ == ExpHypTrig) { normTermCosh_ += weight * ( normExpHypTerm(maxAbs) - normExpHypTerm(minAbs) ); normTermSinh_ += weight * ( normExpHypTermDep( maxAbs) - normExpHypTermDep( minAbs) ); } } Double_t LauDecayTimePdf::generateError(Bool_t forceNew) { if (errHist_ && (forceNew || !abscissaErrorGenerated_)) { LauFitData errData = errHist_->generate(0); abscissaError_ = errData.find(this->varErrName())->second; abscissaErrorGenerated_ = kTRUE; } else { while (forceNew || !abscissaErrorGenerated_) { abscissaError_ = LauRandom::randomFun()->Landau(errorDistMPV_,errorDistSigma_); if (abscissaError_ < maxAbscissaError_ && abscissaError_ > minAbscissaError_) { abscissaErrorGenerated_ = kTRUE; forceNew = kFALSE; } } } return abscissaError_; } /* LauFitData LauDecayTimePdf::generate(const LauKinematics* kinematics) { // generateError SHOULD have been called before this // function but will call it here just to make sure // (has ns effect if has already been called) abscissaError_ = this->generateError(); // If the PDF is scaled by the per-event error then need to update the PDF height for each event Bool_t scale(kFALSE); for (std::vector::const_iterator iter = scaleMeans_.begin(); iter != scaleMeans_.end(); ++iter) { scale |= (*iter); } for (std::vector::const_iterator iter = scaleWidths_.begin(); iter != scaleWidths_.end(); ++iter) { scale |= (*iter); } if (scale || (!this->heightUpToDate() && !this->cachePDF())) { this->calcPDFHeight(kinematics); this->heightUpToDate(kTRUE); } // Generate the value of the abscissa. Bool_t gotAbscissa(kFALSE); Double_t genVal(0.0); Double_t genPDFVal(0.0); LauFitData genAbscissa; const Double_t xMin = this->minAbscissa(); const Double_t xMax = this->maxAbscissa(); const Double_t xRange = xMax - xMin; while (!gotAbscissa) { genVal = LauRandom::randomFun()->Rndm()*xRange + xMin; this->calcLikelihoodInfo(genVal, abscissaError_); genPDFVal = this->getUnNormLikelihood(); if (LauRandom::randomFun()->Rndm() <= genPDFVal/this->getMaxHeight()) {gotAbscissa = kTRUE;} if (genPDFVal > this->getMaxHeight()) { cerr<<"Warning in LauDecayTimePdf::generate()." <<" genPDFVal = "<getMaxHeight()<<" for the abscissa = "<varName()] = genVal; // mark that we need a new error to be generated next time abscissaErrorGenerated_ = kFALSE; return genAbscissa; } */ void LauDecayTimePdf::setErrorHisto(const TH1* hist) { if ( errHist_ != 0 ) { cerr<<"WARNING in LauDecayTimePdf::setErrorHisto : Error histogram already set, not doing it again."<varErrName(), hist, this->minAbscissaError(), this->maxAbscissaError()); } void LauDecayTimePdf::setHistoPdf(const TH1* hist) { if ( pdfHist_ != 0 ) { cerr<<"WARNING in LauDecayTimePdf::setHistoPdf : PDF histogram already set, not doing it again."<varName(), hist, this->minAbscissa(), this->maxAbscissa()); } void LauDecayTimePdf::setEffiHist(const TH1* hist) { if ( effiHist_ != nullptr ) { std::cerr << "WARNING in LauDecayTimePdf::setEffiHist : efficiency histogram already set, not doing it again." << std::endl; return; } if ( hist == nullptr ) { std::cerr << "WARNING in LauDecayTimePdf::setEffiHist : supplied efficiency histogram pointer is null." << std::endl; return; } // Check boundaries of histogram align with our abscissa's range const Double_t axisMin {hist->GetXaxis()->GetXmin()}; const Double_t axisMax {hist->GetXaxis()->GetXmax()}; if ( TMath::Abs(minAbscissa_ - axisMin)>1e-6 || TMath::Abs(maxAbscissa_ - axisMax)>1e-6 ) { std::cerr << "WARNING in LauDecayTimePdf::setEffiHist : mismatch in range between supplied histogram and abscissa\n" << " : histogram range: " << axisMin << " - " << axisMax << "\n" << " : abscissa range: " << minAbscissa_ << " - " << maxAbscissa_ << "\n" << " : Disregarding this histogram." << std::endl; return; } effiHist_ = dynamic_cast( hist->Clone() ); + + //Since we didn't do it in the constructor + this -> calcNorm(); } void LauDecayTimePdf::setEffiSpline(Lau1DCubicSpline* spline) { if ( effiFun_ != 0 ) { cerr<<"WARNING in LauDecayTimePdf::setEffiPdf : efficiency function already set, not doing it again."< effis = effiFun_->getYValues(); effiPars_.resize( effis.size() ); size_t index = 0; for( Double_t& effi : effis ) { effiPars_[ index ] = new LauParameter( Form( "%s_Knot_%lu", varName_.Data() ,index ), effi, 0.0, 1.0, kTRUE ); ++index; } } LauAbsRValue* LauDecayTimePdf::findParameter(const TString& parName) { for ( std::vector::iterator iter = param_.begin(); iter != param_.end(); ++iter ) { if ((*iter)->name().Contains(parName)) { return (*iter); } } std::cerr << "ERROR in LauDecayTimePdf::findParameter : Parameter \"" << parName << "\" not found." << std::endl; return 0; } const LauAbsRValue* LauDecayTimePdf::findParameter(const TString& parName) const { for ( std::vector::const_iterator iter = param_.begin(); iter != param_.end(); ++iter ) { if ((*iter)->name().Contains(parName)) { return (*iter); } } std::cerr << "ERROR in LauDecayTimePdf::findParameter : Parameter \"" << parName << "\" not found." << std::endl; return 0; } void LauDecayTimePdf::updatePulls() { for ( std::vector::iterator iter = param_.begin(); iter != param_.end(); ++iter ) { std::vector params = (*iter)->getPars(); for (std::vector::iterator params_iter = params.begin(); params_iter != params.end(); ++params_iter ) { if (!(*iter)->fixed()) { (*params_iter)->updatePull(); } } } } void LauDecayTimePdf::updateEffiSpline(std::vector effiPars) { if (effiPars.size() != effiFun_->getnKnots()){ cerr<<"ERROR in LauDecayTimePdf::updateEffiSpline : number of efficiency parameters is not equal to the number of spline knots."<Exit(EXIT_FAILURE); } effiFun_->updateYValues(effiPars); }