diff --git a/examples/GenFitTimeDep_Bd2Dpipi_SignalOnly.cc b/examples/GenFitTimeDep_Bd2Dpipi_SignalOnly.cc index c466a6a..adc13e4 100644 --- a/examples/GenFitTimeDep_Bd2Dpipi_SignalOnly.cc +++ b/examples/GenFitTimeDep_Bd2Dpipi_SignalOnly.cc @@ -1,591 +1,591 @@ #include "TimeDep_Dpipi_ProgOpts.hh" #include "Lau1DHistPdf.hh" #include "Lau1DCubicSpline.hh" #include "LauBinnedDecayTimeEfficiency.hh" #include "LauBkgndDPModel.hh" #include "LauCrystalBallPdf.hh" #include "LauDaughters.hh" #include "LauDecayTime.hh" #include "LauDecayTimePdf.hh" #include "LauDecayTimePhysicsModel.hh" #include "LauDecayTimeResolution.hh" #include "LauEffModel.hh" #include "LauExponentialPdf.hh" #include "LauFlavTag.hh" #include "LauGounarisSakuraiRes.hh" #include "LauIsobarDynamics.hh" #include "LauLHCbNR.hh" #include "LauMagPhaseCoeffSet.hh" #include "LauRandom.hh" #include "LauRealImagCoeffSet.hh" #include "LauResonanceMaker.hh" #include "LauSplineDecayTimeEfficiency.hh" #include "LauSumPdf.hh" #include "LauTimeDepFitModel.hh" #include "LauVetoes.hh" #include "TFile.h" #include "TH2.h" #include "TRandom.h" #include "TString.h" #include "TSystem.h" #include "TF1.h" #include "TCanvas.h" #include "TRegexp.h" #include "nlohmann/json.hpp" #include #include #include #include #include #include // Helper functions for creating sets of DTA splines using LauCubicSplineDecayTimeEfficiencyPtr = std::unique_ptr>; using LauSixthSplineDecayTimeEfficiencyPtr = std::unique_ptr>; auto createSplineDTASet( const TString& jsonFileName, const TString& dModeStr, const TString& runStr, const TString& suffix, const TString& signalName, const std::vector& bkgndNames ) { std::cout << "INFO - creating QFS signal DTA model" << std::endl; const TString controlSplineName { Form("%s_Kpi_%s%s",signalName.Data(),runStr.Data(),suffix.Data()) }; const TString controlEffName { Form("dteff_QFS_%s",runStr.Data()) }; auto controlSpline = Lau1DCubicSpline::readFromJson( jsonFileName, controlSplineName ); LauCubicSplineDecayTimeEfficiencyPtr controlEff { std::make_unique>( controlEffName, std::move( controlSpline ) ) }; LauSixthSplineDecayTimeEfficiencyPtr signalEff; if ( dModeStr != "Kpi" ) { std::cout << "INFO - creating " << dModeStr << " signal DTA model" << std::endl; const TString signalSplineName { Form("%s_%s_%s%s",signalName.Data(),dModeStr.Data(),runStr.Data(),suffix.Data()) }; const TString signalEffName { Form("dteff_CP%s_%s",dModeStr.Data(),runStr.Data()) }; auto signalSpline = Lau1DCubicSpline::readFromJson( jsonFileName, signalSplineName ); signalEff = std::make_unique>( signalEffName, *controlEff, std::move( signalSpline ) ); } std::map bkgndEffs; for ( auto& name : bkgndNames ) { std::cout << "INFO - creating " << dModeStr << " " << name << " background DTA model" << std::endl; const TString bkgndSplineName { Form("%s_%s_%s%s",name.Data(),dModeStr.Data(),runStr.Data(),suffix.Data()) }; const TString bkgndEffName { Form("%s_DTA_ratio_%s_%s",name.Data(),runStr.Data(),dModeStr.Data()) }; auto bkgndSpline = Lau1DCubicSpline::readFromJson( jsonFileName, bkgndSplineName ); auto bkgndEff = std::make_unique>( bkgndEffName, *controlEff, std::move( bkgndSpline ) ); bkgndEffs.emplace( std::make_pair( name, std::move(bkgndEff) ) ); } return std::make_tuple( std::move(controlEff), std::move(signalEff), std::move(bkgndEffs) ); } int main(const int argc, const char ** argv) { const TestDpipi_ProgramSettings settings{argc,argv}; if ( ! settings.parsedOK ) { return EXIT_FAILURE; } if ( settings.helpRequested ) { return EXIT_SUCCESS; } if ( settings.dataFit and settings.command == Command::Generate ) { std::cerr << "I can't generate data! Wait for Run 3" << std::endl; return EXIT_FAILURE; } if ( settings.dataFit and not settings.blindFit and not settings.fixPhiMix ) { std::cerr << "We don't have permission to do unblinded fits yet!" << std::endl; return EXIT_FAILURE; } if ( settings.run == 0 or settings.run > 2 ) { std::cerr << "The Run number must be either 1 or 2" << std::endl; return EXIT_FAILURE; } // check that all required data files are present const std::string signalYieldsJsonFile { "Bd2D0pipi_SignalYields.json" }; const std::string dpModelJsonFile = Form("Bd2D0pipi_DP_Model_Coeffs_Vetoes.json"); const std::string dtModelJsonFile { "Bd2D0pipi_DecayTime.json" }; const std::string dtaModelJsonFile { "Bd2D0pipi_DecayTime_Acceptance.json" }; const std::string taggingCalibJsonFile { "Bd2D0pipi_TaggingCalib.json" }; const std::array jsonFiles { dpModelJsonFile, dtModelJsonFile, dtaModelJsonFile, signalYieldsJsonFile, taggingCalibJsonFile }; for ( auto& jsonFile : jsonFiles ) { if ( std::filesystem::exists( jsonFile ) ) { continue; } std::cerr << "WARNING : couldn't find the json file \"" << jsonFile << "\" attempting to fetch from eos ..." << std::endl; if ( system( Form("xrdcp %s/%s/%s .", settings.eosRoot.c_str(), settings.eosConfigDir.c_str(), jsonFile.c_str()) ) != 0 ) { std::cerr << "FATAL : couldn't get the json file from remote!" << std::endl; return EXIT_FAILURE; } } const UInt_t runNo = settings.run; const std::string runStr = Form("Run%u", runNo); const TString dModeStr { TString{settings.directory}.ReplaceAll("B2Dhh_","") }; LauRandom::setSeed(settings.RNGseed); LauDaughters* daughtersB0bar = new LauDaughters("B0_bar", "pi+", "pi-", "D0", kTRUE); LauDaughters* daughtersB0 = new LauDaughters("B0", "pi+", "pi-", "D0_bar",kTRUE); // efficiency auto vetoes { LauVetoes::readFromJson( dpModelJsonFile, "Bd2D0pipi_Vetoes" ) }; LauEffModel* effModelB0bar = new LauEffModel(daughtersB0bar, vetoes.get()); LauEffModel* effModelB0 = new LauEffModel(daughtersB0, vetoes.get()); TFile* effFile(nullptr); TH2* effHist(nullptr); if (settings.directory == "B2Dhh_Kpi"){ effFile = TFile::Open(Form("%s/%s/eff_map_mprime_thprime_model_d2kpi_run%u.root",settings.eosRoot.c_str(),settings.eosConfigDir.c_str(),runNo)); effHist = dynamic_cast(effFile->Get(Form("eff_map_mprime_thprime_model_d2kpi_run%u",runNo))); } else if (settings.directory == "B2Dhh_KK"){ effFile = TFile::Open(Form("%s/%s/eff_map_mprime_thprime_model_d2kk_run%u.root",settings.eosRoot.c_str(),settings.eosConfigDir.c_str(),runNo)); effHist = dynamic_cast(effFile->Get(Form("eff_map_mprime_thprime_model_d2kk_run%u",runNo))); } else if (settings.directory == "B2Dhh_pipi"){ effFile = TFile::Open(Form("%s/%s/eff_map_mprime_thprime_model_d2pipi_run%u.root",settings.eosRoot.c_str(),settings.eosConfigDir.c_str(),runNo)); effHist = dynamic_cast(effFile->Get(Form("eff_map_mprime_thprime_model_d2pipi_run%u",runNo))); } else {std::cerr << "bad dir given!" << std::endl; return EXIT_FAILURE;} effModelB0->setEffHisto(effHist, kTRUE, kFALSE, 0.0, 0.0, kFALSE, kTRUE); effModelB0bar->setEffHisto(effHist, kTRUE, kFALSE, 0.0, 0.0, kFALSE, kTRUE); // setup flavour tagging const Bool_t useAveDeltaCalibVals { settings.useAveDeltaCalibVals }; const Bool_t useEtaPrime { kFALSE }; LauFlavTag* flavTag = new LauFlavTag(useAveDeltaCalibVals,useEtaPrime); if (settings.dType == LauTimeDepFitModel::CPEigenvalue::QFS) { flavTag->setDecayFlvVarName("decayFlv"); } //if(not settings.dataFit) //{ // flavTag->setTrueTagVarName("trueTag"); //} TFile* etaFile = TFile::Open(Form("%s/%s/ETAhists.root",settings.eosRoot.c_str(),settings.eosConfigDir.c_str())); TH1* etaHist{nullptr}; TH1* etaHistB0{nullptr}; TH1* etaHistB0bar{nullptr}; if (settings.directory == "B2Dhh_Kpi"){ etaHistB0 = dynamic_cast(etaFile->Get(Form("signalMC_Kpi_Run%u_etaHist_dcyB",runNo))); etaHistB0bar = dynamic_cast(etaFile->Get(Form("signalMC_Kpi_Run%u_etaHist_dcyBbar",runNo))); etaHist = dynamic_cast(etaHistB0->Clone(Form("signalMC_Kpi_Run%u_etaHist",runNo))); etaHist->Add(etaHistB0bar); } else if (settings.directory == "B2Dhh_KK"){ etaHist = dynamic_cast(etaFile->Get(Form("signalMC_KK_Run%u_etaHist",runNo))); } else if (settings.directory == "B2Dhh_pipi"){ etaHist = dynamic_cast(etaFile->Get(Form("signalMC_pipi_Run%u_etaHist",runNo))); } else {std::cerr << "bad dir given!" << std::endl; return EXIT_FAILURE;} // Crude check as to whether we're doing perfect vs realistic mis-tag // - in the former case all entries should be in the first bin // If the tagging is perfect then don't interpolate the eta histogram // and also make it perfectly efficient, otherwise do interpolate and // make it 50% efficient Lau1DHistPdf* etaHistPdf = new Lau1DHistPdf( "eta", etaHist, 0.0, 0.5, kTRUE, kFALSE ); if(settings.addTaggers) { // NB deliberately not using uniform initialisation here because of this issue: // https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays const nlohmann::json taggingCalibJson = LauJsonTools::readJsonFile( taggingCalibJsonFile, "", LauJsonTools::JsonType::Array ); if ( taggingCalibJson.is_null() ) { std::cerr << "ERROR : unable to retrieve root JSON object from file \"" << taggingCalibJsonFile << "\"" << std::endl; return EXIT_FAILURE; } for ( const auto& taggerConfig : taggingCalibJson ) { if ( taggerConfig.at("name").get() == ("IFT_" + runStr) ) { flavTag->addTagger( taggerConfig, etaHistPdf ); } } if (settings.floatCalibPars) { flavTag->floatAllCalibPars(); } } // signal dynamics LauIsobarDynamics* sigModelB0bar = new LauIsobarDynamics(daughtersB0bar, effModelB0bar); if (settings.directory == "B2Dhh_Kpi"){ sigModelB0bar->setIntFileName(Form("integ_Kpi_Run%u_B0bar.dat",runNo)); } else if (settings.directory == "B2Dhh_KK"){ sigModelB0bar->setIntFileName(Form("integ_KK_Run%u_B0bar.dat",runNo)); } else if (settings.directory == "B2Dhh_pipi"){ sigModelB0bar->setIntFileName(Form("integ_pipi_Run%u_B0bar.dat",runNo)); } sigModelB0bar->constructModelFromJson( dpModelJsonFile, "Bd2D0pipi_B0bar_Model" ); LauIsobarDynamics* sigModelB0 = new LauIsobarDynamics(daughtersB0, effModelB0); if (settings.directory == "B2Dhh_Kpi"){ sigModelB0->setIntFileName(Form("integ_Kpi_Run%u_B0.dat",runNo)); } else if (settings.directory == "B2Dhh_KK"){ sigModelB0->setIntFileName(Form("integ_KK_Run%u_B0.dat",runNo)); } else if (settings.directory == "B2Dhh_pipi"){ sigModelB0->setIntFileName(Form("integ_pipi_Run%u_B0.dat",runNo)); } sigModelB0->constructModelFromJson( dpModelJsonFile, "Bd2D0pipi_B0_Model" ); // fit model LauTimeDepFitModel* fitModel = new LauTimeDepFitModel(sigModelB0bar,sigModelB0,flavTag); fitModel->breakOnBadLikelihood(kFALSE); fitModel->sendFixedYieldsToFitter(kTRUE); std::vector> coeffset { LauAbsCoeffSet::readFromJson( dpModelJsonFile, "Bd2D0pipi_Coeffs" ) }; for ( auto& coeff : coeffset ) { fitModel->setAmpCoeffSet( std::move(coeff) ); } // decay type and mixing parameter const Bool_t fixPhiMix{ settings.fixPhiMix || settings.dType == LauTimeDepFitModel::CPEigenvalue::QFS }; const Bool_t useSinCos{ settings.useSinCos }; fitModel->setCPEigenvalue( settings.dType ); fitModel->setPhiMix( 2.0*LauConstants::beta, fixPhiMix, useSinCos ); if ( useSinCos ) { if ( settings.blindFit ) { //Blinding strings generated from: https://www.thewordfinder.com/random-sentence-generator/ const TString sinBlindString{settings.dataFit ? "Tom realized he could be making a big mistake." : "Don't Look a Gift Horse In The Mouth"}; const TString cosBlindString{settings.dataFit ? "He admitted defeat." : "Long In The Tooth"}; fitModel->blindPhiMix( sinBlindString, cosBlindString ); } std::cout << "Is sin(phiMix) blinded? " << std::boolalpha << fitModel->sinPhiMixBlinded() << std::endl; std::cout << "Is cos(phiMix) blinded? " << std::boolalpha << fitModel->cosPhiMixBlinded() << std::endl; } else { if ( settings.blindFit ) { const TString blindString{"A Cut Above"}; fitModel->blindPhiMix( blindString ); } std::cout << "Is phiMix blinded? " << std::boolalpha << fitModel->phiMixBlinded() << std::endl; } // production asymmetries - fitModel->setProductionAsymmetry( runNo == 1 ? 0.00317 : 0.00113, settings.fixProdAsym, runStr ); + fitModel->setProductionAsymmetry( runNo == 1 ? -0.00659512 : -0.00637719, settings.fixProdAsym, runStr ); // decay time PDFs const Double_t minDt{0.2}; const Double_t maxDt{15.0}; const Double_t minDtErr{0.0}; const Double_t maxDtErr{0.15}; // physics models auto dtPhysicsModels { LauDecayTimePhysicsModel::readFromJson( dtModelJsonFile, "PhysicsModels" ) }; auto& dtPhysModel { dtPhysicsModels.at("signal") }; auto lifetimePar = dynamic_cast( dtPhysModel->findParameter("dt_sig_tau_Bd") ); if ( lifetimePar ) { lifetimePar->fixed( settings.fixLifetime ); } auto deltaMPar = dynamic_cast( dtPhysModel->findParameter("dt_sig_deltaM_Bd") ); if ( deltaMPar ) { deltaMPar->fixed( settings.fixDeltaM ); } // resolution models auto dtResolutionModels { LauDecayTimeResolution::readFromJson( dtModelJsonFile, Form("ResolutionModels_Run%d", runNo) ) }; auto& dtResoModel { dtResolutionModels.at("signal") }; // Decay time error histogram // (always set this so that it gets generated properly, whether we're using it in the PDF or not) TFile* dtErrFile = TFile::Open(Form("%s/%s/dte-hist.root",settings.eosRoot.c_str(),settings.eosConfigDir.c_str())); TH1* dtErrHist = dynamic_cast(dtErrFile->Get("dte_hist")); LauDecayTimePdf * dtPdf{nullptr}; if ( settings.timeResolution ) { if ( settings.perEventTimeErr ) { std::cerr << "Warning : the resolution model has not been constructed with per-event error scaling, but you have requested it" << std::endl; dtPdf = new LauDecayTimePdf( "decayTime", minDt, maxDt, "decayTimeErr", minDtErr, maxDtErr, std::move(dtPhysModel), std::move(dtResoModel), dtErrHist ); } else { dtPdf = new LauDecayTimePdf( "decayTime", minDt, maxDt, std::move(dtPhysModel), std::move(dtResoModel) ); } } else { dtPdf = new LauDecayTimePdf( "decayTime", minDt, maxDt, std::move(dtPhysModel) ); } // Decay time acceptance histogram TFile* dtaFile = TFile::Open(Form("%s/%s/DTAhists.root",settings.eosRoot.c_str(),settings.eosConfigDir.c_str())); TH1* dtaHist{nullptr}; if (settings.directory == "B2Dhh_Kpi"){ dtaHist = dynamic_cast(dtaFile->Get(Form("signalMC_Kpi_Run%u_DTAhist",runNo))); } else if (settings.directory == "B2Dhh_KK"){ dtaHist = dynamic_cast(dtaFile->Get(Form("signalMC_KK_Run%u_DTAhist",runNo))); } else if (settings.directory == "B2Dhh_pipi"){ dtaHist = dynamic_cast(dtaFile->Get(Form("signalMC_pipi_Run%u_DTAhist",runNo))); } else {std::cerr << "bad dir given!" << std::endl; return EXIT_FAILURE;} const TString signalName { "signalMC" }; std::vector bkgndNames; const TString suffix { "_DTAhist" }; auto [ qfsDTAModel, cpDTAModel, _ ] = createSplineDTASet( dtaModelJsonFile, dModeStr, runStr, suffix, signalName, bkgndNames ); auto qfsDTAModelPtr = qfsDTAModel.get(); switch(settings.timeEffModel) { case LauDecayTime::EfficiencyMethod::Spline: { fitModel->setASqMaxValue(0.01); if ( settings.dType == LauTimeDepFitModel::CPEigenvalue::QFS ) { fitModel->setASqMaxValue(0.009); } dynamic_cast(qfsDTAModel->getParameters().front())->maxValue(1e-1); //qfsDTAModel->fitToTH1(dtaHist); // Set which knots to float and which to fix (at least 1 knot must be fixed, not the first one) // Knots should only be floating if requested AND the B lifetime is fixed! if ( settings.fixSplineKnots or not settings.fixLifetime ) { qfsDTAModel->fixKnots(); } else { qfsDTAModel->floatKnots(); qfsDTAModel->fixKnot( 0, true ); qfsDTAModel->fixKnot( 3, true ); } if ( settings.dType == LauTimeDepFitModel::CPEigenvalue::QFS ) { dtPdf->setSplineEfficiency( std::move(qfsDTAModel) ); } else { dtPdf->setSplineEfficiency( std::move(cpDTAModel) ); } break; } case LauDecayTime::EfficiencyMethod::Binned: { fitModel->setASqMaxValue(0.06); auto dtaBinnedModel = std::make_unique( *dtaHist ); dtPdf->setBinnedEfficiency( std::move(dtaBinnedModel) ); break; } case LauDecayTime::EfficiencyMethod::Uniform: { fitModel->setASqMaxValue(4.45); break; } } fitModel->setSignalDtPdf( dtPdf ); // Signal and bkgnd yields const Bool_t fixYields {kTRUE};//{ settings.bkgndList.empty() or not settings.floatYields }; TString yieldName; LauParameter* nSigPar{nullptr}; // NB deliberately not using uniform initialisation here because of this issue: // https://json.nlohmann.me/home/faq/#brace-initialization-yields-arrays const nlohmann::json signalYieldsJson = LauJsonTools::readJsonFile( signalYieldsJsonFile, "", LauJsonTools::JsonType::Object ); if ( signalYieldsJson.is_null() ) { std::cerr << "ERROR : unable to retrieve root JSON object from file \"" << signalYieldsJsonFile << "\"" << std::endl; return EXIT_FAILURE; } const auto& nSigJson { signalYieldsJson.at(runStr).at(settings.directory) }; yieldName = Form("signalEvents_%s_Run%u", settings.directory.c_str(), runNo); if ( nSigJson.is_number() ) { const auto nSigEvents{ nSigJson.get() }; nSigPar = new LauParameter(yieldName, nSigEvents, -2.0*TMath::Abs(nSigEvents), 2.0*TMath::Abs(nSigEvents), fixYields); } else { const auto nSigEvents { LauJsonTools::getValue( nSigJson, "value" ) }; nSigPar = new LauParameter(yieldName, nSigEvents, -2.0*TMath::Abs(nSigEvents), 2.0*TMath::Abs(nSigEvents), fixYields); if ( ! fixYields && LauJsonTools::getOptionalValue( nSigJson, "constrained", LauJsonTools::JsonType::Boolean ).value_or(kFALSE) ) { const auto nSigEventsErr { LauJsonTools::getValue( nSigJson, "error" ) }; nSigPar->removeLimits(); nSigPar->error( nSigEventsErr ); nSigPar->addGaussianConstraint( nSigEvents, nSigEventsErr ); } } if ( nSigPar->value() < 0.0 ) { if ( settings.command == Command::Generate ) { std::cerr << "WARNING : setting negative signal yield to 0 for generation" << std::endl; } nSigPar->genValue( 0.0 ); } fitModel->setNSigEvents(nSigPar); // set the number of experiments if (settings.command == Command::Generate) { fitModel->setNExpts(settings.nExptGen, settings.firstExptGen, kTRUE); } else { fitModel->setNExpts(settings.nExptFit, settings.firstExptFit, !settings.dataFit); } fitModel->useAsymmFitErrors(kFALSE); fitModel->useRandomInitFitPars(kFALSE); fitModel->writeLatexTable(kFALSE); const Bool_t haveBkgnds = ( fitModel->nBkgndClasses() > 0 ); fitModel->doPoissonSmearing(haveBkgnds); fitModel->doEMLFit(haveBkgnds); TString dTypeStr; switch (settings.dType) { case LauTimeDepFitModel::CPEigenvalue::CPEven : dTypeStr = "CPEven"; break; case LauTimeDepFitModel::CPEigenvalue::CPOdd : dTypeStr = "CPOdd"; break; case LauTimeDepFitModel::CPEigenvalue::QFS : dTypeStr = "QFS"; break; } TString dataFile(""); TString treeName("fitTree"); TString rootFileName(""); TString tableFileName(""); TString fitToyFileName(""); TString splotFileName(""); dataFile = "TEST-Dpipi"; dataFile += "_"+dTypeStr+"_"+settings.directory; switch(settings.timeEffModel) { case LauDecayTime::EfficiencyMethod::Spline: dataFile += "_Spline"; break; case LauDecayTime::EfficiencyMethod::Binned: dataFile += "_Binned"; break; case LauDecayTime::EfficiencyMethod::Uniform: dataFile += "_Uniform"; break; } if (settings.timeResolution) { if (settings.perEventTimeErr) { dataFile += "_DTRperevt"; } else { dataFile += "_DTRavg"; } } else { dataFile += "_DTRoff"; } dataFile += "_expts"; dataFile += settings.firstExptGen; dataFile += "-"; dataFile += settings.firstExptGen+settings.nExptGen-1; dataFile += Form("-Run%u",runNo); dataFile += ".root"; if (settings.dataFit) { if(runNo == 2) { dataFile = Form("%s/%s/Run2/B2Dhh-CollisionCombined-MagCombined-Stripping24r2-withDNN-withPIDcorr-withMVA-withPIDMVA-WithDpiMatching-withSwappedMassHypotheses-withKKvetoes-withSelection-LauraPrepped.root",settings.eosRoot.c_str(),settings.eosDataDir.c_str()); } else { dataFile = Form("%s/%s/Run1/B2Dhh-CollisionCombined-MagCombined-Stripping21r1p2-withDNN-withPIDcorr-withMVA-withPIDMVA-WithDpiMatching-withSwappedMassHypotheses-withKKvetoes-withSelection-LauraPrepped.root",settings.eosRoot.c_str(),settings.eosDataDir.c_str()); } //treeName = Form("%s/B2DhhReco",settings.directory.data()); treeName = "fitTree"; } else if (settings.directory != "B2Dhh_Kpi") { TString dir = settings.directory; dir = TString(dir("_.+$")); dir.ReplaceAll("_",""); dataFile = Form("Bd2pipiD0-D02%s-%s-BootstrapSample.root", dir.Data(), runStr.c_str()); treeName = "fitTree"; } if (settings.command == Command::Generate) { rootFileName = "dummy.root"; tableFileName = "genResults"; } else { rootFileName = "fit"; rootFileName += settings.iFit; rootFileName += "_Results_"; rootFileName += dTypeStr; rootFileName += "_"; rootFileName += settings.directory; rootFileName += "_expts"; rootFileName += settings.firstExptFit; rootFileName += "-"; rootFileName += settings.firstExptFit+settings.nExptFit-1; rootFileName += Form("_Run%u",runNo); rootFileName += ".root"; tableFileName = "fit"; tableFileName += settings.iFit; tableFileName += "_Results_"; tableFileName += dTypeStr; tableFileName += "_"; tableFileName += settings.directory; tableFileName += "_expts"; tableFileName += settings.firstExptFit; tableFileName += "-"; tableFileName += settings.firstExptFit+settings.nExptFit-1; tableFileName += Form("_Run%u",runNo); fitToyFileName = "fit"; fitToyFileName += settings.iFit; fitToyFileName += "_ToyMC_"; fitToyFileName += dTypeStr; fitToyFileName += "_"; fitToyFileName += settings.directory; fitToyFileName += "_expts"; fitToyFileName += settings.firstExptFit; fitToyFileName += "-"; fitToyFileName += settings.firstExptFit+settings.nExptFit-1; fitToyFileName += Form("_Run%u",runNo); fitToyFileName += ".root"; splotFileName = "fit"; splotFileName += settings.iFit; splotFileName += "_sPlot_"; splotFileName += dTypeStr; splotFileName += "_"; splotFileName += settings.directory; splotFileName += "_expts"; splotFileName += settings.firstExptFit; splotFileName += "-"; splotFileName += settings.firstExptFit+settings.nExptFit-1; splotFileName += Form("_Run%u",runNo); splotFileName += ".root"; } if( settings.genToy and not settings.blindFit ) { fitModel->compareFitData(50, fitToyFileName); } // 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 switch (settings.command) { case Command::Generate : fitModel->run( "gen", dataFile, treeName, rootFileName, tableFileName ); break; case Command::Fit : fitModel->run( "fit", dataFile, treeName, rootFileName, tableFileName ); break; case Command::SimFit : fitModel->runTask( dataFile, treeName, rootFileName, tableFileName, "localhost", settings.port ); break; } // Write JSON files with the fitted values // signal yield nlohmann::json signalYieldJson = nlohmann::json::object(); signalYieldJson[ runStr ] = nlohmann::json::object(); signalYieldJson[ runStr ][ settings.directory ] = nlohmann::json::object(); signalYieldJson[ runStr ][ settings.directory ][ "value" ] = nSigPar->value(); signalYieldJson[ runStr ][ settings.directory ][ "error" ] = nSigPar->error(); signalYieldJson[ runStr ][ settings.directory ][ "constrained" ] = nSigPar->gaussConstraint(); LauJsonTools::writeJsonFile( signalYieldJson, "Bd2D0pipi_SignalYield_" + settings.directory + "_" + runStr + ".json" ); if (settings.dType == LauTimeDepFitModel::CPEigenvalue::QFS) { // QFS DTA spline qfsDTAModelPtr->writeSplineToJson( "Bd2D0pipi_DecayTime_Acceptance_Fitted_" + runStr + ".json" ); // FT calibration parameters flavTag->writeTaggersToJson( "Bd2D0pipi_TaggingCalib_Fitted_" + runStr + ".json" ); } return EXIT_SUCCESS; }