From 6d03b9e90cd1862bfd9069b340a6400d13ba2119 Mon Sep 17 00:00:00 2001 From: Giordon Stark Date: Wed, 23 Mar 2022 15:58:04 -0400 Subject: [PATCH] fix: writexml handles missing parameter configs for normfactor (#1819) * In situations in writexml where the normfactor parameter config is missing inits or bounds, fall back to using default values instead. * Add tests that use workspaces with no parameter inits and no parameter bounds to cover this behavior. --- src/pyhf/writexml.py | 4 +- tests/test_export.py | 27 ++++++++++++++ .../workspace_no_parameter_bounds.json | 37 +++++++++++++++++++ .../workspace_no_parameter_inits.json | 37 +++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 tests/test_export/workspace_no_parameter_bounds.json create mode 100644 tests/test_export/workspace_no_parameter_inits.json diff --git a/src/pyhf/writexml.py b/src/pyhf/writexml.py index fb118f5b81..3eaa1c1d32 100644 --- a/src/pyhf/writexml.py +++ b/src/pyhf/writexml.py @@ -178,8 +178,8 @@ def build_modifier(spec, modifierspec, channelname, samplename, sampledata): high = 10 for p in spec['measurements'][0]['config']['parameters']: if p['name'] == modifierspec['name']: - val = p['inits'][0] - low, high = p['bounds'][0] + val = p.get('inits', [val])[0] + low, high = p.get('bounds', [[low, high]])[0] attrs['Val'] = str(val) attrs['Low'] = str(low) attrs['High'] = str(high) diff --git a/tests/test_export.py b/tests/test_export.py index 649170c360..a63a010f73 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -428,3 +428,30 @@ def test_integer_data(datadir, mocker): channel = pyhf.writexml.build_channel(spec, channel_spec, {}) assert channel + + +@pytest.mark.parametrize( + "fname,val,low,high", + [ + ('workspace_no_parameter_inits.json', '1', '-5', '5'), + ('workspace_no_parameter_bounds.json', '5', '0', '10'), + ], + ids=['no_inits', 'no_bounds'], +) +def test_issue1814(datadir, mocker, fname, val, low, high): + with open(datadir / fname) as spec_file: + spec = json.load(spec_file) + + modifierspec = {'data': None, 'name': 'mu_sig', 'type': 'normfactor'} + channelname = None + samplename = None + sampledata = None + + modifier = pyhf.writexml.build_modifier( + spec, modifierspec, channelname, samplename, sampledata + ) + assert modifier is not None + assert sorted(modifier.keys()) == ['High', 'Low', 'Name', 'Val'] + assert modifier.get('Val') == val + assert modifier.get('Low') == low + assert modifier.get('High') == high diff --git a/tests/test_export/workspace_no_parameter_bounds.json b/tests/test_export/workspace_no_parameter_bounds.json new file mode 100644 index 0000000000..ae772e6d3c --- /dev/null +++ b/tests/test_export/workspace_no_parameter_bounds.json @@ -0,0 +1,37 @@ +{ + "channels": [ + { + "name": "ch", + "samples": [ + { + "data": [1000.0], + "modifiers": [ + {"data": null, "name": "mu_sig", "type": "normfactor"}, + { + "data": {"hi": 1.5, "lo": 0.5}, + "name": "unc", + "type": "normsys" + } + ], + "name": "signal" + } + ] + } + ], + "measurements": [ + { + "config": { + "parameters": [ + { + "name": "mu_sig", + "inits": [5] + } + ], + "poi": "mu_sig" + }, + "name": "meas" + } + ], + "observations": [{"data": [1000], "name": "ch"}], + "version": "1.0.0" +} diff --git a/tests/test_export/workspace_no_parameter_inits.json b/tests/test_export/workspace_no_parameter_inits.json new file mode 100644 index 0000000000..ddacc20d66 --- /dev/null +++ b/tests/test_export/workspace_no_parameter_inits.json @@ -0,0 +1,37 @@ +{ + "channels": [ + { + "name": "ch", + "samples": [ + { + "data": [1000.0], + "modifiers": [ + {"data": null, "name": "mu_sig", "type": "normfactor"}, + { + "data": {"hi": 1.5, "lo": 0.5}, + "name": "unc", + "type": "normsys" + } + ], + "name": "signal" + } + ] + } + ], + "measurements": [ + { + "config": { + "parameters": [ + { + "name": "mu_sig", + "bounds": [[-5, 5]] + } + ], + "poi": "mu_sig" + }, + "name": "meas" + } + ], + "observations": [{"data": [1000], "name": "ch"}], + "version": "1.0.0" +}