Skip to content

Commit 2f75c41

Browse files
committed
[RF] Change AddPdf BatchMode coef updating to use values from dataMap
So far, the raw coefficient values for the RooAddPdf in BatchMode were still obstained with the `getVal()` interface. This is redundant, because as value servers the coefficients are also evaluated by the RooFitDriver. This caused slowdowns in more complicated fits, like the ATLAS Higgs combination. This commit solves that problem by not evaluating the `_coefList` directly with `getVal()` in `updateCoefficients()`. Instead, the raw coeficients will be passed to the function via the already existing `_coefCache`, which is also used as an output parameter. In the BatchMode, we can then just fill the initial `_coefCache` with the values from the data map.
1 parent 9604027 commit 2f75c41

File tree

5 files changed

+85
-54
lines changed

5 files changed

+85
-54
lines changed

roofit/roofitcore/inc/RooAddPdf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class RooAddPdf : public RooAbsPdf {
106106

107107
mutable RooObjCacheManager _projCacheMgr ; //! Manager of cache with coefficient projections and transformations
108108
AddCacheElem* getProjCache(const RooArgSet* nset, const RooArgSet* iset=nullptr, const char* rangeName=nullptr) const ;
109-
void updateCoefficients(AddCacheElem& cache, const RooArgSet* nset) const ;
109+
void updateCoefficients(AddCacheElem& cache, const RooArgSet* nset, bool syncCoefValues=true) const ;
110110

111111

112112
friend class RooAddGenContext ;

roofit/roofitcore/src/RooAddHelpers.cxx

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include <RooRealIntegral.h>
1818
#include <RooRealVar.h>
1919

20+
////////////////////////////////////////////////////////////////////////////////
21+
/// Create a RooAddPdf cache element for a given normalization set and
22+
/// projection configuration.
23+
2024
AddCacheElem::AddCacheElem(RooAbsPdf const &addPdf, RooArgList const &pdfList, RooArgList const &coefList,
2125
const RooArgSet *nset, const RooArgSet *iset, const char *rangeName, bool projectCoefs,
2226
RooArgSet const &refCoefNorm, TNamed const *refCoefRangeName, int verboseEval)
@@ -110,12 +114,12 @@ AddCacheElem::AddCacheElem(RooAbsPdf const &addPdf, RooArgList const &pdfList, R
110114
<< (refCoefRangeName ? RooNameReg::str(refCoefRangeName) : "") << std::endl;
111115

112116
// Recalculate projection integrals of PDFs
113-
for (auto *thePdf : static_range_cast<const RooAbsPdf *>(pdfList)) {
117+
for (auto *pdf : static_range_cast<const RooAbsPdf *>(pdfList)) {
114118

115119
// Calculate projection integral
116120
std::unique_ptr<RooAbsReal> pdfProj;
117121
if (!nset2.equals(refCoefNorm)) {
118-
pdfProj = std::unique_ptr<RooAbsReal>{thePdf->createIntegral(nset2, refCoefNorm, addPdf.normRange())};
122+
pdfProj = std::unique_ptr<RooAbsReal>{pdf->createIntegral(nset2, refCoefNorm, addPdf.normRange())};
119123
pdfProj->setOperMode(addPdf.operMode());
120124
oocxcoutD(&addPdf, Caching) << addPdf.ClassName() << "(" << addPdf.GetName() << ")::getPC nset2(" << nset2
121125
<< ")!=_refCoefNorm(" << refCoefNorm << ") --> pdfProj = " << pdfProj->GetName()
@@ -128,11 +132,11 @@ AddCacheElem::AddCacheElem(RooAbsPdf const &addPdf, RooArgList const &pdfList, R
128132

129133
// Calculation optional supplemental normalization term
130134
RooArgSet supNormSet(refCoefNorm);
131-
auto deps = std::unique_ptr<RooArgSet>{thePdf->getParameters(RooArgSet())};
135+
auto deps = std::unique_ptr<RooArgSet>{pdf->getParameters(RooArgSet())};
132136
supNormSet.remove(*deps, true, true);
133137

134138
std::unique_ptr<RooAbsReal> snorm;
135-
auto name = std::string(addPdf.GetName()) + "_" + thePdf->GetName() + "_ProjSupNorm";
139+
auto name = std::string(addPdf.GetName()) + "_" + pdf->GetName() + "_ProjSupNorm";
136140
if (!supNormSet.empty() && !nset2.equals(refCoefNorm)) {
137141
snorm = std::make_unique<RooRealIntegral>(name.c_str(), "Projection Supplemental normalization integral",
138142
RooRealConstant::value(1.0), supNormSet);
@@ -155,7 +159,7 @@ AddCacheElem::AddCacheElem(RooAbsPdf const &addPdf, RooArgList const &pdfList, R
155159

156160
// ----------
157161
RooArgSet tmpObs;
158-
thePdf->getObservables(&refCoefNorm, tmpObs);
162+
pdf->getObservables(&refCoefNorm, tmpObs);
159163
bool allIdent = true;
160164
for (auto *rvarg : dynamic_range_cast<RooRealVar *>(tmpObs)) {
161165
if (rvarg) {
@@ -170,9 +174,8 @@ AddCacheElem::AddCacheElem(RooAbsPdf const &addPdf, RooArgList const &pdfList, R
170174
if (refCoefRangeName && !refCoefNorm.empty() && !allIdent) {
171175

172176
RooArgSet tmp;
173-
thePdf->getObservables(&refCoefNorm, tmp);
174-
rangeProj1 =
175-
std::unique_ptr<RooAbsReal>{thePdf->createIntegral(tmp, tmp, RooNameReg::str(refCoefRangeName))};
177+
pdf->getObservables(&refCoefNorm, tmp);
178+
rangeProj1 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(tmp, tmp, RooNameReg::str(refCoefRangeName))};
176179

177180
// rangeProj1->setOperMode(operMode()) ;
178181
oocxcoutD(&addPdf, Caching) << " " << addPdf.ClassName() << "::syncCoefProjList(" << addPdf.GetName()
@@ -187,14 +190,14 @@ AddCacheElem::AddCacheElem(RooAbsPdf const &addPdf, RooArgList const &pdfList, R
187190
<< " nset = " << (nset ? *nset : RooArgSet()) << std::endl;
188191
if (rangeName && !refCoefNorm.empty()) {
189192

190-
rangeProj2 = std::unique_ptr<RooAbsReal>{thePdf->createIntegral(refCoefNorm, refCoefNorm, rangeName)};
193+
rangeProj2 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(refCoefNorm, refCoefNorm, rangeName)};
191194
// rangeProj2->setOperMode(operMode()) ;
192195

193196
} else if (addPdf.normRange()) {
194197

195198
RooArgSet tmp;
196-
thePdf->getObservables(&refCoefNorm, tmp);
197-
rangeProj2 = std::unique_ptr<RooAbsReal>{thePdf->createIntegral(tmp, tmp, addPdf.normRange())};
199+
pdf->getObservables(&refCoefNorm, tmp);
200+
rangeProj2 = std::unique_ptr<RooAbsReal>{pdf->createIntegral(tmp, tmp, addPdf.normRange())};
198201
oocxcoutD(&addPdf, Caching) << " " << addPdf.ClassName() << "::syncCoefProjList(" << addPdf.GetName()
199202
<< ") R2 = " << rangeProj2->GetName() << std::endl;
200203
}
@@ -230,15 +233,20 @@ RooArgList AddCacheElem::containedArgs(Action)
230233
return allNodes;
231234
}
232235

233-
void RooAddHelpers::updateCoefficients(RooAbsPdf const &addPdf, RooArgList const &pdfList, RooArgList const &coefList,
234-
AddCacheElem &cache, const RooArgSet *nset, bool projectCoefs,
235-
RooArgSet const &refCoefNorm, bool allExtendable, std::vector<double> &coefCache,
236-
int &coefErrCount)
236+
////////////////////////////////////////////////////////////////////////////////
237+
/// Update the RooAddPdf coefficients for a given normalization set and
238+
/// projection configuration. The `coefCache` argument should have the same
239+
/// size as `pdfList`. It needs to be initialized with the raw values of the
240+
/// coefficients, as obtained from the `_coefList` proxy in the RooAddPdf. If
241+
/// the last coefficient is not given, the initial value of the last element of
242+
/// `_coefCache` does not matter. After this function, the `_coefCache` will be
243+
/// filled with the correctly scaled coefficients for each pdf.
244+
245+
void RooAddHelpers::updateCoefficients(RooAbsPdf const &addPdf, std::vector<double> &coefCache,
246+
RooArgList const &pdfList, bool haveLastCoef, AddCacheElem &cache,
247+
const RooArgSet *nset, bool projectCoefs, RooArgSet const &refCoefNorm,
248+
bool allExtendable, int &coefErrCount)
237249
{
238-
bool haveLastCoef = pdfList.size() == coefList.size();
239-
240-
coefCache.resize(haveLastCoef ? coefList.size() : pdfList.size(), 0.);
241-
242250
// Straight coefficients
243251
if (allExtendable) {
244252

@@ -265,38 +273,26 @@ void RooAddHelpers::updateCoefficients(RooAbsPdf const &addPdf, RooArgList const
265273
if (haveLastCoef) {
266274

267275
// coef[i] = coef[i] / SUM(coef)
268-
double coefSum(0);
269-
std::size_t i = 0;
270-
for (auto coefArg : coefList) {
271-
auto coef = static_cast<RooAbsReal *>(coefArg);
272-
coefCache[i] = coef->getVal(nset);
273-
coefSum += coefCache[i++];
274-
}
276+
double coefSum = std::accumulate(coefCache.begin(), coefCache.end(), 0.0);
275277
if (coefSum == 0.) {
276278
oocoutW(&addPdf, Eval) << addPdf.ClassName() << "::updateCoefCache(" << addPdf.GetName()
277279
<< ") WARNING: sum of coefficients is zero 0" << std::endl;
278280
} else {
279281
const double invCoefSum = 1. / coefSum;
280-
for (std::size_t j = 0; j < coefList.size(); j++) {
282+
for (std::size_t j = 0; j < coefCache.size(); j++) {
281283
coefCache[j] *= invCoefSum;
282284
}
283285
}
284286
} else {
285287

286288
// coef[i] = coef[i] ; coef[n] = 1-SUM(coef[0...n-1])
287-
double lastCoef(1);
288-
std::size_t i = 0;
289-
for (auto coefArg : coefList) {
290-
auto coef = static_cast<RooAbsReal *>(coefArg);
291-
coefCache[i] = coef->getVal(nset);
292-
lastCoef -= coefCache[i++];
293-
}
294-
coefCache[coefList.size()] = lastCoef;
289+
double lastCoef = 1.0 - std::accumulate(coefCache.begin(), coefCache.end() - 1, 0.0);
290+
coefCache.back() = lastCoef;
295291

296292
// Treat coefficient degeneration
297293
const float coefDegen = lastCoef < 0. ? -lastCoef : (lastCoef > 1. ? lastCoef - 1. : 0.);
298294
if (coefDegen > 1.E-5) {
299-
coefCache[coefList.size()] = RooNaNPacker::packFloatIntoNaN(100.f * coefDegen);
295+
coefCache.back() = RooNaNPacker::packFloatIntoNaN(100.f * coefDegen);
300296

301297
std::stringstream msg;
302298
if (coefErrCount-- > 0) {

roofit/roofitcore/src/RooAddHelpers.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,9 @@ class AddCacheElem : public RooAbsCacheElement {
6161

6262
class RooAddHelpers {
6363
public:
64-
static void updateCoefficients(RooAbsPdf const &addPdf, RooArgList const &pdfList, RooArgList const &coefList,
65-
AddCacheElem &cache, const RooArgSet *nset, bool projectCoefs,
66-
RooArgSet const &refCoefNorm, bool allExtendable, std::vector<double> &coefCache,
67-
int &coefErrCount);
64+
static void updateCoefficients(RooAbsPdf const &addPdf, std::vector<double> &coefCache, RooArgList const &pdfList,
65+
bool haveLastCoef, AddCacheElem &cache, const RooArgSet *nset, bool projectCoefs,
66+
RooArgSet const &refCoefNorm, bool allExtendable, int &coefErrCount);
6867
};
6968

7069
#endif

roofit/roofitcore/src/RooAddModel.cxx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ RooAddModel::RooAddModel() :
6464
_projCacheMgr(this,10),
6565
_intCacheMgr(this,10)
6666
{
67-
_coefCache.resize(10);
6867
_coefErrCount = _errorCount ;
6968
}
7069

@@ -149,7 +148,6 @@ RooAddModel::RooAddModel(const char *name, const char *title, const RooArgList&
149148
_haveLastCoef = true;
150149
}
151150

152-
_coefCache.resize(_pdfList.getSize());
153151
_coefErrCount = _errorCount;
154152

155153
if (ownPdfList) {
@@ -173,7 +171,6 @@ RooAddModel::RooAddModel(const RooAddModel& other, const char* name) :
173171
_haveLastCoef(other._haveLastCoef),
174172
_allExtendable(other._allExtendable)
175173
{
176-
_coefCache.resize(_pdfList.getSize());
177174
_coefErrCount = _errorCount ;
178175
}
179176

@@ -340,8 +337,12 @@ AddCacheElem* RooAddModel::getProjCache(const RooArgSet* nset, const RooArgSet*
340337

341338
void RooAddModel::updateCoefficients(AddCacheElem& cache, const RooArgSet* nset) const
342339
{
343-
RooAddHelpers::updateCoefficients(*this, _pdfList, _coefList, cache, nset, _projectCoefs,
344-
_refCoefNorm, _allExtendable, _coefCache, _coefErrCount);
340+
_coefCache.resize(_pdfList.getSize());
341+
for(std::size_t i = 0; i < _coefList.size(); ++i) {
342+
_coefCache[i] = static_cast<RooAbsReal const&>(_coefList[i]).getVal(nset);
343+
}
344+
RooAddHelpers::updateCoefficients(*this, _coefCache, _pdfList, _haveLastCoef, cache, nset, _projectCoefs,
345+
_refCoefNorm, _allExtendable, _coefErrCount);
345346
}
346347

347348

roofit/roofitcore/src/RooAddPdf.cxx

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,6 @@ void RooAddPdf::finalizeConstruction() {
121121
}
122122
seen.insert(elem);
123123
}
124-
125-
_coefCache.resize(_pdfList.size());
126124
}
127125

128126

@@ -378,11 +376,25 @@ AddCacheElem* RooAddPdf::getProjCache(const RooArgSet* nset, const RooArgSet* is
378376
/// fraction, normalize fractions obtained from extended ML terms to unity, and
379377
/// multiply the various range and dimensional corrections needed in the
380378
/// current use context.
381-
382-
void RooAddPdf::updateCoefficients(AddCacheElem& cache, const RooArgSet* nset) const
379+
///
380+
/// param[in] cache The cache element for the given normalization set that
381+
/// stores the supplementary normalization values and
382+
/// projection-related objects.
383+
/// param[in] nset The set of variables to normalize over.
384+
/// param[in] syncCoefValues If the initial values of the coefficients still
385+
/// need to be copied from the `_coefList` elements to
386+
/// the `_coefCache`. True by default.
387+
388+
void RooAddPdf::updateCoefficients(AddCacheElem& cache, const RooArgSet* nset, bool syncCoefValues) const
383389
{
384-
RooAddHelpers::updateCoefficients(*this, _pdfList, _coefList, cache, nset, _projectCoefs,
385-
_refCoefNorm, _allExtendable, _coefCache, _coefErrCount);
390+
_coefCache.resize(_pdfList.size());
391+
if(syncCoefValues) {
392+
for(std::size_t i = 0; i < _coefList.size(); ++i) {
393+
_coefCache[i] = static_cast<RooAbsReal const&>(_coefList[i]).getVal(nset);
394+
}
395+
}
396+
RooAddHelpers::updateCoefficients(*this, _coefCache, _pdfList, _haveLastCoef, cache, nset, _projectCoefs,
397+
_refCoefNorm, _allExtendable, _coefErrCount);
386398
}
387399

388400
////////////////////////////////////////////////////////////////////////////////
@@ -435,7 +447,6 @@ std::pair<const RooArgSet*, AddCacheElem*> RooAddPdf::getNormAndCache(const RooA
435447

436448

437449
AddCacheElem* cache = getProjCache(nset) ;
438-
updateCoefficients(*cache, nset);
439450

440451
return {nset, cache};
441452
}
@@ -449,6 +460,7 @@ double RooAddPdf::getValV(const RooArgSet* normSet) const
449460
auto normAndCache = getNormAndCache(normSet);
450461
const RooArgSet* nset = normAndCache.first;
451462
AddCacheElem* cache = normAndCache.second;
463+
updateCoefficients(*cache, nset);
452464

453465
// Process change in last data set used
454466
bool nsetChanged(false) ;
@@ -481,9 +493,32 @@ double RooAddPdf::getValV(const RooArgSet* normSet) const
481493
/// Compute addition of PDFs in batches.
482494
void RooAddPdf::computeBatch(cudaStream_t* stream, double* output, size_t nEvents, RooFit::Detail::DataMap const& dataMap) const
483495
{
496+
_coefCache.resize(_pdfList.size());
497+
for(std::size_t i = 0; i < _coefList.size(); ++i) {
498+
auto coefVals = dataMap.at(&_coefList[i]);
499+
// We don't support per-event coefficients in this function. If the CPU
500+
// mode is used, we can just fall back to the RooAbsReal implementation.
501+
// With CUDA, we can't do that because the inputs might be on the device.
502+
// That's why we throw an exception then.
503+
if(coefVals.size() > 1) {
504+
if(stream) {
505+
throw std::runtime_error("The RooAddPdf doesn't support per-event coefficients in CUDA mode yet!");
506+
}
507+
RooAbsReal::computeBatch(stream, output, nEvents, dataMap);
508+
return;
509+
}
510+
_coefCache[i] = coefVals[0];
511+
}
512+
484513
RooBatchCompute::VarVector pdfs;
485514
RooBatchCompute::ArgVector coefs;
486-
AddCacheElem* cache = getNormAndCache(nullptr).second;
515+
auto normAndCache = getNormAndCache(nullptr);
516+
const RooArgSet* nset = normAndCache.first;
517+
AddCacheElem* cache = normAndCache.second;
518+
// We don't sync the coefficient values from the _coefList to the _coefCache
519+
// because we have already done it using the dataMap.
520+
updateCoefficients(*cache, nset, /*syncCoefValues=*/false);
521+
487522
for (unsigned int pdfNo = 0; pdfNo < _pdfList.size(); ++pdfNo)
488523
{
489524
auto pdf = static_cast<RooAbsPdf*>(&_pdfList[pdfNo]);

0 commit comments

Comments
 (0)