Skip to content

Staterror on samples with negative bin counts #2577

@alexander-held

Description

@alexander-held

Summary

How can I assign staterror modifiers on samples with negative yields? These kind of models arise in the context of interference measurements. At the moment pyhf seems to freeze the associated nuisance parameter.

Steps to Reproduce

Consider the following:

import pyhf

spec = {
    "channels": [
        {
            "name": "SR",
            "samples": [
                {
                    "data": [-50.0],
                    "modifiers": [
                        {
                            "data": [10.0],
                            "name": "staterror_SR",
                            "type": "staterror"
                        }
                    ],
                    "name": "Signal"
                },
                {
                    "data": [500.0],
                    "modifiers": [],
                    "name": "Background"
                }
            ]
        }
    ],
    "measurements": [
        {
            "config": {
                "parameters": [],
                "poi": ""
            },
            "name": "minimal_example"
        }
    ],
    "observations": [
        {
            "data": [450.0],
            "name": "SR"
        }
    ],
    "version": "1.0.0"
}

ws = pyhf.Workspace(spec)
model = ws.model()
data = ws.data(model)

pyhf.set_backend("numpy", "minuit")
res = pyhf.infer.mle.fit(data, model, return_uncertainties=True)
print(res)

which shows that the parameter is fixed:

[[1. 0.]]

Expected Results

I think the setup should in principle work. Here is a workaround: multiply sample yields by -1 manually and then attach a fixed normalization factor that makes them negative again.

import pyhf

spec = {
    "channels": [
        {
            "name": "SR",
            "samples": [
                {
                    "data": [50.0],
                    "modifiers": [
                        {
                            "data": [10.0],
                            "name": "staterror_SR",
                            "type": "staterror"
                        },
                        {
                            "data": None,
                            "name": "set_neg",
                            "type": "normfactor"
                        },
                    ],
                    "name": "Signal"
                },
                {
                    "data": [500.0],
                    "modifiers": [],
                    "name": "Background"
                }
            ]
        }
    ],
    "measurements": [
        {
            "config": {
                "parameters": [{"inits": [-1.0], "bounds": [[-5,5]], "name": "set_neg", "fixed": True}],
                "poi": ""
            },
            "name": "minimal_example"
        }
    ],
    "observations": [
        {
            "data": [550.0],
            "name": "SR"
        }
    ],
    "version": "1.0.0"
}

ws = pyhf.Workspace(spec)
model = ws.model()
data = ws.data(model)

pyhf.set_backend("numpy", "minuit")
res = pyhf.infer.mle.fit(data, model, return_uncertainties=True)
print(res)

This results in

[[-1.          0.        ]
 [ 0.64771039  0.17861548]]

With the first row being the intentionally fixed normalization factor and the second being the staterror term that acts on the sample.

pyhf Version

HEAD `40ebf6d`

Code of Conduct

  • I agree to follow the Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-triageNeeds a maintainer to categorize and assign

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions