scikit-hep / pyhf

pure-Python HistFactory implementation with tensors and autodiff
https://pyhf.readthedocs.io/
Apache License 2.0
283 stars 83 forks source link

possible contrib: ROOT bridge #1342

Open lukasheinrich opened 3 years ago

lukasheinrich commented 3 years ago

Description

it could be useful to provide a pyhf-like confiig interface to a roo-hf workspace/measuremet

cc @alexander-held @cranmer @kratsg @matthewfeickert

def process_measurement(measobj):
    spec = {'channels':[],'parameters':[]}
    for c in measobj.GetChannels():
        channel_spec = {'name': None, 'samples': []}
        channel_spec['name'] = c.GetName()
        nbins = c.GetData().GetHisto().GetNbinsX()
        for s in c.GetSamples():
            sample_spec = {'name': None, 'data': [0]*nbins, 'modifiers': []}
            sample_spec['name'] = s.GetName()
            for m in s.GetNormFactorList():
                modifier_spec = {'type': 'normfactor', 'name': m.GetName(),'data': 'wha'}
                sample_spec['modifiers'].append(modifier_spec)
            for m in s.GetOverallSysList():
                modifier_spec = {'type': 'normsys', 'name': m.GetName(),'data': 'wha'}
                sample_spec['modifiers'].append(modifier_spec)
            if s.GetNormalizeByTheory():
                modifier_spec = {'type': 'lumi', 'name': 'lumi', 'data': None}
                sample_spec['modifiers'].append(modifier_spec)
            channel_spec['samples'].append(sample_spec)
        spec['channels'].append(channel_spec)

    lumi_spec = {
        "auxdata": [1.0], "bounds": [
            [
                measobj.GetLumi() - 5.0 * measobj.GetLumiRelErr(),
                measobj.GetLumi() + 5.0 * measobj.GetLumiRelErr()

            ]
        ],
        "fixed": ('Lumi' in list(measobj.GetConstantParams())),
        "inits": [measobj.GetLumi()],
        "name": "lumi",
        "sigmas": [measobj.GetLumiRelErr()]
    }

    spec['parameters'].append(lumi_spec)
    return pyhf.pdf._ModelConfig(spec,poi_name = 'SigXsecOverSM')

class roohf_bridge:
    def __init__(self,fname,mname):
        import ROOT
        self.f = ROOT.TFile.Open(fname)
        self.config = process_measurement(self.f.Get(mname))

image

matthewfeickert commented 3 years ago

@lukasheinrich in the screenshot there is print(rm.config.par_order) twice, but I'll believe that it gives the same output as print(pm.config.par_order). :+1:

it could be useful to provide a pyhf-like config interface to a roo-hf workspace/measurement

I'm possibly missing the obvious, but can you elaborate more on the use case? This is more just adding a reader utility that then is still doing all the model conversion and building. Is the idea is to add syntactic sugar so that they don't have to write the lines themselves?

lukasheinrich commented 3 years ago

imagine you have a

and you want to plot it via cabinetry .. ideally those two things presennt a similar API to what ccabinetry uses anyways (which is inspired by pyhf) so this just provides an adapter