Skip to content

Commit

Permalink
use pyhf API for parameter labels, fix MINOS via pyhf (parameter name…
Browse files Browse the repository at this point in the history
…s now passed through)
  • Loading branch information
alexander-held committed Aug 25, 2021
1 parent 5220056 commit c00332a
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 40 deletions.
22 changes: 6 additions & 16 deletions src/cabinetry/fit/__init__.py
Expand Up @@ -85,15 +85,7 @@ def _fit_model_pyhf(
fit_results = FitResults(bestfit, uncertainty, labels, corr_mat, best_twice_nll)

if minos is not None:
parameters_translated = []
for minos_par in minos:
par_index = model_utils._parameter_index(minos_par, labels)
if par_index != -1:
# pyhf does not hand over parameter names, all parameters are known as
# x0, x1, etc.
parameters_translated.append(f"x{par_index}")

_run_minos(result_obj.minuit, parameters_translated, labels)
_run_minos(result_obj.minuit, minos, labels)

return fit_results

Expand Down Expand Up @@ -243,13 +235,11 @@ def _run_minos(
knows parameters)
"""
for par_name in minos:
# get index of current parameter in labels (to translate its name if iminuit
# did not receive the parameter labels)
par_index = model_utils._parameter_index(par_name, minuit_obj.parameters)
if par_index == -1:
# parameter not found, skip calculation (can only happen with custom fit)
if par_name not in minuit_obj.parameters:
# parameter not found, skip calculation
log.warning(f"parameter {par_name} not found in model")
continue
log.info(f"running MINOS for {labels[par_index]}")
log.info(f"running MINOS for {par_name}")
minuit_obj.minos(par_name)

log.info("MINOS results:")
Expand Down Expand Up @@ -503,7 +493,7 @@ def scan(
# get index of parameter with name par_name
par_index = model_utils._parameter_index(par_name, labels)
if par_index == -1:
raise ValueError(f"could not find parameter {par_name} in model")
raise ValueError(f"parameter {par_name} not found in model")

# run a fit with the parameter not held constant, to find the best-fit point
fit_results = _fit_model(model, data, custom_fit=custom_fit)
Expand Down
10 changes: 1 addition & 9 deletions src/cabinetry/model_utils.py
Expand Up @@ -77,15 +77,7 @@ def parameter_names(model: pyhf.pdf.Model) -> List[str]:
Returns:
List[str]: names of fit parameters
"""
labels = []
for parname in model.config.par_order:
for i_par in range(model.config.param_set(parname).n_parameters):
labels.append(
f"{parname}[bin_{i_par}]"
if model.config.param_set(parname).n_parameters > 1
else parname
)
return labels
return model.config.par_names()


def asimov_data(model: pyhf.Model, with_aux: bool = True) -> List[float]:
Expand Down
16 changes: 2 additions & 14 deletions tests/fit/test_fit.py
Expand Up @@ -68,7 +68,7 @@ def test__fit_model_pyhf(mock_minos, example_spec, example_spec_multibin):
fit_results = fit._fit_model_pyhf(model, data, minos=["Signal strength", "abc"])
assert mock_minos.call_count == 1
# first argument to minos call is the Minuit instance
assert mock_minos.call_args[0][1] == ["x1"]
assert mock_minos.call_args[0][1] == ["Signal strength", "abc"]
assert mock_minos.call_args[0][2] == ["staterror_Signal-Region", "Signal strength"]
assert mock_minos.call_args[1] == {}

Expand Down Expand Up @@ -222,18 +222,6 @@ def func_to_minimize(pars):
assert "b = 1.5909 -0.7262 +0.4738" in [rec.message for rec in caplog.records]
caplog.clear()

# proper labels not known to iminuit
m = iminuit.Minuit(
func_to_minimize,
[1.0, 1.0],
)
m.errordef = 1
m.migrad()
fit._run_minos(m, ["x0"], ["a", "b"])
assert "running MINOS for a" in [rec.message for rec in caplog.records]
assert "a = 1.3827 -0.8713 +0.5715" in [rec.message for rec in caplog.records]
caplog.clear()

# unknown parameter, MINOS does not run
m = iminuit.Minuit(
func_to_minimize,
Expand Down Expand Up @@ -480,7 +468,7 @@ def test_scan(mock_fit, example_spec):
assert mock_fit.call_args[1]["custom_fit"] is True

# unknown parameter
with pytest.raises(ValueError, match="could not find parameter abc in model"):
with pytest.raises(ValueError, match="parameter abc not found in model"):
fit.scan(model, data, "abc")


Expand Down
2 changes: 1 addition & 1 deletion tests/test_integration.py
Expand Up @@ -148,7 +148,7 @@ def test_integration(tmp_path, ntuple_creator, caplog):
assert np.allclose(fit_results.goodness_of_fit, 0.24679341)

# minos result
assert "Signal_norm = 1.6895 -0.9580 +0.9052" in [
assert "Signal_norm = 1.6895 -0.9580 +0.9052" in [
rec.message for rec in caplog.records
]
caplog.clear()
Expand Down

0 comments on commit c00332a

Please sign in to comment.