splitCats[observables['runPeriod'].GetName()] = set([ par.GetName() for par in massPdf.Parameters() if not par.isConstant() ])
    if len(KKMassBinBounds) > 2 :
        splitCats[ observables['KKMassCat'].GetName() ] = set(yieldNames)
        for par in backgroundBMass.parameters() :
            if not par.isConstant() : splitCats[ observables['KKMassCat'].GetName() ].add( par.GetName() )
    if triggerSel == 'paper2012' or triggerSel == 'timeEffFit' :
        splitCats[ observables['hlt1ExclB'].GetName() ] = set(yieldNames)
    if triggerSel == 'timeEffFit' :
        splitCats[ observables['hlt2B'].GetName() ] = set(yieldNames)

    splitParsDict = { }
    pdfVars = massPdf.getVariables()
    for cat, params in splitCats.iteritems() :
        assert ws.cat(cat), 'P2VV - ERROR: createB2CCFitNTuple: category "%s" not in workspace' % cat
        for par in params :
            assert ws.var(par), 'P2VV - ERROR: createB2CCFitNTuple: no variable "%s" in workspace' % par
            assert pdfVars.find(par), 'P2VV - ERROR: createB2CCFitNTuple: variable "%s" not in PDF' % par
            if ws[par] not in splitParsDict :
                splitParsDict[ ws[par] ] = set( [ ws[cat] ] )
            else :
                splitParsDict[ ws[par] ].add( ws[cat] )

    # create lists of split categories and parameters
    pars = splitParsDict.keys()
    splitCats = [ ]
    splitPars = [ ]
    for par in pars :
        if par not in splitParsDict : continue
        splitPars.append( set( [par] ) )
        splitCats.append( splitParsDict.pop(par) )
        for par1 in pars :
if model == 'ipatia2' :
    # split Ipatia 2 signal parameters
    hlt2BName = observables['hlt2B'].GetName()
    KKCatName = observables['KKMassCat'].GetName()
    for parName in sigParNames :
        if not biasedOnly and 'sigma' in parName : splitCats[hlt2BName].add(parName)
        splitCats[KKCatName].add(parName)
    for parName in constSplitPars :
        splitCats[KKCatName].add(parName)

splitParsDict = { }
pdfVars = massPdf.getVariables()
for cat, params in splitCats.iteritems() :
    assert ws.cat(cat), 'P2VV - ERROR: createBs2JpsiKKDataSet: category "%s" not in workspace' % cat
    for par in params :
        assert ws.var(par), 'P2VV - ERROR: createBs2JpsiKKDataSet: no variable "%s" in workspace' % par
        assert pdfVars.find(par), 'P2VV - ERROR: createBs2JpsiKKDataSet: variable "%s" not in PDF' % par
        if ws[par] not in splitParsDict :
            splitParsDict[ ws[par] ] = set( [ ws[cat] ] )
        else :
            splitParsDict[ ws[par] ].add( ws[cat] )

# create list of split parameters and categories
from P2VV.Utilities.General import createSplitParsList
splitPars = createSplitParsList(splitParsDict)

# build simultaneous mass PDF
print 'P2VV - INFO: createBs2JpsiKKDataSet: building simultaneous PDF "%s":' % ( massPdf.GetName() + '_simul' )
print 13 * ' ' + 'split parameters:'
for it, pars in enumerate(splitPars) :
    print 13 * ' ' + '%2d: pars: [ %s ]' % ( it, ', '.join( par.GetName() for par in pars[0] ) )
             , observables['KKMassCat'].GetName() : set( yieldNames               )
            }

# split Ipatia 2 signal parameters
KKCatName = observables['KKMassCat'].GetName()
for parName in sigParNames :
    splitCats[KKCatName].add(parName)
for parName in constSplitPars :
    splitCats[KKCatName].add(parName)

splitParsDict = { }
pdfVars = massPdf.getVariables()
for cat, params in splitCats.iteritems() :
    assert ws.cat(cat), 'P2VV - ERROR: splitDataSetSigBkg: category "%s" not in workspace' % cat
    for par in params :
        assert ws.var(par), 'P2VV - ERROR: splitDataSetSigBkg: no variable "%s" in workspace' % par
        assert pdfVars.find(par), 'P2VV - ERROR: splitDataSetSigBkg: variable "%s" not in PDF' % par
        if ws[par] not in splitParsDict :
            splitParsDict[ ws[par] ] = set( [ ws[cat] ] )
        else :
            splitParsDict[ ws[par] ].add( ws[cat] )

# create list of split parameters and categories
from P2VV.Utilities.General import createSplitParsList
splitPars = createSplitParsList(splitParsDict)

# build simultaneous mass PDF
print 'P2VV - INFO: splitDataSetSigBkg: building simultaneous PDF "%s":' % ( massPdf.GetName() + '_simul' )
print 13 * ' ' + 'split parameters:'
for it, pars in enumerate(splitPars) :
    print 13 * ' ' + '%2d: pars: [ %s ]' % ( it, ', '.join( par.GetName() for par in pars[0] ) )