diff --git a/roofit/roofit/inc/RooLagrangianMorphFunc.h b/roofit/roofit/inc/RooLagrangianMorphFunc.h index 3548ead4ba7fe..274d98ac341ce 100644 --- a/roofit/roofit/inc/RooLagrangianMorphFunc.h +++ b/roofit/roofit/inc/RooLagrangianMorphFunc.h @@ -106,7 +106,7 @@ class RooLagrangianMorphFunc : public RooAbsReal { RooLagrangianMorphFunc(const char *name, const char *title, const Config &config); RooLagrangianMorphFunc(const RooLagrangianMorphFunc &other, const char *newName); - virtual ~RooLagrangianMorphFunc(); + ~RooLagrangianMorphFunc() override; std::list *binBoundaries(RooAbsRealLValue & /*obs*/, double /*xlo*/, double /*xhi*/) const override; std::list *plotSamplingHint(RooAbsRealLValue & /*obs*/, double /*xlo*/, double /*xhi*/) const override; @@ -230,16 +230,16 @@ class RooLagrangianMorphFunc : public RooAbsReal { void setScale(double val); double getScale(); - int nSamples() const { return this->_config.folderNames.size(); } + int nSamples() const { return _config.folderNames.size(); } RooRealSumFunc *getFunc() const; std::unique_ptr createPdf() const; RooAbsPdf::ExtendMode extendMode() const; - Double_t expectedEvents(const RooArgSet *nset) const; - Double_t expectedEvents(const RooArgSet &nset) const; - Double_t expectedEvents() const; - Bool_t selfNormalized() const { return true; } + double expectedEvents(const RooArgSet *nset) const; + double expectedEvents(const RooArgSet &nset) const; + double expectedEvents() const; + bool selfNormalized() const { return true; } void readParameters(TDirectory *f); void collectInputs(TDirectory *f); @@ -247,7 +247,6 @@ class RooLagrangianMorphFunc : public RooAbsReal { static std::unique_ptr makeRatio(const char *name, const char *title, RooArgList &nr, RooArgList &dr); private: - mutable RooObjCacheManager _cacheMgr; //! The cache manager double _scale = 1.0; std::map _sampleMap; diff --git a/roofit/roofit/src/RooLagrangianMorphFunc.cxx b/roofit/roofit/src/RooLagrangianMorphFunc.cxx index df1b320977cd1..9fc095ad2ba6d 100644 --- a/roofit/roofit/src/RooLagrangianMorphFunc.cxx +++ b/roofit/roofit/src/RooLagrangianMorphFunc.cxx @@ -449,53 +449,54 @@ void readValues(std::map &myMap, TH1 *h_pc) } /////////////////////////////////////////////////////////////////////////////// -/// Set up folder ownership over its children, and treat likewise any subfolders. -/// @param theFolder: folder to update. Assumed to be a valid pointer -void setOwnerRecursive(TFolder* theFolder){ +/// Set up folder ownership over its children, and treat likewise any subfolders. +/// @param theFolder: folder to update. Assumed to be a valid pointer +void setOwnerRecursive(TFolder *theFolder) +{ theFolder->SetOwner(); // And also need to set up ownership for nested folders - auto subdirs = theFolder->GetListOfFolders(); - for (auto* subdir : *subdirs){ - auto thisfolder = dynamic_cast(subdir); - if (thisfolder){ + auto subdirs = theFolder->GetListOfFolders(); + for (auto *subdir : *subdirs) { + auto thisfolder = dynamic_cast(subdir); + if (thisfolder) { // no explicit deletion here, will be handled by parent - setOwnerRecursive(thisfolder); - } + setOwnerRecursive(thisfolder); + } } } - /////////////////////////////////////////////////////////////////////////////// -/// Load a TFolder from a file while ensuring it owns its content. +/// Load a TFolder from a file while ensuring it owns its content. /// This avoids memory leaks. Note that when fetching objects -/// from this folder, you need to clone them to prevent deletion. +/// from this folder, you need to clone them to prevent deletion. /// Also recursively updates nested subfolders accordingly -/// @param inFile: Input file to read - assumed to be a valid pointer -/// @param folderName: Name of the folder to read from the file -/// @return a unique_ptr to the folder. Nullptr if not found. -std::unique_ptr readOwningFolderFromFile(TDirectory* inFile, const std::string & folderName){ +/// @param inFile: Input file to read - assumed to be a valid pointer +/// @param folderName: Name of the folder to read from the file +/// @return a unique_ptr to the folder. Nullptr if not found. +std::unique_ptr readOwningFolderFromFile(TDirectory *inFile, const std::string &folderName) +{ std::unique_ptr theFolder(inFile->Get(folderName.c_str())); if (!theFolder) { - std::cerr << "Error: unable to access data from folder '" << folderName << "' from file '"<GetName()<<"'!" << std::endl; - return nullptr; + std::cerr << "Error: unable to access data from folder '" << folderName << "' from file '" << inFile->GetName() + << "'!" << std::endl; + return nullptr; } - setOwnerRecursive(theFolder.get()); - return theFolder; + setOwnerRecursive(theFolder.get()); + return theFolder; } /////////////////////////////////////////////////////////////////////////////// -/// Helper to load a single object from a file-resident TFolder, while -/// avoiding memory leaks. -/// @tparam AObjType Type of object to load. -/// @param inFile input file to load from. Expected to be a valid pointer -/// @param folderName Name of the TFolder to load from the file -/// @param objName Name of the object to load +/// Helper to load a single object from a file-resident TFolder, while +/// avoiding memory leaks. +/// @tparam AObjType Type of object to load. +/// @param inFile input file to load from. Expected to be a valid pointer +/// @param folderName Name of the TFolder to load from the file +/// @param objName Name of the object to load /// @param notFoundError If set, print a detailed error if we didn't find something -/// @return Returns a pointer to a clone of the loaded object. Ownership assigned to the caller. -template AObjType* loadFromFileResidentFolder(TDirectory* inFile, - const std::string & folderName, - const std::string & objName, - bool notFoundError = true) +/// @return Returns a pointer to a clone of the loaded object. Ownership assigned to the caller. +template +std::unique_ptr loadFromFileResidentFolder(TDirectory *inFile, const std::string &folderName, + const std::string &objName, bool notFoundError = true) { auto folder = readOwningFolderFromFile(inFile, folderName); if (!folder) { @@ -503,23 +504,23 @@ template AObjType* loadFromFileResidentFolder(TDirectory* inFil } AObjType *loadedObject = dynamic_cast(folder->FindObject(objName.c_str())); if (!loadedObject) { - if (notFoundError){ + if (notFoundError) { std::stringstream errstr; errstr << "Error: unable to retrieve object '" << objName << "' from folder '" << folderName - << "'. contents are:"; + << "'. contents are:"; TIter next(folder->GetListOfFolders()->begin()); TFolder *f; while ((f = (TFolder *)next())) { errstr << " " << f->GetName(); } std::cerr << errstr.str() << std::endl; - } - return nullptr; + } + return nullptr; } - // replace the loaded object by a clone, as the loaded folder will delete the original - return static_cast(loadedObject->Clone()); // can use a static_cast - confirmed validity by initial cast above. -} - + // replace the loaded object by a clone, as the loaded folder will delete the original + // can use a static_cast - confirmed validity by initial cast above. + return std::unique_ptr{static_cast(loadedObject->Clone())}; +} /////////////////////////////////////////////////////////////////////////////// /// retrieve a ParamSet from a certain subfolder 'name' of the file @@ -528,8 +529,8 @@ template void readValues(std::map &myMap, TDirectory *file, const std::string &name, const std::string &key = "param_card", bool notFoundError = true) { - TH1F *h_pc = loadFromFileResidentFolder(file, name, key, notFoundError); - readValues(myMap, h_pc); + auto h_pc = loadFromFileResidentFolder(file, name, key, notFoundError); + readValues(myMap, h_pc.get()); } /////////////////////////////////////////////////////////////////////////////// @@ -766,8 +767,9 @@ void collectHistograms(const char *name, TDirectory *file, std::map(file, sample, varname, true); - if (!hist) return; + auto hist = loadFromFileResidentFolder(file, sample, varname, true); + if (!hist) + return; auto it = list_hf.find(sample); if (it != list_hf.end()) { @@ -778,7 +780,7 @@ void collectHistograms(const char *name, TDirectory *file, std::mapimportTH1(vars,*hist,1.,kFALSE); + // dh->importTH1(vars,*hist,1.,false); } else { if (!binningOK) { int n = hist->GetNbinsX(); @@ -796,13 +798,15 @@ void collectHistograms(const char *name, TDirectory *file, std::map(funcname, funcname, var, *dh); int idx = physics.getSize(); list_hf[sample] = idx; - physics.add(*hf); - assert(hf = static_cast(physics.at(idx))); + physics.addOwned(std::move(hf)); } // std::cout << "found histogram " << hist->GetName() << " with integral " // << hist->Integral() << std::endl; @@ -818,14 +822,14 @@ void collectRooAbsReal(const char * /*name*/, TDirectory *file, std::map(file,sample,varname,true); - if (!obj) return; + auto obj = loadFromFileResidentFolder(file, sample, varname, true); + if (!obj) + return; auto it = list_hf.find(sample); if (it == list_hf.end()) { int idx = physics.getSize(); list_hf[sample] = idx; - physics.add(*obj); - assert(obj == physics.at(idx)); + physics.addOwned(std::move(obj)); } } } @@ -840,14 +844,14 @@ void collectCrosssections(const char *name, TDirectory *file, std::map(file, sample, varname,false); + auto obj = loadFromFileResidentFolder(file, sample, varname, false); TParameter *xsection = nullptr; TParameter *error = nullptr; - TParameter *p = dynamic_cast *>(obj); + TParameter *p = dynamic_cast *>(obj.get()); if (p) { xsection = p; } - TPair *pair = dynamic_cast(obj); + TPair *pair = dynamic_cast(obj.get()); if (pair) { xsection = dynamic_cast *>(pair->Key()); error = dynamic_cast *>(pair->Value()); @@ -865,15 +869,17 @@ void collectCrosssections(const char *name, TDirectory *file, std::mapsetVal(xsection->GetVal()); } else { std::string objname = Form("phys_%s_%s", name, sample.c_str()); - xs = new RooRealVar(objname.c_str(), objname.c_str(), xsection->GetVal()); + auto xsOwner = std::make_unique(objname.c_str(), objname.c_str(), xsection->GetVal()); + xs = xsOwner.get(); xs->setConstant(true); int idx = physics.getSize(); list_xs[sample] = idx; - physics.add(*xs); + physics.addOwned(std::move(xsOwner)); assert(physics.at(idx) == xs); } - if (error) + if (error) { xs->setError(error->GetVal()); + } } } @@ -885,20 +891,17 @@ void collectCrosssectionsTPair(const char *name, TDirectory *file, std::map(file,basefolder,varname,false); - if (!pair) return; - TParameter *xsec_double = dynamic_cast *>(pair->Key()); - if (xsec_double) { + auto pair = loadFromFileResidentFolder(file, basefolder, varname, false); + if (!pair) + return; + if (dynamic_cast *>(pair->Key())) { collectCrosssections(name, file, list_xs, physics, varname, inputParameters); + } else if (dynamic_cast *>(pair->Key())) { + collectCrosssections(name, file, list_xs, physics, varname, inputParameters); } else { - TParameter *xsec_float = dynamic_cast *>(pair->Key()); - if (xsec_float) { - collectCrosssections(name, file, list_xs, physics, varname, inputParameters); - } else { - std::cerr << "cannot morph objects of class 'TPair' if parameter is not " - "double or float!" - << std::endl; - } + std::cerr << "cannot morph objects of class 'TPair' if parameter is not " + "double or float!" + << std::endl; } } @@ -1081,11 +1084,10 @@ inline void checkNameConflict(const RooLagrangianMorphFunc::ParamMap &inputParam /// build the formulas corresponding to the given set of input files and /// the physics process -template -inline FormulaList -buildFormulas(const char *mfname, const RooLagrangianMorphFunc::ParamMap &inputParameters, - const RooLagrangianMorphFunc::FlagMap &inputFlags, const MorphFuncPattern &morphfunc, - const RooArgList &couplings, const List &flags, const std::vector &nonInterfering) +FormulaList buildFormulas(const char *mfname, const RooLagrangianMorphFunc::ParamMap &inputParameters, + const RooLagrangianMorphFunc::FlagMap &inputFlags, const MorphFuncPattern &morphfunc, + const RooArgList &couplings, const RooArgList &flags, + const std::vector &nonInterfering) { // example vbf hww: // Operators kSM, kHww, kAww, kHdwR,kHzz, kAzz @@ -1221,11 +1223,10 @@ buildFormulas(const char *mfname, const RooLagrangianMorphFunc::ParamMap &inputP //////////////////////////////////////////////////////////////////////////////// /// create the weight formulas required for the morphing -template -inline FormulaList -createFormulas(const char *name, const RooLagrangianMorphFunc::ParamMap &inputs, - const RooLagrangianMorphFunc::FlagMap &inputFlags, const std::vector> &diagrams, - RooArgList &couplings, const T &flags, const std::vector &nonInterfering) +FormulaList createFormulas(const char *name, const RooLagrangianMorphFunc::ParamMap &inputs, + const RooLagrangianMorphFunc::FlagMap &inputFlags, + const std::vector> &diagrams, RooArgList &couplings, + const RooArgList &flags, const std::vector &nonInterfering) { MorphFuncPattern morphfuncpattern; @@ -1235,12 +1236,12 @@ createFormulas(const char *name, const RooLagrangianMorphFunc::ParamMap &inputs, ::collectPolynomials(morphfuncpattern, d); } FormulaList retval = buildFormulas(name, inputs, inputFlags, morphfuncpattern, couplings, flags, nonInterfering); - if (retval.size() == 0) { + if (retval.empty()) { std::stringstream errorMsgStream; errorMsgStream << "no formulas are non-zero, check if any if your couplings is floating and missing from your param_cards!" << std::endl; - const auto errorMsg = errorMsgStream.str(); + const auto errorMsg = errorMsgStream.str(); throw std::runtime_error(errorMsg); } checkMatrix(inputs, retval); @@ -1268,13 +1269,13 @@ inline void buildSampleWeights(T1 &weights, const char *fname, const RooLagrangi int formulaidx = 0; // build the formula with the correct normalization - RooLinearCombination *sampleformula = new RooLinearCombination(name_full.Data()); + auto sampleformula = std::make_unique(name_full.Data()); for (auto const &formulait : formulas) { const RooFit::SuperFloat val(inverse(formulaidx, sampleidx)); sampleformula->add(val, formulait.second.get()); formulaidx++; } - weights.add(*sampleformula); + weights.addOwned(std::move(sampleformula)); sampleidx++; } } @@ -1323,12 +1324,12 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { double _condition; CacheElem(){}; - virtual void operModeHook(RooAbsArg::OperMode) override{}; + void operModeHook(RooAbsArg::OperMode) override{}; ////////////////////////////////////////////////////////////////////////////// /// retrieve the list of contained args - virtual RooArgList containedArgs(Action) override + RooArgList containedArgs(Action) override { RooArgList args(*_sumFunc); args.add(_weights); @@ -1342,21 +1343,23 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { ////////////////////////////////////////////////////////////////////////////// // default destructor - virtual ~CacheElem() {} + ~CacheElem() override {} ////////////////////////////////////////////////////////////////////////////// /// create the basic objects required for the morphing inline void createComponents(const RooLagrangianMorphFunc::ParamMap &inputParameters, const RooLagrangianMorphFunc::FlagMap &inputFlags, const char *funcname, - const std::vector> &diagrams, - const std::vector &nonInterfering, const RooListProxy &flags) + const std::vector> &diagramProxyList, + const std::vector &nonInterfering, const RooArgList &flags) { RooArgList operators; - // coutD(ObjectHandling) << "collecting couplings" << std::endl; - for (const auto &diagram : diagrams) { - for (const auto &vertex : diagram) { - extractCouplings(*vertex, this->_couplings); + std::vector> diagrams; + for (const auto &diagram : diagramProxyList) { + diagrams.emplace_back(); + for (RooArgList *vertex : diagram) { + extractCouplings(*vertex, _couplings); + diagrams.back().emplace_back(vertex); } } extractOperators(_couplings, operators); @@ -1370,8 +1373,8 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { const RooLagrangianMorphFunc::FlagMap &inputFlags, const List &flags) { RooArgList operators; - extractOperators(this->_couplings, operators); - Matrix matrix(buildMatrixT(inputParameters, this->_formulas, operators, inputFlags, flags)); + extractOperators(_couplings, operators); + Matrix matrix(buildMatrixT(inputParameters, _formulas, operators, inputFlags, flags)); if (size(matrix) < 1) { std::cerr << "input matrix is empty, please provide suitable input samples!" << std::endl; } @@ -1406,7 +1409,7 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { bool first = true; RooAbsReal *obj; - for (auto itr : this->_couplings) { + for (auto itr : _couplings) { obj = dynamic_cast(itr); if (!first) std::cerr << ", "; @@ -1417,12 +1420,12 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { } } #ifndef USE_UBLAS - this->_matrix.ResizeTo(matrix.GetNrows(), matrix.GetNrows()); - this->_inverse.ResizeTo(matrix.GetNrows(), matrix.GetNrows()); + _matrix.ResizeTo(matrix.GetNrows(), matrix.GetNrows()); + _inverse.ResizeTo(matrix.GetNrows(), matrix.GetNrows()); #endif - this->_matrix = matrix; - this->_inverse = inverse; - this->_condition = condition; + _matrix = matrix; + _inverse = inverse; + _condition = condition; } //////////////////////////////////////////////////////////////////////////////// @@ -1442,10 +1445,10 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { } RooArgList operators; - extractOperators(this->_couplings, operators); + extractOperators(_couplings, operators); // retrieve the weights - ::buildSampleWeights(this->_weights, name, inputParameters, this->_formulas, this->_inverse); + ::buildSampleWeights(_weights, name, inputParameters, _formulas, _inverse); // build the products of element and weight for each sample size_t i = 0; @@ -1462,7 +1465,7 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { return; } - RooAbsReal *weight = static_cast(this->_weights.at(i)); + RooAbsReal *weight = static_cast(_weights.at(i)); if (!weight) { std::cerr << "unable to access weight object for " << prodname << std::endl; @@ -1473,38 +1476,38 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { RooArgList prodElems(*weight, *obj); allowNegativeYields = true; - RooProduct *prod = new RooProduct(prodname, prodname, prodElems); + auto prod = std::make_unique(prodname, prodname, prodElems); if (!allowNegativeYields) { auto maxname = std::string(prodname) + "_max0"; RooArgSet prodset(*prod); - RooFormulaVar *max = new RooFormulaVar(maxname.c_str(), "max(0," + prodname + ")", prodset); - sumElements.add(*max); + auto max = std::make_unique(maxname.c_str(), "max(0," + prodname + ")", prodset); + max->addOwnedComponents(std::move(prod)); + sumElements.addOwned(std::move(max)); } else { - sumElements.add(*prod); + sumElements.addOwned(std::move(prod)); } scaleElements.add(*(binWidth)); i++; } // put everything together - this->_sumFunc = make_unique(Form("%s_morphfunc", name), name, sumElements, scaleElements); + _sumFunc = make_unique(Form("%s_morphfunc", name), name, sumElements, scaleElements); if (!observable) std::cerr << "unable to access observable" << std::endl; - this->_sumFunc.get()->addServer(*observable); + _sumFunc.get()->addServer(*observable); if (!binWidth) std::cerr << "unable to access bin width" << std::endl; - this->_sumFunc.get()->addServer(*binWidth); + _sumFunc.get()->addServer(*binWidth); if (operators.getSize() < 1) std::cerr << "no operators listed" << std::endl; - this->_sumFunc.get()->addServerList(operators); - if (this->_weights.getSize() < 1) + _sumFunc.get()->addServerList(operators); + if (_weights.getSize() < 1) std::cerr << "unable to access weight objects" << std::endl; - this->_sumFunc.get()->addOwnedComponents(this->_weights); - this->_sumFunc.get()->addOwnedComponents(sumElements); - this->_sumFunc.get()->addServerList(sumElements); - this->_sumFunc.get()->addServerList(scaleElements); + _sumFunc.get()->addOwnedComponents(std::move(sumElements)); + _sumFunc.get()->addServerList(sumElements); + _sumFunc.get()->addServerList(scaleElements); #ifdef USE_UBLAS std::cout.precision(std::numeric_limits::digits); @@ -1519,11 +1522,12 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { RooLagrangianMorphFunc::ParamSet values = getParams(func->_operators); RooLagrangianMorphFunc::CacheElem *cache = new RooLagrangianMorphFunc::CacheElem(); + cache->createComponents(func->_config.paramCards, func->_config.flagValues, func->GetName(), func->_diagrams, - func->_nonInterfering, func->_flags); + {func->_nonInterfering.begin(), func->_nonInterfering.end()}, func->_flags); cache->buildMatrix(func->_config.paramCards, func->_config.flagValues, func->_flags); - if (obsName.size() == 0) { + if (obsName.empty()) { std::cerr << "Matrix inversion succeeded, but no observable was " "supplied. quitting..." << std::endl; @@ -1550,8 +1554,9 @@ class RooLagrangianMorphFunc::CacheElem : public RooAbsCacheElement { RooLagrangianMorphFunc::ParamSet values = getParams(func->_operators); RooLagrangianMorphFunc::CacheElem *cache = new RooLagrangianMorphFunc::CacheElem(); + cache->createComponents(func->_config.paramCards, func->_config.flagValues, func->GetName(), func->_diagrams, - func->_nonInterfering, func->_flags); + {func->_nonInterfering.begin(), func->_nonInterfering.end()}, func->_flags); #ifndef USE_UBLAS cache->_inverse.ResizeTo(inverse.GetNrows(), inverse.GetNrows()); @@ -1611,20 +1616,20 @@ RooRealVar *RooLagrangianMorphFunc::setupObservable(const char *obsname, TClass { // cxcoutP(ObjectHandling) << "setting up observable" << std::endl; RooRealVar *obs = nullptr; - Bool_t obsExists(false); - if (this->_observables.at(0) != 0) { - obs = (RooRealVar *)this->_observables.at(0); + bool obsExists(false); + if (_observables.at(0) != 0) { + obs = (RooRealVar *)_observables.at(0); obsExists = true; } if (mode && mode->InheritsFrom(RooHistFunc::Class())) { obs = (RooRealVar *)(dynamic_cast(inputExample)->getHistObsList().first()); obsExists = true; - this->_observables.add(*obs); + _observables.add(*obs); } else if (mode && mode->InheritsFrom(RooParamHistFunc::Class())) { obs = (RooRealVar *)(dynamic_cast(inputExample)->paramList().first()); obsExists = true; - this->_observables.add(*obs); + _observables.add(*obs); } // Note: "found!" will be printed if s2 is a substring of s1, both s1 and s2 @@ -1633,26 +1638,31 @@ RooRealVar *RooLagrangianMorphFunc::setupObservable(const char *obsname, TClass if (!obsExists) { if (mode && mode->InheritsFrom(TH1::Class())) { TH1 *hist = (TH1 *)(inputExample); - obs = new RooRealVar(obsname, obsname, hist->GetXaxis()->GetXmin(), hist->GetXaxis()->GetXmax()); + auto obsOwner = + std::make_unique(obsname, obsname, hist->GetXaxis()->GetXmin(), hist->GetXaxis()->GetXmax()); + obs = obsOwner.get(); + addOwnedComponents(std::move(obsOwner)); obs->setBins(hist->GetNbinsX()); } else { - obs = new RooRealVar(obsname, obsname, 0, 1); + auto obsOwner = std::make_unique(obsname, obsname, 0, 1); + obs = obsOwner.get(); + addOwnedComponents(std::move(obsOwner)); obs->setBins(1); } - this->_observables.add(*obs); + _observables.add(*obs); } else { if (strcmp(obsname, obs->GetName()) != 0) { - coutW(ObjectHandling) << " name of existing observable " << this->_observables.at(0)->GetName() - << " does not match expected name " << obsname << std::endl ; + coutW(ObjectHandling) << " name of existing observable " << _observables.at(0)->GetName() + << " does not match expected name " << obsname << std::endl; } } TString sbw = Form("binWidth_%s", makeValidName(obs->GetName()).Data()); - RooRealVar *binWidth = new RooRealVar(sbw.Data(), sbw.Data(), 1.); + auto binWidth = std::make_unique(sbw.Data(), sbw.Data(), 1.); double bw = obs->numBins() / (obs->getMax() - obs->getMin()); binWidth->setVal(bw); binWidth->setConstant(true); - this->_binWidths.add(*binWidth); + _binWidths.addOwned(std::move(binWidth)); return obs; } @@ -1671,13 +1681,13 @@ inline void RooLagrangianMorphFunc::updateSampleWeights() int sampleidx = 0; auto cache = this->getCache(); const size_t n(size(cache->_inverse)); - for (auto sampleit : this->_config.paramCards) { + for (auto sampleit : _config.paramCards) { const std::string sample(sampleit.first); // build the formula with the correct normalization RooLinearCombination *sampleformula = dynamic_cast(this->getSampleWeight(sample.c_str())); if (!sampleformula) { - coutE(ObjectHandling) << Form("unable to access formula for sample '%s'!",sample.c_str()) << std::endl; - return; + coutE(ObjectHandling) << Form("unable to access formula for sample '%s'!", sample.c_str()) << std::endl; + return; } cxcoutP(ObjectHandling) << "updating formula for sample '" << sample << "'" << std::endl; for (size_t formulaidx = 0; formulaidx < n; ++formulaidx) { @@ -1710,8 +1720,8 @@ inline void RooLagrangianMorphFunc::updateSampleWeights() void RooLagrangianMorphFunc::readParameters(TDirectory *f) { - readValues(this->_config.paramCards, f, this->_config.folderNames, "param_card", true); - readValues(this->_config.flagValues, f, this->_config.folderNames, "flags", false); + readValues(_config.paramCards, f, _config.folderNames, "param_card", true); + readValues(_config.flagValues, f, _config.folderNames, "flags", false); } //////////////////////////////////////////////////////////////////////////////// @@ -1719,32 +1729,33 @@ void RooLagrangianMorphFunc::readParameters(TDirectory *f) void RooLagrangianMorphFunc::collectInputs(TDirectory *file) { - std::string obsName = this->_config.observableName; + std::string obsName = _config.observableName; cxcoutP(InputArguments) << "initializing physics inputs from file " << file->GetName() << " with object name(s) '" << obsName << "'" << std::endl; - auto folderNames = this->_config.folderNames; - TObject* obj = loadFromFileResidentFolder(file, folderNames.front(), obsName, true); + auto folderNames = _config.folderNames; + auto obj = loadFromFileResidentFolder(file, folderNames.front(), obsName, true); if (!obj) { - std::cerr << "unable to locate object '" << obsName << "' in folder '" << folderNames.front() << "'!" << std::endl; + std::cerr << "unable to locate object '" << obsName << "' in folder '" << folderNames.front() << "'!" + << std::endl; return; } std::string classname = obj->ClassName(); TClass *mode = TClass::GetClass(obj->ClassName()); - RooRealVar *observable = this->setupObservable(obsName.c_str(), mode, obj); + RooRealVar *observable = this->setupObservable(obsName.c_str(), mode, obj.get()); if (classname.find("TH1") != std::string::npos) { collectHistograms(this->GetName(), file, _sampleMap, _physics, *observable, obsName, _config.paramCards); } else if (classname.find("RooHistFunc") != std::string::npos || classname.find("RooParamHistFunc") != std::string::npos || classname.find("PiecewiseInterpolation") != std::string::npos) { - collectRooAbsReal(this->GetName(), file, this->_sampleMap, this->_physics, obsName, this->_config.paramCards); + collectRooAbsReal(this->GetName(), file, _sampleMap, _physics, obsName, _config.paramCards); } else if (classname.find("TParameter") != std::string::npos) { collectCrosssections(this->GetName(), file, _sampleMap, _physics, obsName, _config.paramCards); } else if (classname.find("TParameter") != std::string::npos) { collectCrosssections(this->GetName(), file, _sampleMap, _physics, obsName, _config.paramCards); } else if (classname.find("TPair") != std::string::npos) { - collectCrosssectionsTPair(this->GetName(), file, this->_sampleMap, this->_physics, obsName, folderNames[0], - this->_config.paramCards); + collectCrosssectionsTPair(this->GetName(), file, _sampleMap, _physics, obsName, folderNames[0], + _config.paramCards); } else { std::cerr << "cannot morph objects of class '" << mode->GetName() << "'!" << std::endl; } @@ -1760,20 +1771,20 @@ void RooLagrangianMorphFunc::addFolders(const RooArgList &folders) const std::string sample(var ? var->getVal() : folder->GetName()); if (sample.empty()) continue; - this->_config.folderNames.push_back(sample); + _config.folderNames.push_back(sample); } - TDirectory *file = openFile(this->_config.fileName); + TDirectory *file = openFile(_config.fileName); TIter next(file->GetList()); TObject *obj = nullptr; while ((obj = (TObject *)next())) { - auto f = readOwningFolderFromFile(file,obj->GetName()); + auto f = readOwningFolderFromFile(file, obj->GetName()); if (!f) continue; - std::string name(f->GetName()); + std::string name(f->GetName()); if (name.empty()) continue; - this->_config.folderNames.push_back(name); + _config.folderNames.push_back(name); } closeFile(file); } @@ -1783,7 +1794,7 @@ void RooLagrangianMorphFunc::addFolders(const RooArgList &folders) void RooLagrangianMorphFunc::printParameters(const char *samplename) const { - for (const auto ¶m : this->_config.paramCards.at(samplename)) { + for (const auto ¶m : _config.paramCards.at(samplename)) { if (this->hasParameter(param.first.c_str())) { std::cout << param.first << " = " << param.second; if (this->isParameterConstant(param.first.c_str())) @@ -1799,7 +1810,7 @@ void RooLagrangianMorphFunc::printParameters(const char *samplename) const void RooLagrangianMorphFunc::printSamples() const { // print all the known samples to the console - for (auto folder : this->_config.folderNames) { + for (auto folder : _config.folderNames) { std::cout << folder << std::endl; } } @@ -1809,8 +1820,8 @@ void RooLagrangianMorphFunc::printSamples() const void RooLagrangianMorphFunc::printPhysics() const { - for (const auto &sample : this->_sampleMap) { - RooAbsArg *phys = this->_physics.at(sample.second); + for (const auto &sample : _sampleMap) { + RooAbsArg *phys = _physics.at(sample.second); if (!phys) continue; phys->Print(); @@ -1821,10 +1832,9 @@ void RooLagrangianMorphFunc::printPhysics() const /// constructor with proper arguments RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *title, const Config &config) - : RooAbsReal(name, title), _cacheMgr(this, 10, kTRUE, kTRUE), - _operators("operators", "set of operators", this, kTRUE, kFALSE), - _observables("observables", "morphing observables", this, kTRUE, kFALSE), - _binWidths("binWidths", "set of binWidth objects", this, kTRUE, kFALSE), _config(config) + : RooAbsReal(name, title), _cacheMgr(this, 10, true, true), _physics("physics", "physics", this), + _operators("operators", "set of operators", this), _observables("observables", "morphing observables", this), + _binWidths("binWidths", "set of binWidth objects", this), _flags("flags", "flags", this), _config(config) { this->init(); this->disableInterferences(_config.nonInterfering); @@ -1838,14 +1848,13 @@ RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *tit RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *title, const char *filename, const char *observableName, const RooArgSet &couplings, const RooArgSet &folders) - : RooAbsReal(name, title), _cacheMgr(this, 10, kTRUE, kTRUE), - _operators("operators", "set of operators", this, kTRUE, kFALSE), - _observables("observables", "morphing observables", this, kTRUE, kFALSE), - _binWidths("binWidths", "set of binWidth objects", this, kTRUE, kFALSE) -{ - this->_config.fileName = filename; - this->_config.observableName = observableName; - this->_config.couplings.add(couplings); + : RooAbsReal(name, title), _cacheMgr(this, 10, true, true), _physics("physics", "physics", this), + _operators("operators", "set of operators", this), _observables("observables", "morphing observables", this), + _binWidths("binWidths", "set of binWidth objects", this), _flags("flags", "flags", this) +{ + _config.fileName = filename; + _config.observableName = observableName; + _config.couplings.add(couplings); this->addFolders(folders); this->init(); this->setup(false); @@ -1855,45 +1864,45 @@ RooLagrangianMorphFunc::RooLagrangianMorphFunc(const char *name, const char *tit //////////////////////////////////////////////////////////////////////////////// /// setup this instance with the given set of operators and vertices -/// if own=true, the class will own the operatorsemplate +/// if own=true, the class will own the operators template `` void RooLagrangianMorphFunc::setup(bool own) { if (_config.couplings.size() > 0) { RooArgList operators; std::vector vertices; - extractOperators(this->_config.couplings, operators); - vertices.push_back(new RooListProxy("!couplings", "set of couplings in the vertex", this, kTRUE, kFALSE)); + extractOperators(_config.couplings, operators); + vertices.push_back(new RooListProxy("!couplings", "set of couplings in the vertex", this, true, false)); if (own) { - this->_operators.addOwned(operators); - vertices[0]->addOwned(this->_config.couplings); + _operators.addOwned(std::move(operators)); + vertices[0]->addOwned(_config.couplings); } else { - this->_operators.add(operators); - vertices[0]->add(this->_config.couplings); + _operators.add(operators); + vertices[0]->add(_config.couplings); } - this->_diagrams.push_back(vertices); + _diagrams.push_back(vertices); } - else if (this->_config.prodCouplings.size() > 0 && this->_config.decCouplings.size() > 0) { + else if (_config.prodCouplings.size() > 0 && _config.decCouplings.size() > 0) { std::vector vertices; RooArgList operators; cxcoutP(InputArguments) << "prod/dec couplings provided" << std::endl; - extractOperators(this->_config.prodCouplings, operators); - extractOperators(this->_config.decCouplings, operators); + extractOperators(_config.prodCouplings, operators); + extractOperators(_config.decCouplings, operators); vertices.push_back( - new RooListProxy("!production", "set of couplings in the production vertex", this, kTRUE, kFALSE)); - vertices.push_back(new RooListProxy("!decay", "set of couplings in the decay vertex", this, kTRUE, kFALSE)); + new RooListProxy("!production", "set of couplings in the production vertex", this, true, false)); + vertices.push_back(new RooListProxy("!decay", "set of couplings in the decay vertex", this, true, false)); if (own) { - this->_operators.addOwned(operators); - vertices[0]->addOwned(this->_config.prodCouplings); - vertices[1]->addOwned(this->_config.decCouplings); + _operators.addOwned(std::move(operators)); + vertices[0]->addOwned(_config.prodCouplings); + vertices[1]->addOwned(_config.decCouplings); } else { cxcoutP(InputArguments) << "adding non-own operators" << std::endl; - this->_operators.add(operators); - vertices[0]->add(this->_config.prodCouplings); - vertices[1]->add(this->_config.decCouplings); + _operators.add(operators); + vertices[0]->add(_config.prodCouplings); + vertices[1]->add(_config.decCouplings); } - this->_diagrams.push_back(vertices); + _diagrams.push_back(vertices); } } @@ -1908,10 +1917,10 @@ void RooLagrangianMorphFunc::disableInterference(const std::vector for (auto c : nonInterfering) { name << c; } - RooListProxy *p = new RooListProxy(name.str().c_str(), name.str().c_str(), this, kTRUE, kFALSE); + auto *p = new RooListProxy(name.str().c_str(), name.str().c_str(), this, true, false); this->_nonInterfering.push_back(p); for (auto c : nonInterfering) { - p->addOwned(*(new RooStringVar(c, c, c))); + p->addOwned(std::make_unique(c, c, c)); } } @@ -1931,37 +1940,39 @@ void RooLagrangianMorphFunc::disableInterferences(const std::vector_config.fileName; + std::string filename = _config.fileName; TDirectory *file = openFile(filename.c_str()); if (!file) { coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl; return; } this->readParameters(file); - checkNameConflict(this->_config.paramCards, this->_operators); + checkNameConflict(_config.paramCards, _operators); this->collectInputs(file); closeFile(file); - this->addServerList(this->_physics); RooRealVar *nNP0 = new RooRealVar("nNP0", "nNP0", 1., 0, 1.); nNP0->setStringAttribute("NewPhysics", "0"); nNP0->setConstant(true); - this->_flags.add(*nNP0); + _flags.add(*nNP0); RooRealVar *nNP1 = new RooRealVar("nNP1", "nNP1", 1., 0, 1.); nNP1->setStringAttribute("NewPhysics", "1"); nNP1->setConstant(true); - this->_flags.add(*nNP1); + _flags.add(*nNP1); RooRealVar *nNP2 = new RooRealVar("nNP2", "nNP2", 1., 0, 1.); nNP2->setStringAttribute("NewPhysics", "2"); nNP2->setConstant(true); - this->_flags.add(*nNP2); + _flags.add(*nNP2); RooRealVar *nNP3 = new RooRealVar("nNP3", "nNP3", 1., 0, 1.); nNP3->setStringAttribute("NewPhysics", "3"); nNP3->setConstant(true); - this->_flags.add(*nNP3); + _flags.add(*nNP3); RooRealVar *nNP4 = new RooRealVar("nNP4", "nNP4", 1., 0, 1.); nNP4->setStringAttribute("NewPhysics", "4"); nNP4->setConstant(true); - this->_flags.add(*nNP4); + _flags.add(*nNP4); + // we can't use `addOwned` before, because the RooListProxy doesn't overload + // `addOwned` correctly (it might in the future, then this can be changed). + _flags.takeOwnership(); } //////////////////////////////////////////////////////////////////////////////// @@ -1972,7 +1983,7 @@ RooLagrangianMorphFunc::RooLagrangianMorphFunc(const RooLagrangianMorphFunc &oth _physics(other._physics.GetName(), this, other._physics), _operators(other._operators.GetName(), this, other._operators), _observables(other._observables.GetName(), this, other._observables), - _binWidths(other._binWidths.GetName(), this, other._binWidths), _flags(other._flags.GetName(), this, other._flags), + _binWidths(other._binWidths.GetName(), this, other._binWidths), _flags{other._flags.GetName(), this, other._flags}, _config(other._config) { for (size_t j = 0; j < other._diagrams.size(); ++j) { @@ -1981,7 +1992,7 @@ RooLagrangianMorphFunc::RooLagrangianMorphFunc(const RooLagrangianMorphFunc &oth RooListProxy *list = new RooListProxy(other._diagrams[j][i]->GetName(), this, *(other._diagrams[j][i])); diagram.push_back(list); } - this->_diagrams.push_back(diagram); + _diagrams.push_back(diagram); } TRACE_CREATE } @@ -1991,7 +2002,7 @@ RooLagrangianMorphFunc::RooLagrangianMorphFunc(const RooLagrangianMorphFunc &oth void RooLagrangianMorphFunc::setScale(double val) { - this->_scale = val; + _scale = val; } //////////////////////////////////////////////////////////////////////////////// @@ -1999,16 +2010,16 @@ void RooLagrangianMorphFunc::setScale(double val) double RooLagrangianMorphFunc::getScale() { - return this->_scale; + return _scale; } //////////////////////////////////////////////////////////////////////////////// // default constructor RooLagrangianMorphFunc::RooLagrangianMorphFunc() - : _cacheMgr(this, 10, true, true), _operators("operators", "set of operators", this, kTRUE, kFALSE), - _observables("observable", "morphing observable", this, kTRUE, kFALSE), - _binWidths("binWidths", "set of bin width objects", this, kTRUE, kFALSE) + : _cacheMgr(this, 10, true, true), _operators("operators", "set of operators", this, true, false), + _observables("observable", "morphing observable", this, true, false), + _binWidths("binWidths", "set of bin width objects", this, true, false) { static int counter(0); counter++; @@ -2018,7 +2029,18 @@ RooLagrangianMorphFunc::RooLagrangianMorphFunc() //////////////////////////////////////////////////////////////////////////////// /// default destructor -RooLagrangianMorphFunc::~RooLagrangianMorphFunc(){TRACE_DESTROY} +RooLagrangianMorphFunc::~RooLagrangianMorphFunc() +{ + for (auto const &diagram : _diagrams) { + for (RooListProxy *vertex : diagram) { + delete vertex; + } + } + for (RooListProxy *l : _nonInterfering) { + delete l; + } + TRACE_DESTROY +} //////////////////////////////////////////////////////////////////////////////// /// cloning method @@ -2087,10 +2109,11 @@ RooLagrangianMorphFunc::createWeightStrings(const RooLagrangianMorphFunc::ParamM ownedVertices.emplace(); auto &vertex = ownedVertices.top(); for (const auto &c : vtx) { - RooRealVar *coupling = (RooRealVar *)(couplings.find(c.c_str())); + auto coupling = static_cast(couplings.find(c.c_str())); if (!coupling) { - coupling = new RooRealVar(c.c_str(), c.c_str(), 1., 0., 10.); - couplings.add(*coupling); + auto couplingOwner = std::make_unique(c.c_str(), c.c_str(), 1., 0., 10.); + coupling = couplingOwner.get(); + couplings.addOwned(std::move(couplingOwner)); } vertex.add(*coupling); } @@ -2199,7 +2222,7 @@ RooProduct *RooLagrangianMorphFunc::getSumElement(const char *name) const std::vector RooLagrangianMorphFunc::getSamples() const { - return this->_config.folderNames; + return _config.folderNames; } //////////////////////////////////////////////////////////////////////////////// @@ -2261,7 +2284,7 @@ bool RooLagrangianMorphFunc::updateCoefficients() { auto cache = this->getCache(); - std::string filename = this->_config.fileName; + std::string filename = _config.fileName; TDirectory *file = openFile(filename.c_str()); if (!file) { coutE(InputArguments) << "unable to open file '" << filename << "'!" << std::endl; @@ -2270,10 +2293,10 @@ bool RooLagrangianMorphFunc::updateCoefficients() this->readParameters(file); - checkNameConflict(this->_config.paramCards, this->_operators); + checkNameConflict(_config.paramCards, _operators); this->collectInputs(file); - cache->buildMatrix(this->_config.paramCards, this->_config.flagValues, this->_flags); + cache->buildMatrix(_config.paramCards, _config.flagValues, _flags); this->updateSampleWeights(); closeFile(file); @@ -2289,7 +2312,7 @@ bool RooLagrangianMorphFunc::useCoefficients(const TMatrixD &inverse) auto cache = static_cast(_cacheMgr.getObj(0, (RooArgSet *)0)); Matrix m = makeSuperMatrix(inverse); if (cache) { - std::string filename = this->_config.fileName; + std::string filename = _config.fileName; cache->_inverse = m; TDirectory *file = openFile(filename.c_str()); if (!file) { @@ -2298,7 +2321,7 @@ bool RooLagrangianMorphFunc::useCoefficients(const TMatrixD &inverse) } this->readParameters(file); - checkNameConflict(this->_config.paramCards, this->_operators); + checkNameConflict(_config.paramCards, _operators); this->collectInputs(file); // then, update the weights in the morphing function @@ -2309,7 +2332,7 @@ bool RooLagrangianMorphFunc::useCoefficients(const TMatrixD &inverse) cache = RooLagrangianMorphFunc::CacheElem::createCache(this, m); if (!cache) coutE(Caching) << "unable to create cache!" << std::endl; - this->_cacheMgr.setObj(0, 0, cache, 0); + _cacheMgr.setObj(0, 0, cache, 0); } return true; } @@ -2351,7 +2374,7 @@ typename RooLagrangianMorphFunc::CacheElem *RooLagrangianMorphFunc::getCache() c auto cache = static_cast(_cacheMgr.getObj(0, (RooArgSet *)0)); if (!cache) { cxcoutP(Caching) << "creating cache from getCache function for " << this << std::endl; - cxcoutP(Caching) << "current storage has size " << this->_sampleMap.size() << std::endl; + cxcoutP(Caching) << "current storage has size " << _sampleMap.size() << std::endl; cache = RooLagrangianMorphFunc::CacheElem::createCache(this); if (cache) _cacheMgr.setObj(nullptr, nullptr, cache, nullptr); @@ -2366,7 +2389,7 @@ typename RooLagrangianMorphFunc::CacheElem *RooLagrangianMorphFunc::getCache() c bool RooLagrangianMorphFunc::hasCache() const { - return (bool)(_cacheMgr.getObj(nullptr, static_cast(nullptr))); + return (bool)(_cacheMgr.getObj(nullptr, static_cast(nullptr))); } //////////////////////////////////////////////////////////////////////////////// @@ -2444,7 +2467,7 @@ bool RooLagrangianMorphFunc::isParameterConstant(const char *name) const RooRealVar *RooLagrangianMorphFunc::getParameter(const char *name) const { - return dynamic_cast(this->_operators.find(name)); + return dynamic_cast(_operators.find(name)); } //////////////////////////////////////////////////////////////////////////////// @@ -2452,7 +2475,7 @@ RooRealVar *RooLagrangianMorphFunc::getParameter(const char *name) const RooRealVar *RooLagrangianMorphFunc::getFlag(const char *name) const { - return dynamic_cast(this->_flags.find(name)); + return dynamic_cast(_flags.find(name)); } //////////////////////////////////////////////////////////////////////////////// @@ -2493,7 +2516,7 @@ double RooLagrangianMorphFunc::getParameterValue(const char *name) const void RooLagrangianMorphFunc::setParameters(TH1 *paramhist) { - setParams(paramhist, this->_operators, false); + setParams(paramhist, _operators, false); } //////////////////////////////////////////////////////////////////////////////// @@ -2502,10 +2525,10 @@ void RooLagrangianMorphFunc::setParameters(TH1 *paramhist) void RooLagrangianMorphFunc::setParameters(const char *foldername) { - std::string filename = this->_config.fileName; + std::string filename = _config.fileName; TDirectory *file = openFile(filename.c_str()); - TH1 *paramhist = loadFromFileResidentFolder(file, foldername,"param_card"); - setParams(paramhist, this->_operators, false); + auto paramhist = loadFromFileResidentFolder(file, foldername, "param_card"); + setParams(paramhist.get(), _operators, false); closeFile(file); } @@ -2516,7 +2539,7 @@ void RooLagrangianMorphFunc::setParameters(const char *foldername) RooLagrangianMorphFunc::ParamSet RooLagrangianMorphFunc::getMorphParameters(const char *foldername) const { const std::string name(foldername); - return this->_config.paramCards.at(name); + return _config.paramCards.at(name); } //////////////////////////////////////////////////////////////////////////////// @@ -2538,11 +2561,11 @@ void RooLagrangianMorphFunc::setParameters(const RooArgList *list) RooRealVar *RooLagrangianMorphFunc::getObservable() const { - if (this->_observables.getSize() < 1) { + if (_observables.getSize() < 1) { coutE(InputArguments) << "observable not available!" << std::endl; return nullptr; } - return static_cast(this->_observables.at(0)); + return static_cast(_observables.at(0)); } //////////////////////////////////////////////////////////////////////////////// @@ -2550,11 +2573,11 @@ RooRealVar *RooLagrangianMorphFunc::getObservable() const RooRealVar *RooLagrangianMorphFunc::getBinWidth() const { - if (this->_binWidths.getSize() < 1) { + if (_binWidths.getSize() < 1) { coutE(InputArguments) << "bin width not available!" << std::endl; return nullptr; } - return static_cast(this->_binWidths.at(0)); + return static_cast(_binWidths.at(0)); } //////////////////////////////////////////////////////////////////////////////// @@ -2635,7 +2658,7 @@ bool RooLagrangianMorphFunc::isParameterUsed(const char *paramname) const std::string pname(paramname); double val = 0; bool isUsed = false; - for (const auto &sample : this->_config.paramCards) { + for (const auto &sample : _config.paramCards) { double thisval = sample.second.at(pname); if (thisval != val) { if (val != 0) @@ -2661,7 +2684,7 @@ bool RooLagrangianMorphFunc::isCouplingUsed(const char *couplname) RooLagrangianMorphFunc::ParamSet params = this->getMorphParameters(); double val = 0; bool isUsed = false; - for (const auto &sample : this->_config.paramCards) { + for (const auto &sample : _config.paramCards) { this->setParameters(sample.second); double thisval = coupling->getVal(); if (thisval != val) { @@ -2725,7 +2748,7 @@ void RooLagrangianMorphFunc::printEvaluation() const const RooArgSet *RooLagrangianMorphFunc::getParameterSet() const { - return &(this->_operators); + return &(_operators); } //////////////////////////////////////////////////////////////////////////////// @@ -2759,7 +2782,7 @@ RooLagrangianMorphFunc::ParamSet RooLagrangianMorphFunc::getCouplings() const RooLagrangianMorphFunc::ParamSet RooLagrangianMorphFunc::getMorphParameters() const { - return getParams(this->_operators); + return getParams(_operators); } //////////////////////////////////////////////////////////////////////////////// @@ -2767,7 +2790,7 @@ RooLagrangianMorphFunc::ParamSet RooLagrangianMorphFunc::getMorphParameters() co void RooLagrangianMorphFunc::setParameters(const ParamSet ¶ms) { - setParams(params, this->_operators, false); + setParams(params, _operators, false); } //////////////////////////////////////////////////////////////////////////////// @@ -2803,7 +2826,7 @@ RooAbsPdf::ExtendMode RooLagrangianMorphFunc::extendMode() const /// return expected number of events for extended likelihood calculation, /// this is the sum of all coefficients -Double_t RooLagrangianMorphFunc::expectedEvents(const RooArgSet *nset) const +double RooLagrangianMorphFunc::expectedEvents(const RooArgSet *nset) const { return this->createPdf()->expectedEvents(nset); } @@ -2811,7 +2834,7 @@ Double_t RooLagrangianMorphFunc::expectedEvents(const RooArgSet *nset) const //////////////////////////////////////////////////////////////////////////////// /// return the number of expected events for the current parameter set -Double_t RooLagrangianMorphFunc::expectedEvents() const +double RooLagrangianMorphFunc::expectedEvents() const { RooArgSet set; set.add(*this->getObservable()); @@ -2822,7 +2845,7 @@ Double_t RooLagrangianMorphFunc::expectedEvents() const /// return expected number of events for extended likelihood calculation, /// this is the sum of all coefficients -Double_t RooLagrangianMorphFunc::expectedEvents(const RooArgSet &nset) const +double RooLagrangianMorphFunc::expectedEvents(const RooArgSet &nset) const { return createPdf()->expectedEvents(&nset); } @@ -2835,8 +2858,8 @@ double RooLagrangianMorphFunc::expectedUncertainty() const RooRealVar *observable = this->getObservable(); auto cache = this->getCache(); double unc2 = 0; - for (const auto &sample : this->_sampleMap) { - RooAbsArg *phys = this->_physics.at(sample.second); + for (const auto &sample : _sampleMap) { + RooAbsArg *phys = _physics.at(sample.second); auto weightName = std::string("w_") + sample.first + "_" + this->GetName(); auto weight = static_cast(cache->_weights.find(weightName.c_str())); if (!weight) { @@ -2870,7 +2893,7 @@ double RooLagrangianMorphFunc::expectedUncertainty() const void RooLagrangianMorphFunc::printParameters() const { // print the parameters and their current values - for (auto obj : this->_operators) { + for (auto obj : _operators) { RooRealVar *param = static_cast(obj); if (!param) continue; @@ -2883,7 +2906,7 @@ void RooLagrangianMorphFunc::printParameters() const void RooLagrangianMorphFunc::printFlags() const { - for (auto flag : this->_flags) { + for (auto flag : _flags) { RooRealVar *param = static_cast(flag); if (!param) continue; @@ -2905,7 +2928,7 @@ void RooLagrangianMorphFunc::printCouplings() const //////////////////////////////////////////////////////////////////////////////// /// retrieve the list of bin boundaries -std::list *RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs, Double_t xlo, Double_t xhi) const +std::list *RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs, double xlo, double xhi) const { return this->getFunc()->binBoundaries(obs, xlo, xhi); } @@ -2913,7 +2936,7 @@ std::list *RooLagrangianMorphFunc::binBoundaries(RooAbsRealLValue &obs //////////////////////////////////////////////////////////////////////////////// /// retrieve the sample Hint -std::list *RooLagrangianMorphFunc::plotSamplingHint(RooAbsRealLValue &obs, Double_t xlo, Double_t xhi) const +std::list *RooLagrangianMorphFunc::plotSamplingHint(RooAbsRealLValue &obs, double xlo, double xhi) const { return this->getFunc()->plotSamplingHint(obs, xlo, xhi); } @@ -2935,7 +2958,7 @@ double RooLagrangianMorphFunc::evaluate() const //////////////////////////////////////////////////////////////////////////////// /// check if this PDF is a binned distribution in the given observable -Bool_t RooLagrangianMorphFunc::isBinnedDistribution(const RooArgSet &obs) const +bool RooLagrangianMorphFunc::isBinnedDistribution(const RooArgSet &obs) const { return this->getFunc()->isBinnedDistribution(obs); } @@ -2943,7 +2966,7 @@ Bool_t RooLagrangianMorphFunc::isBinnedDistribution(const RooArgSet &obs) const //////////////////////////////////////////////////////////////////////////////// /// check if observable exists in the RooArgSet (-?-) -Bool_t RooLagrangianMorphFunc::checkObservables(const RooArgSet *nset) const +bool RooLagrangianMorphFunc::checkObservables(const RooArgSet *nset) const { return this->getFunc()->checkObservables(nset); } @@ -2951,7 +2974,7 @@ Bool_t RooLagrangianMorphFunc::checkObservables(const RooArgSet *nset) const //////////////////////////////////////////////////////////////////////////////// /// Force analytical integration for the given observable -Bool_t RooLagrangianMorphFunc::forceAnalyticalInt(const RooAbsArg &arg) const +bool RooLagrangianMorphFunc::forceAnalyticalInt(const RooAbsArg &arg) const { return this->getFunc()->forceAnalyticalInt(arg); } @@ -2968,7 +2991,7 @@ Int_t RooLagrangianMorphFunc::getAnalyticalIntegralWN(RooArgSet &allVars, RooArg //////////////////////////////////////////////////////////////////////////////// /// Retrieve the matrix of coefficients -Double_t RooLagrangianMorphFunc::analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName) const +double RooLagrangianMorphFunc::analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName) const { return this->getFunc()->analyticalIntegralWN(code, normSet, rangeName); } diff --git a/roofit/roofitcore/inc/RooAbsRealLValue.h b/roofit/roofitcore/inc/RooAbsRealLValue.h index 06c214f3ec825..f2bd855334e5f 100644 --- a/roofit/roofitcore/inc/RooAbsRealLValue.h +++ b/roofit/roofitcore/inc/RooAbsRealLValue.h @@ -157,6 +157,8 @@ class RooAbsRealLValue : public RooAbsReal, public RooAbsLValue { static TH1* createHistogram(const char *name, RooArgList &vars, const char *tAxisLabel, Double_t* xlo, Double_t* xhi, Int_t* nBins) ; static TH1* createHistogram(const char *name, RooArgList &vars, const char *tAxisLabel, const RooAbsBinning** bins) ; + RooAbsReal* createIntegral(const RooArgSet& iset, const RooArgSet* nset=nullptr, const RooNumIntConfig* cfg=nullptr, const char* rangeName=nullptr) const; + protected: virtual void setValFast(Double_t value) { setVal(value) ; } diff --git a/roofit/roofitcore/inc/RooArgProxy.h b/roofit/roofitcore/inc/RooArgProxy.h index 5e25ea7696abd..f6ce48ef29cde 100644 --- a/roofit/roofitcore/inc/RooArgProxy.h +++ b/roofit/roofitcore/inc/RooArgProxy.h @@ -48,9 +48,19 @@ class RooArgProxy : public TNamed, public RooAbsProxy { /// Returns the owner of this proxy. RooAbsArg* owner() const { return _owner; } + inline Bool_t isValueServer() const { + // Returns true of contents is value server of owner + return _valueServer ; + } + inline Bool_t isShapeServer() const { + // Returns true if contents is shape server of owner + return _shapeServer ; + } + protected: - friend class RooSimultaneous ; + friend class RooRealIntegral; + RooAbsArg* _owner ; // Pointer to owner of proxy RooAbsArg* _arg ; // Pointer to content of proxy @@ -59,16 +69,6 @@ class RooArgProxy : public TNamed, public RooAbsProxy { Bool_t _isFund ; // If true proxy contains an lvalue Bool_t _ownArg ; // If true proxy owns contents - friend class RooAbsArg ; - - inline Bool_t isValueServer() const { - // Returns true of contents is value server of owner - return _valueServer ; - } - inline Bool_t isShapeServer() const { - // Returns true if contents is shape server of owner - return _shapeServer ; - } virtual Bool_t changePointer(const RooAbsCollection& newServerSet, Bool_t nameChange=kFALSE, Bool_t factoryInitMode=kFALSE) ; virtual void changeDataSet(const RooArgSet* newNormSet) ; diff --git a/roofit/roofitcore/inc/RooEffProd.h b/roofit/roofitcore/inc/RooEffProd.h index 60d74e7e46ae9..f79ef6f2aabfe 100644 --- a/roofit/roofitcore/inc/RooEffProd.h +++ b/roofit/roofitcore/inc/RooEffProd.h @@ -13,13 +13,13 @@ #define ROO_EFF_PROD #include "RooAbsPdf.h" -#include "RooAbsReal.h" #include "RooRealProxy.h" #include "RooObjCacheManager.h" class RooEffProd: public RooAbsPdf { public: // Constructors, assignment etc + RooEffProd() {} RooEffProd(const char *name, const char *title, RooAbsPdf& pdf, RooAbsReal& efficiency); RooEffProd(const RooEffProd& other, const char* name=0); diff --git a/roofit/roofitcore/res/RooFit/BatchModeDataHelpers.h b/roofit/roofitcore/res/RooFit/BatchModeDataHelpers.h index 38dbebe345228..c4ff48bc86886 100644 --- a/roofit/roofitcore/res/RooFit/BatchModeDataHelpers.h +++ b/roofit/roofitcore/res/RooFit/BatchModeDataHelpers.h @@ -30,10 +30,9 @@ class TNamed; namespace RooFit { namespace BatchModeDataHelpers { -std::map> getDataSpans(RooAbsData const &data, - std::string_view rangeName, - RooAbsCategory const *indexCat, - std::stack> &buffers); +std::map> +getDataSpans(RooAbsData const &data, std::string_view rangeName, RooAbsCategory const *indexCat, + std::stack> &buffers, bool skipZeroWeights); } // namespace BatchModeDataHelpers } // namespace RooFit diff --git a/roofit/roofitcore/res/RooFitDriver.h b/roofit/roofitcore/res/RooFitDriver.h index 2485ac0080041..83e685b1ed350 100644 --- a/roofit/roofitcore/res/RooFitDriver.h +++ b/roofit/roofitcore/res/RooFitDriver.h @@ -50,7 +50,7 @@ class RooFitDriver { RooFit::BatchModeOption batchMode = RooFit::BatchModeOption::Cpu); void setData(RooAbsData const &data, std::string_view rangeName = "", - RooAbsCategory const *indexCatForSplitting = nullptr); + RooAbsCategory const *indexCatForSplitting = nullptr, bool skipZeroWeights = false); void setData(DataSpansMap const &dataSpans); ~RooFitDriver(); diff --git a/roofit/roofitcore/src/BatchModeDataHelpers.cxx b/roofit/roofitcore/src/BatchModeDataHelpers.cxx index 0d8df16f90a5b..f281b5416c502 100644 --- a/roofit/roofitcore/src/BatchModeDataHelpers.cxx +++ b/roofit/roofitcore/src/BatchModeDataHelpers.cxx @@ -22,8 +22,8 @@ namespace { -void splitByCategory(std::map> &dataSpans, RooAbsCategory const &category, - std::stack> &buffers) +void splitByCategory(std::map> &dataSpans, + RooAbsCategory const &category, std::stack> &buffers) { std::stack> oldBuffers; std::swap(buffers, oldBuffers); @@ -71,28 +71,33 @@ void splitByCategory(std::map> &d } // namespace //////////////////////////////////////////////////////////////////////////////// -// Extract all content from a RooFit datasets as a map of spans. -// Spans with the weights and squared weights will be also stored in the map, -// keyed with the names `_weight` and the `_weight_sumW2`. If the dataset is -// unweighted, these weight spans will only contain the single value `1.0`. -// Entries with zero weight will be skipped. -// -// \return A `std::map` with spans keyed to name pointers. -// \param[in] data The input dataset. -// \param[in] rangeName Select only entries from the data in a given range -// (empty string for no range). -// \param[in] indexCat If not `nullptr`, each span is spit up by this category, -// with the new names prefixed by the category component name -// surrounded by underscores. For example, if you have a category -// with `signal` and `control` samples, the span for a variable `x` -// will be split in two spans `_signal_x` and `_control_x`. -// \param[in] buffers Pass here an empty stack of `double` vectors, which will -// be used as memory for the data if the memory in the dataset -// object can't be used directly (e.g. because you used the range -// selection or the splitting by categories). +/// Extract all content from a RooFit datasets as a map of spans. +/// Spans with the weights and squared weights will be also stored in the map, +/// keyed with the names `_weight` and the `_weight_sumW2`. If the dataset is +/// unweighted, these weight spans will only contain the single value `1.0`. +/// Entries with zero weight will be skipped. +/// +/// \return A `std::map` with spans keyed to name pointers. +/// \param[in] data The input dataset. +/// \param[in] rangeName Select only entries from the data in a given range +/// (empty string for no range). +/// \param[in] indexCat If not `nullptr`, each span is spit up by this category, +/// with the new names prefixed by the category component name +/// surrounded by underscores. For example, if you have a category +/// with `signal` and `control` samples, the span for a variable `x` +/// will be split in two spans `_signal_x` and `_control_x`. +/// \param[in] buffers Pass here an empty stack of `double` vectors, which will +/// be used as memory for the data if the memory in the dataset +/// object can't be used directly (e.g. because you used the range +/// selection or the splitting by categories). +/// \param[in] skipZeroWeights Skip entries with zero weight when filling the +/// data spans. Be very careful with enabling it, because the user +/// might not expect that the batch results are not aligned with the +/// original dataset anymore! std::map> RooFit::BatchModeDataHelpers::getDataSpans(RooAbsData const &data, std::string_view rangeName, - RooAbsCategory const *indexCat, std::stack> &buffers) + RooAbsCategory const *indexCat, std::stack> &buffers, + bool skipZeroWeights) { std::map> dataSpans; // output variable @@ -137,7 +142,7 @@ RooFit::BatchModeDataHelpers::getDataSpans(RooAbsData const &data, std::string_v buffer.reserve(nEvents); bufferSumW2.reserve(nEvents); for (std::size_t i = 0; i < nEvents; ++i) { - if (weight[i] != 0) { + if (!skipZeroWeights || weight[i] != 0) { buffer.push_back(weight[i]); bufferSumW2.push_back(weightSumW2[i]); ++nNonZeroWeight; diff --git a/roofit/roofitcore/src/BatchModeHelpers.cxx b/roofit/roofitcore/src/BatchModeHelpers.cxx index 5db0dad64ce5a..ea78c4bfca9f7 100644 --- a/roofit/roofitcore/src/BatchModeHelpers.cxx +++ b/roofit/roofitcore/src/BatchModeHelpers.cxx @@ -34,22 +34,21 @@ using ROOT::Experimental::RooNLLVarNew; namespace { -std::unique_ptr prepareSimultaneousModelForBatchMode(RooSimultaneous &simPdf, RooArgSet &observables, - bool isExtended, std::string const &rangeName, - bool doOffset) +std::unique_ptr createSimultaneousNLL(std::unique_ptr &&simPdf, RooArgSet &observables, + bool isExtended, std::string const &rangeName, bool doOffset) { // Prepare the NLLTerms for each component RooArgList nllTerms; RooArgSet newObservables; - for (auto const &catItem : simPdf.indexCat()) { + for (auto const &catItem : simPdf->indexCat()) { auto const &catName = catItem.first; - if (RooAbsPdf *pdf = simPdf.getPdf(catName.c_str())) { - auto nllName = std::string("nll_") + pdf->GetName(); - auto *nll = - new RooNLLVarNew(nllName.c_str(), nllName.c_str(), *pdf, observables, isExtended, rangeName, doOffset); + if (RooAbsPdf *pdf = simPdf->getPdf(catName.c_str())) { + auto name = std::string("nll_") + pdf->GetName(); + auto nll = std::make_unique(name.c_str(), name.c_str(), *pdf, observables, isExtended, rangeName, + doOffset); // Rename the observables and weights newObservables.add(nll->prefixObservableAndWeightNames(std::string("_") + catName + "_")); - nllTerms.add(*nll); + nllTerms.addOwned(std::move(nll)); } } @@ -57,7 +56,10 @@ std::unique_ptr prepareSimultaneousModelForBatchMode(RooSimultaneous observables.add(newObservables); // Time to sum the NLLs - return std::make_unique("mynll", "mynll", nllTerms, true); + auto nll = std::make_unique("mynll", "mynll", nllTerms); + nll->addOwnedComponents(std::move(simPdf)); + nll->addOwnedComponents(std::move(nllTerms)); + return nll; } } // namespace @@ -97,12 +99,16 @@ RooFit::BatchModeHelpers::createNLL(RooAbsPdf &pdf, RooAbsData &data, std::uniqu RooArgList nllTerms; + RooAbsCategory const *indexCatForSplitting = nullptr; if (auto simPdf = dynamic_cast(&finalPdf)) { - auto *simPdfClone = static_cast(simPdf->cloneTree()); + RooArgSet parameters; + finalPdf.getParameters(data.get(), parameters); + std::unique_ptr simPdfClone{static_cast(simPdf->cloneTree())}; + indexCatForSplitting = &simPdfClone->indexCat(); + simPdfClone->recursiveRedirectServers(parameters); simPdfClone->wrapPdfsInBinSamplingPdfs(data, integrateOverBinsPrecision); // Warning! This mutates "observables" - nllTerms.addOwned( - prepareSimultaneousModelForBatchMode(*simPdfClone, observables, isExtended, rangeName, doOffset)); + nllTerms.addOwned(createSimultaneousNLL(std::move(simPdfClone), observables, isExtended, rangeName, doOffset)); } else { nllTerms.addOwned(std::make_unique("RooNLLVarNew", "RooNLLVarNew", finalPdf, observables, isExtended, rangeName, doOffset)); @@ -116,16 +122,8 @@ RooFit::BatchModeHelpers::createNLL(RooAbsPdf &pdf, RooAbsData &data, std::uniqu nll->addOwnedComponents(std::move(binSamplingPdfs)); nll->addOwnedComponents(std::move(nllTerms)); - if (auto simPdf = dynamic_cast(&finalPdf)) { - RooArgSet parameters; - pdf.getParameters(data.get(), parameters); - nll->recursiveRedirectServers(parameters); - driver = std::make_unique(*nll, observables, batchMode); - driver->setData(data, rangeName, &simPdf->indexCat()); - } else { - driver = std::make_unique(*nll, observables, batchMode); - driver->setData(data, rangeName); - } + driver = std::make_unique(*nll, observables, batchMode); + driver->setData(data, rangeName, indexCatForSplitting, /*skipZeroWeights=*/true); // Set the fitrange attribute so that RooPlot can automatically plot the fitting range by default if (!rangeName.empty()) { @@ -195,10 +193,9 @@ namespace { class RooAbsRealWrapper final : public RooAbsReal { public: - RooAbsRealWrapper() {} - RooAbsRealWrapper(RooFitDriver &driver, RooArgSet const &observables, bool ownsDriver) - : RooAbsReal{"RooFitDriverWrapper", "RooFitDriverWrapper"}, _driver{&driver}, - _topNode("topNode", "top node", this, _driver->topNode()), _ownsDriver{ownsDriver} + RooAbsRealWrapper(std::unique_ptr driver, RooArgSet const &observables) + : RooAbsReal{"RooFitDriverWrapper", "RooFitDriverWrapper"}, _driver{std::move(driver)}, + _topNode("topNode", "top node", this, _driver->topNode()) { _driver->topNode().getParameters(&observables, _parameters, true); } @@ -209,20 +206,16 @@ class RooAbsRealWrapper final : public RooAbsReal { { } - ~RooAbsRealWrapper() override - { - if (_ownsDriver) - delete _driver; - } - TObject *clone(const char *newname) const override { return new RooAbsRealWrapper(*this, newname); } double defaultErrorLevel() const override { return _driver->topNode().defaultErrorLevel(); } - bool getParameters(const RooArgSet * /*observables*/, RooArgSet &outputSet, - bool /*stripDisconnected=true*/) const override + bool getParameters(const RooArgSet *observables, RooArgSet &outputSet, bool /*stripDisconnected*/) const override { outputSet.add(_parameters); + if (observables) { + outputSet.remove(*observables); + } return false; } @@ -237,10 +230,9 @@ class RooAbsRealWrapper final : public RooAbsReal { double evaluate() const override { return _driver ? _driver->getVal() : 0.0; } private: - RooFitDriver *_driver = nullptr; + std::shared_ptr _driver; RooRealProxy _topNode; RooArgSet _parameters; - bool _ownsDriver; }; } // namespace @@ -251,5 +243,5 @@ std::unique_ptr RooFit::BatchModeHelpers::makeDriverAbsRealWrapper(std::unique_ptr driver, RooArgSet const &observables) { - return std::unique_ptr{new RooAbsRealWrapper{*driver.release(), observables, true}}; + return std::make_unique(std::move(driver), observables); } diff --git a/roofit/roofitcore/src/NormalizationHelpers.cxx b/roofit/roofitcore/src/NormalizationHelpers.cxx index 3e1ab11039c20..9f532b7205285 100644 --- a/roofit/roofitcore/src/NormalizationHelpers.cxx +++ b/roofit/roofitcore/src/NormalizationHelpers.cxx @@ -171,8 +171,9 @@ void treeNodeServerListAndNormSets(const RooAbsArg &arg, RooAbsCollection &list, } auto differentSet = arg.fillNormSetForServer(normSet, *server); - if (differentSet) + if (differentSet) { differentSet->sort(); + } auto &serverNormSet = differentSet ? *differentSet : normSet; @@ -220,14 +221,17 @@ std::vector> unfoldIntegrals(RooAbsArg const &topNode treeNodeServerListAndNormSets(topNode, nodes, normSetSorted, normSets, checker); // Clean normsets of the variables that the arg does not depend on - // std::unordered_map,bool> dependsResults; for (auto &item : normSets) { if (!item.second || item.second->empty()) continue; auto actualNormSet = new RooArgSet{}; for (auto *narg : *item.second) { if (checker.dependsOn(item.first, narg)) - actualNormSet->add(*narg); + // Add the arg from the actual node list in the computation graph. + // Like this, we don't accidentally add internal variable clones + // that the client args returned. Looking this up is fast because + // of the name pointer hash map optimization. + actualNormSet->add(*nodes.find(*narg)); } delete item.second; item.second = actualNormSet; diff --git a/roofit/roofitcore/src/RooAbsRealLValue.cxx b/roofit/roofitcore/src/RooAbsRealLValue.cxx index a734ff3bcd3f6..fa68fbcfe00f9 100644 --- a/roofit/roofitcore/src/RooAbsRealLValue.cxx +++ b/roofit/roofitcore/src/RooAbsRealLValue.cxx @@ -1059,3 +1059,14 @@ Bool_t RooAbsRealLValue::isJacobianOK(const RooArgSet&) const // always returns true (i.e. jacobian is constant) return kTRUE ; } + + +RooAbsReal* RooAbsRealLValue::createIntegral(const RooArgSet&, const RooArgSet*, const RooNumIntConfig*, const char*) const +{ + std::stringstream errStream; + errStream << "Attempting to integrate the " << ClassName() << " \"" << GetName() + << "\", but integrating a RooAbsRealLValue is not allowed!"; + const std::string errString = errStream.str(); + coutE(InputArguments) << errString << std::endl; + throw std::runtime_error(errString); +} diff --git a/roofit/roofitcore/src/RooEffProd.cxx b/roofit/roofitcore/src/RooEffProd.cxx index 082acbaa38ae8..7d262800e81d7 100644 --- a/roofit/roofitcore/src/RooEffProd.cxx +++ b/roofit/roofitcore/src/RooEffProd.cxx @@ -24,8 +24,6 @@ #include "RooFit.h" #include "RooEffProd.h" #include "RooEffGenContext.h" -#include "RooNameReg.h" -#include "RooRealVar.h" //////////////////////////////////////////////////////////////////////////////// diff --git a/roofit/roofitcore/src/RooFitDriver.cxx b/roofit/roofitcore/src/RooFitDriver.cxx index 3a0e74c493dcc..5d316f91a00cf 100644 --- a/roofit/roofitcore/src/RooFitDriver.cxx +++ b/roofit/roofitcore/src/RooFitDriver.cxx @@ -96,8 +96,6 @@ struct NodeInfo { RooBatchCompute::dispatchCUDA->deleteCudaEvent(eventStart); if (stream) RooBatchCompute::dispatchCUDA->deleteCudaStream(stream); - - absArg->setDataToken(originalDataToken); } }; @@ -186,9 +184,10 @@ RooFitDriver::RooFitDriver(const RooAbsReal &absReal, RooArgSet const &normSet, } void RooFitDriver::setData(RooAbsData const &data, std::string_view rangeName, - RooAbsCategory const *indexCatForSplitting) + RooAbsCategory const *indexCatForSplitting, bool skipZeroWeights) { - setData(RooFit::BatchModeDataHelpers::getDataSpans(data, rangeName, indexCatForSplitting, _vectorBuffers)); + setData(RooFit::BatchModeDataHelpers::getDataSpans(data, rangeName, indexCatForSplitting, _vectorBuffers, + skipZeroWeights)); } void RooFitDriver::setData(DataSpansMap const &dataSpans) @@ -245,6 +244,10 @@ void RooFitDriver::setData(DataSpansMap const &dataSpans) RooFitDriver::~RooFitDriver() { + for (auto &info : _nodes) { + info.absArg->setDataToken(info.originalDataToken); + } + if (_batchMode == RooFit::BatchModeOption::Cuda) { RooBatchCompute::dispatchCUDA->cudaFree(_cudaMemDataset); } diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index 6db23dd27fb1d..1db6a83c25c89 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -601,14 +601,12 @@ void RooProdPdf::factorizeProduct(const RooArgSet& normSet, const RooArgSet& int }; // Reduce pdfNSet to actual dependents - if (0 == strcmp("nset", pdfNSetOrig.GetName())) { - getObservablesOfCurrentPdf(pdfNSet, pdfNSetOrig); - } else if (0 == strcmp("cset", pdfNSetOrig.GetName())) { + if (0 == strcmp("cset", pdfNSetOrig.GetName())) { getObservablesOfCurrentPdf(pdfNSet, normSet); removeCommon(pdfNSet, pdfNSetOrig.get()); pdfCSet = pdfNSetOrig.get(); } else { - // Legacy mode. Interpret at NSet for backward compatibility + // Interpret at NSet getObservablesOfCurrentPdf(pdfNSet, pdfNSetOrig); } @@ -2346,7 +2344,18 @@ std::unique_ptr RooProdPdf::fillNormSetForServer(RooArgSet const& nor if(normSet.empty()) return nullptr; auto * pdfNset = findPdfNSet(static_cast(server)); if (pdfNset && !pdfNset->empty()) { - return std::make_unique(*pdfNset); + if (0 == strcmp("cset", pdfNset->GetName())) { + // If the name of the normalization set is "cset", it doesn't contain the + // normalization set but the conditional observables that should *not* be + // normalized over. + auto out = std::make_unique(normSet); + RooArgSet common; + out->selectCommon(*pdfNset, common); + out->remove(common); + return out; + } else { + return std::make_unique(*pdfNset); + } } else { return nullptr; } diff --git a/roofit/roofitcore/src/RooRealIntegral.cxx b/roofit/roofitcore/src/RooRealIntegral.cxx index ef4d157b6fb2a..610179039ef73 100644 --- a/roofit/roofitcore/src/RooRealIntegral.cxx +++ b/roofit/roofitcore/src/RooRealIntegral.cxx @@ -104,8 +104,7 @@ RooRealIntegral::RooRealIntegral(const char *name, const char *title, _anaList("!anaList","Variables to be integrated analytically",this,kFALSE,kFALSE), _jacList("!jacList","Jacobian product term",this,kFALSE,kFALSE), _facList("!facList","Variables independent of function",this,kFALSE,kTRUE), - _function("!func","Function to be integrated",this, - const_cast(function),kFALSE,kFALSE), + _function("!func","Function to be integrated",this,false,false), _iconfig((RooNumIntConfig*)config), _sumCat("!sumCat","SuperCategory for summation",this,kFALSE,kFALSE), _mode(0), @@ -416,7 +415,7 @@ RooRealIntegral::RooRealIntegral(const char *name, const char *title, RooArgSet anIntDepList ; RooArgSet *anaSet = new RooArgSet( _anaList, Form("UniqueCloneOf_%s",_anaList.GetName())); - _mode = ((RooAbsReal&)_function.arg()).getAnalyticalIntegralWN(anIntOKDepList,*anaSet,_funcNormSet,RooNameReg::str(_rangeName)) ; + _mode = function.getAnalyticalIntegralWN(anIntOKDepList,*anaSet,_funcNormSet,RooNameReg::str(_rangeName)) ; _anaList.removeAll() ; _anaList.add(*anaSet); delete anaSet; @@ -549,9 +548,13 @@ RooRealIntegral::RooRealIntegral(const char *name, const char *title, // Purely analytical integration _intOperMode = Analytic ; } else { - // No integration performed + // No integration performed, where the function is a direct value server _intOperMode = PassThrough ; + _function._valueServer = true; } + // We are only setting the function proxy now that it's clear if it's a value + // server or not. + _function.setArg(const_cast(function)); // Determine auto-dirty status autoSelectDirtyMode() ; @@ -894,6 +897,10 @@ Double_t RooRealIntegral::evaluate() const case PassThrough: { + // In pass through mode, the RooRealIntegral should have registered the + // function as a value server, because we directly depend on its value. + assert(_function.isValueServer()); + //setDirtyInhibit(kTRUE) ; retVal= _function.arg().getVal(_funcNormSet) ; //setDirtyInhibit(kFALSE) ; diff --git a/roofit/roofitcore/test/CMakeLists.txt b/roofit/roofitcore/test/CMakeLists.txt index 17f9d9bab0592..e9fe3c83e6622 100644 --- a/roofit/roofitcore/test/CMakeLists.txt +++ b/roofit/roofitcore/test/CMakeLists.txt @@ -26,7 +26,7 @@ ROOT_ADD_GTEST(testRooAbsPdf testRooAbsPdf.cxx LIBRARIES RooFitCore RooFit) ROOT_ADD_GTEST(testRooAbsCollection testRooAbsCollection.cxx LIBRARIES RooFitCore) ROOT_ADD_GTEST(testRooDataSet testRooDataSet.cxx LIBRARIES Tree RooFitCore) ROOT_ADD_GTEST(testRooFormula testRooFormula.cxx LIBRARIES RooFitCore) -ROOT_ADD_GTEST(testRooProdPdf testRooProdPdf.cxx LIBRARIES RooFitCore) +ROOT_ADD_GTEST(testRooProdPdf testRooProdPdf.cxx LIBRARIES RooFitCore RooFit) ROOT_ADD_GTEST(testProxiesAndCategories testProxiesAndCategories.cxx LIBRARIES RooFitCore COPY_TO_BUILDDIR ${CMAKE_CURRENT_SOURCE_DIR}/testProxiesAndCategories_1.root @@ -43,7 +43,6 @@ ROOT_ADD_GTEST(testRooRealVar testRooRealVar.cxx LIBRARIES RooFitCore if(NOT MSVC OR win_broken_tests) ROOT_ADD_GTEST(testTestStatistics testTestStatistics.cxx LIBRARIES RooFitCore) endif() -ROOT_ADD_GTEST(testRooProductPdf testRooProductPdf.cxx LIBRARIES RooFitCore) ROOT_ADD_GTEST(testNaNPacker testNaNPacker.cxx LIBRARIES RooFitCore) ROOT_ADD_GTEST(testRooSimultaneous testRooSimultaneous.cxx LIBRARIES RooFitCore RooFit) ROOT_ADD_GTEST(testRooGradMinimizerFcn testRooGradMinimizerFcn.cxx LIBRARIES RooFitCore) @@ -54,7 +53,7 @@ ROOT_ADD_GTEST(testGlobalObservables testGlobalObservables.cxx LIBRARIES RooFit) ROOT_ADD_GTEST(testRooPolyFunc testRooPolyFunc.cxx LIBRARIES Gpad RooFit) ROOT_ADD_GTEST(testSumW2Error testSumW2Error.cxx LIBRARIES Gpad RooFitCore) if (roofit_multiprocess) - ROOT_ADD_GTEST(testTestStatisticsPlot TestStatistics/testPlot.cpp LIBRARIES RooFitMultiProcess RooFitCore RooFit + ROOT_ADD_GTEST(testTestStatisticsPlot TestStatistics/testPlot.cpp LIBRARIES RooFitMultiProcess RooFitCore RooFit COPY_TO_BUILDDIR ${CMAKE_CURRENT_SOURCE_DIR}/TestStatistics/TestStatistics_ref.root) ROOT_ADD_GTEST(testLikelihoodGradientJob TestStatistics/testLikelihoodGradientJob.cpp LIBRARIES RooFitMultiProcess RooFitCore RooFit RooStats m) target_include_directories(testLikelihoodGradientJob PRIVATE ${RooFitCore_MultiProcess_TestStatistics_INCLUDE_DIR}) diff --git a/roofit/roofitcore/test/testRooProdPdf.cxx b/roofit/roofitcore/test/testRooProdPdf.cxx index e14b997d44efc..f326871c91dc4 100644 --- a/roofit/roofitcore/test/testRooProdPdf.cxx +++ b/roofit/roofitcore/test/testRooProdPdf.cxx @@ -1,18 +1,66 @@ // Tests for the RooProdPdf -// Author: Jonas Rembser, CERN, June 2021 +// Authors: Stephan Hageboeck, CERN 02/2019 +// Jonas Rembser, CERN, June 2021 -#include "RooArgList.h" -#include "RooArgSet.h" -#include "RooGenericPdf.h" -#include "RooProdPdf.h" -#include "RooRealVar.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "gtest/gtest.h" +#include #include #include #include +class TestProdPdf : public ::testing::Test { +protected: + TestProdPdf() : Test() + { + datap.reset(prod.generate(RooArgSet(x), 1000)); + a.setConstant(true); + } + + constexpr static double bTruth = -0.5; + + RooRealVar x{"x", "x", 2., 0., 5.}; + RooRealVar a{"a", "a", -0.2, -5., 0.}; + RooRealVar b{"b", "b", bTruth, -5., 0.}; + + RooGenericPdf c1{"c1", "exp(x[0]*x[1])", RooArgSet(x, a)}; + RooGenericPdf c2{"c2", "exp(x[0]*x[1])", RooArgSet(x, b)}; + RooProdPdf prod{"mypdf", "mypdf", RooArgList(c1, c2)}; + std::unique_ptr datap{nullptr}; +}; + +TEST_F(TestProdPdf, CachingOpt2) +{ + prod.fitTo(*datap, RooFit::Optimize(2), RooFit::PrintLevel(-1)); + EXPECT_LT(fabs(b.getVal() - bTruth), b.getError() * 1.1) + << "b=" << b.getVal() << " +- " << b.getError() << " doesn't match truth value with O2."; +} + +TEST_F(TestProdPdf, CachingOpt1) +{ + prod.fitTo(*datap, RooFit::Optimize(1), RooFit::PrintLevel(-1)); + EXPECT_LT(fabs(b.getVal() - bTruth), b.getError() * 1.1) + << "b=" << b.getVal() << " +- " << b.getError() << " doesn't match truth value with O1."; +} + +TEST_F(TestProdPdf, CachingOpt0) +{ + prod.fitTo(*datap, RooFit::Optimize(0), RooFit::PrintLevel(-1)); + EXPECT_LT(fabs(b.getVal() - bTruth), b.getError() * 1.1) + << "b=" << b.getVal() << " +- " << b.getError() << " doesn't match truth value with O0."; +} + std::vector> allPossibleSubset(RooAbsCollection const &arr) { std::vector> out; @@ -84,3 +132,45 @@ TEST(RooProdPdf, TestGetPartIntList) // RooProdPdf changes. EXPECT_EQ(hashRooProduct(prod), 2448666198); } + +TEST(RooProdPdf, TestDepsAreCond) +{ + using namespace RooFit; + + RooRealVar x("x", "", 0, 1); + RooRealVar xErr("xErr", "", 0.0001, 0.1); + + RooGaussModel gm("gm", "", x, RooConst(0), xErr); + + RooRealVar tau("tau", "", 0.4, 0, 1); + RooDecay decayPdf("decayPdf", "", x, tau, gm, RooDecay::SingleSided); + + RooGamma errPdf("errPdf", "", xErr, RooConst(4), RooConst(0.005), RooConst(0)); + + // What we want: decayPdf(x|xErr)*errPdf(xErr): + RooProdPdf pdf1("pdf1", "", RooArgSet(errPdf), Conditional(decayPdf, x, false)); + + // Should be the same as pdf1: + RooProdPdf pdf2("pdf2", "", RooArgSet(errPdf), Conditional(decayPdf, xErr, true)); + + std::unique_ptr data{pdf1.generate(RooArgSet(x, xErr), NumEvents(10000))}; + + auto resetParameters = [&]() { + tau.setVal(0.4); + tau.setError(0.0); + }; + + using ResultPtr = std::unique_ptr; + + ResultPtr result1{pdf1.fitTo(*data, Save(), BatchMode("off"), PrintLevel(-1))}; + resetParameters(); + ResultPtr result2{pdf1.fitTo(*data, Save(), BatchMode("cpu"), PrintLevel(-1))}; + resetParameters(); + ResultPtr result3{pdf2.fitTo(*data, Save(), BatchMode("off"), PrintLevel(-1))}; + resetParameters(); + ResultPtr result4{pdf2.fitTo(*data, Save(), BatchMode("cpu"), PrintLevel(-1))}; + + EXPECT_TRUE(result2->isIdentical(*result1)) << "batchmode fit is inconsistent!"; + EXPECT_TRUE(result3->isIdentical(*result1)) << "alternative model fit is inconsistent!"; + EXPECT_TRUE(result4->isIdentical(*result1)) << "alternative model batchmode fit is inconsistent!"; +} diff --git a/roofit/roofitcore/test/testRooProductPdf.cxx b/roofit/roofitcore/test/testRooProductPdf.cxx deleted file mode 100644 index 04208de2d5fd8..0000000000000 --- a/roofit/roofitcore/test/testRooProductPdf.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Tests for the RooProdPdf -// Authors: Stephan Hageboeck, CERN 02/2019 - -#include "RooProdPdf.h" -#include "RooRealVar.h" -#include "RooGenericPdf.h" -#include "RooDataSet.h" - -#include "gtest/gtest.h" - -class TestProdPdf : public ::testing::Test { -protected: - TestProdPdf() : - Test() - { - datap.reset(prod.generate(RooArgSet(x), 1000)); - a.setConstant(true); - } - - ~TestProdPdf() { - - } - - constexpr static double bTruth = -0.5; - - RooRealVar x{"x", "x", 2., 0., 5.}; - RooRealVar a{"a", "a", -0.2, -5., 0.}; - RooRealVar b{"b", "b", bTruth, -5., 0.}; - - RooGenericPdf c1{"c1", "exp(x*a)", RooArgSet(x,a)}; - RooGenericPdf c2{"c2", "exp(x*b)", RooArgSet(x,b)}; - RooProdPdf prod{"mypdf", "mypdf", RooArgList(c1,c2)}; - std::unique_ptr datap{nullptr}; -}; - -TEST_F(TestProdPdf, CachingOpt2) { - prod.fitTo(*datap, RooFit::Optimize(2), RooFit::PrintLevel(-1)); - EXPECT_LT(fabs(b.getVal() - bTruth), b.getError()*1.1) << "b=" << b.getVal() - << " +- " << b.getError() << " doesn't match truth value with O2."; -} - -TEST_F(TestProdPdf, CachingOpt1) { - prod.fitTo(*datap, RooFit::Optimize(1), RooFit::PrintLevel(-1)); - EXPECT_LT(fabs(b.getVal() - bTruth), b.getError()*1.1) << "b=" << b.getVal() - << " +- " << b.getError() << " doesn't match truth value with O1."; -} - -TEST_F(TestProdPdf, CachingOpt0) { - prod.fitTo(*datap, RooFit::Optimize(0), RooFit::PrintLevel(-1)); - EXPECT_LT(fabs(b.getVal() - bTruth), b.getError()*1.1) << "b=" << b.getVal() - << " +- " << b.getError() << " doesn't match truth value with O0."; -} diff --git a/roofit/roofitcore/test/testRooWrapperPdf.cxx b/roofit/roofitcore/test/testRooWrapperPdf.cxx index fa8c448ed75fa..b4848833409ae 100644 --- a/roofit/roofitcore/test/testRooWrapperPdf.cxx +++ b/roofit/roofitcore/test/testRooWrapperPdf.cxx @@ -22,9 +22,10 @@ TEST(RooWrapperPdf, Basics) RooRealVar a0("a0", "a0", 0.1, 0.1, 10.); RooRealVar a1("a1", "a1", -0.01, -2.1, 0.); RooRealVar a2("a2", "a2", 0.01, 0.01, 5.); + RooProduct xId("xId", "x", RooArgList(x)); RooProduct xSq("xSq", "x^2", RooArgList(x, x)); RooConstVar one("one", "one", 1.); - RooRealSumFunc pol("pol", "pol", RooArgList(one, x, xSq), RooArgList(a0, a1, a2)); + RooRealSumFunc pol("pol", "pol", RooArgList(one, xId, xSq), RooArgList(a0, a1, a2)); RooWrapperPdf polPdf("polPdf", "polynomial PDF", pol); @@ -52,15 +53,16 @@ TEST(RooWrapperPdf, GenerateAndFit) { RooRealVar a0("a0", "a0", 0.1); RooRealVar a1("a1", "a1", -0.01); RooRealVar a2("a2", "a2", 0.01, 0.001, 5.); + RooProduct xId("xId", "x", RooArgList(x)); RooProduct xSq("xSq", "x^2", RooArgList(x, x)); RooConstVar one("one", "one", 1.); - RooRealSumFunc pol("pol", "pol", RooArgList(one, x, xSq), RooArgList(a0, a1, a2)); + RooRealSumFunc pol("pol", "pol", RooArgList(one, xId, xSq), RooArgList(a0, a1, a2)); RooWrapperPdf polPdf("polPdf", "polynomial PDF", pol); auto data = polPdf.generate(x, 50000); a2.setVal(0.02); - auto result = polPdf.fitTo(*data, RooFit::Save()); + auto result = polPdf.fitTo(*data, RooFit::Save(), RooFit::PrintLevel(-1)); EXPECT_EQ(result->status(), 0) << "Fit converged."; EXPECT_LT(fabs(a2.getVal()-0.01), a2.getError());