def test_WorkspaceBuilder_get_observations(mock_get_yield): # could mock _get_data_sample # create observations list from config example_config = { "General": {"HistogramFolder": "path"}, "Samples": [{"Name": "data", "Data": True}], "Regions": [{"Name": "test_region"}], } ws_builder = workspace.WorkspaceBuilder(example_config) obs = ws_builder.get_observations() expected_obs = [{"name": "test_region", "data": [1.0, 2.0]}] assert obs == expected_obs assert mock_get_yield.call_args_list == [ ((example_config["Regions"][0], example_config["Samples"][0]), {}) ] mock_get_yield.call_args_list = [] # rest call arguments list # multiple channels multi_channel_config = { "General": {"HistogramFolder": "path"}, "Samples": [{"Name": "data", "Data": True}], "Regions": [{"Name": "test_region"}, {"Name": "other_region"}], } ws_builder = workspace.WorkspaceBuilder(multi_channel_config) obs = ws_builder.get_observations() expected_obs = [ {"name": "test_region", "data": [5.0]}, {"name": "other_region", "data": [3.0]}, ] assert obs == expected_obs assert mock_get_yield.call_args_list == [ ((multi_channel_config["Regions"][0], multi_channel_config["Samples"][0]), {}), ((multi_channel_config["Regions"][1], multi_channel_config["Samples"][0]), {}), ]
def test_WorkspaceBuilder_get_yield_for_sample(mock_histogram): expected_yields = [1.0, 2.0] ws_builder = workspace.WorkspaceBuilder({"General": {"HistogramFolder": "path"}}) yields = ws_builder.get_yield_for_sample({"Name": "region"}, {"Name": "signal"}) assert yields == expected_yields # non-nominal yields_non_nominal = ws_builder.get_yield_for_sample( {"Name": "region"}, {"Name": "signal"}, systematic={"Name": "variation"} ) assert yields_non_nominal == expected_yields assert mock_histogram.call_args_list == [ ( ( pathlib.Path("path"), {"Name": "region"}, {"Name": "signal"}, {"Name": "Nominal"}, ), {"modified": True}, ), ( ( pathlib.Path("path"), {"Name": "region"}, {"Name": "signal"}, {"Name": "variation"}, ), {"modified": True}, ), ]
def test_WorkspaceBuilder_get_unc_for_sample(mock_histogram): expected_unc = [0.1, 0.1] ws_builder = workspace.WorkspaceBuilder({"General": {"HistogramFolder": "path"}}) unc = ws_builder.get_unc_for_sample({"Name": "region"}, {"Name": "signal"}) assert unc == expected_unc # non-nominal unc_non_nominal = ws_builder.get_unc_for_sample( {"Name": "region"}, {"Name": "signal"}, systematic={"Name": "variation"} ) assert unc_non_nominal == expected_unc assert mock_histogram.call_args_list == [ ( ( pathlib.Path("path"), {"Name": "region"}, {"Name": "signal"}, {"Name": "Nominal"}, ), {"modified": True}, ), ( ( pathlib.Path("path"), {"Name": "region"}, {"Name": "signal"}, {"Name": "variation"}, ), {"modified": True}, ), ]
def test_WorkspaceBuilder_get_sys_modifiers(mock_norm, mock_norm_shape): # could mock region_contains_modifier / sample_contains_modifier example_config = { "General": {"HistogramFolder": "path"}, "Systematics": [ {"Name": "norm", "Type": "Normalization"}, {"Name": "norm_shape", "Type": "NormPlusShape"}, ], } region = {"Name": "SR"} sample = {"Name": "Signal"} ws_builder = workspace.WorkspaceBuilder(example_config) assert ws_builder.get_sys_modifiers(region, sample) == [ {"mock": "normsys"}, {"mock": "norm"}, {"mock": "shape"}, ] assert mock_norm.call_args_list == [[(example_config["Systematics"][0],), {}]] assert mock_norm_shape.call_args_list == [ [(region, sample, example_config["Systematics"][1]), {}] ] # one systematic not present in region example_config_region_mismatch = copy.deepcopy(example_config) example_config_region_mismatch["Systematics"][0].update({"Regions": "CR"}) ws_builder = workspace.WorkspaceBuilder(example_config_region_mismatch) assert ws_builder.get_sys_modifiers(region, sample) == [ {"mock": "norm"}, {"mock": "shape"}, ] # one systematic not present in sample example_config_sample_mismatch = copy.deepcopy(example_config) example_config_sample_mismatch["Systematics"][1].update({"Samples": "Background"}) ws_builder = workspace.WorkspaceBuilder(example_config_sample_mismatch) assert ws_builder.get_sys_modifiers(region, sample) == [{"mock": "normsys"}] # unsupported systematics type example_config_unsupported = { "General": {"HistogramFolder": "path"}, "Systematics": [{"Name": "Normalization", "Type": "unknown"}], } ws_builder = workspace.WorkspaceBuilder(example_config_unsupported) with pytest.raises( NotImplementedError, match="not supporting other systematic types yet" ): ws_builder.get_sys_modifiers(region, sample)
def test_WorkspaceBuilder__get_data_sample(): mc_sample = {"Name": "MC"} data_sample = {"Name": "Data", "Data": True} example_config = { "General": {"HistogramFolder": "path"}, "Samples": [mc_sample, data_sample], } ws_builder = workspace.WorkspaceBuilder(example_config) assert ws_builder._get_data_sample() == data_sample config_two_data_samples = { "General": {"HistogramFolder": "path"}, "Samples": [data_sample, data_sample], } ws_builder = workspace.WorkspaceBuilder(config_two_data_samples) with pytest.raises(ValueError, match="did not find exactly one data sample"): ws_builder._get_data_sample()
def test_WorkspaceBuilder_get_NormPlusShape_modifiers(mock_histogram): # could mock Histogram.normalize_to_yield # up: 26, 24 (1.25*nom) # nominal: 20, 20 # down: 8, 12 (0.5*nom) example_config = {"General": {"HistogramFolder": "path"}} ws_builder = workspace.WorkspaceBuilder(example_config) region = {"Name": "SR"} sample = {"Name": "Signal"} systematic = {"Name": "sys", "Up": {}, "Down": {}} # no symmetrization modifiers = ws_builder.get_NormPlusShape_modifiers(region, sample, systematic) assert modifiers == [ {"name": "sys", "type": "normsys", "data": {"hi": 1.25, "lo": 0.5}}, { "name": "sys", "type": "histosys", "data": {"hi_data": [20.8, 19.2], "lo_data": [16.0, 24.0]}, }, ] assert mock_histogram.call_args_list == [ ( (pathlib.Path("path"), region, sample, systematic), {"modified": True, "template": "Up"}, ), ( (pathlib.Path("path"), region, sample, {"Name": "Nominal"}), {"modified": True}, ), ( (pathlib.Path("path"), region, sample, systematic), {"modified": True, "template": "Down"}, ), ] # down template via symmetrized up template systematic = {"Name": "sys", "Up": {}, "Down": {"Symmetrize": True}} modifiers = ws_builder.get_NormPlusShape_modifiers(region, sample, systematic) assert modifiers == [ {"name": "sys", "type": "normsys", "data": {"hi": 1.25, "lo": 0.75}}, { "name": "sys", "type": "histosys", "data": {"hi_data": [20.8, 19.2], "lo_data": [19.2, 20.8]}, }, ] assert mock_histogram.call_args_list[3:] == [ ( (pathlib.Path("path"), region, sample, systematic), {"modified": True, "template": "Up"}, ), ( (pathlib.Path("path"), region, sample, {"Name": "Nominal"}), {"modified": True}, ), ]
def test_WorkspaceBuilder_build(mock_channels, mock_measuremets, mock_observations): ws_builder = workspace.WorkspaceBuilder({"General": {"HistogramFolder": "path"}}) ws = ws_builder.build() ws_expected = { "channels": [{"name: channel"}], "measurements": [{"name: measurement"}], "observations": [{"name: observations"}], "version": "1.0.0", } assert ws == ws_expected
def test_WorkspaceBuilder_get_NF_modifiers(): # could mock region_contains_modifier / sample_contains_modifier # one NF affects sample example_config = { "General": {"HistogramFolder": "path"}, "NormFactors": [{"Name": "mu", "Samples": ["ABC", "DEF"]}], } region = {"Name": "SR"} sample = {"Name": "DEF"} expected_modifier = [{"data": None, "name": "mu", "type": "normfactor"}] ws_builder = workspace.WorkspaceBuilder(example_config) assert ws_builder.get_NF_modifiers(region, sample) == expected_modifier # no NF affects sample sample = {"Name": "GHI"} assert ws_builder.get_NF_modifiers(region, sample) == [] # NF enters in region example_config = { "General": {"HistogramFolder": "path"}, "NormFactors": [{"Name": "mu", "Regions": "SR"}], } ws_builder = workspace.WorkspaceBuilder(example_config) assert ws_builder.get_NF_modifiers(region, sample) == expected_modifier # no NF due to region region = {"Name": "CR"} assert ws_builder.get_NF_modifiers(region, sample) == [] # multiple NFs affect sample example_config = { "General": {"HistogramFolder": "path"}, "NormFactors": [{"Name": "mu"}, {"Name": "k"}], } sample = {"Name": "DEF"} expected_modifier = [ {"data": None, "name": "mu", "type": "normfactor"}, {"data": None, "name": "k", "type": "normfactor"}, ] ws_builder = workspace.WorkspaceBuilder(example_config) assert ws_builder.get_NF_modifiers(region, sample) == expected_modifier
def test_WorkspaceBuilder_get_channels(mock_contains, mock_get_yield, mock_get_unc): # should mock get_NF_modifiers / get_sys_modifiers example_config = { "General": {"HistogramFolder": "path"}, "Regions": [{"Name": "region_1"}], "Samples": [{"Name": "signal"}, {"Data": True}], "NormFactors": [], } ws_builder = workspace.WorkspaceBuilder(example_config) channels = ws_builder.get_channels() expected_channels = [ { "name": "region_1", "samples": [ { "name": "signal", "data": [1.0, 2.0], "modifiers": [ { "name": "staterror_region_1", "type": "staterror", "data": [0.1, 0.1], } ], } ], } ] assert channels == expected_channels assert mock_contains.call_args_list == [ ((example_config["Regions"][0], example_config["Samples"][0]), {}) ] assert mock_get_yield.call_args_list == [ ((example_config["Regions"][0], example_config["Samples"][0]), {}) ] assert mock_get_unc.call_args_list == [ ((example_config["Regions"][0], example_config["Samples"][0]), {}) ] # run again, this time region will not contain sample due to side_effect channels = ws_builder.get_channels() expected_channels = [{"name": "region_1", "samples": []}] assert channels == expected_channels assert mock_contains.call_count == 2 assert mock_contains.call_args_list[-1] == ( (example_config["Regions"][0], example_config["Samples"][0]), {}, ) # no calls to read histogram content assert mock_get_yield.call_count == 1 assert mock_get_unc.call_count == 1
def test_WorkspaceBuilder__get_constant_parameter_setting(): config_no_fixed = {"General": {"HistogramFolder": "path"}} ws_builder = workspace.WorkspaceBuilder(config_no_fixed) assert ws_builder._get_constant_parameter_setting("par") is None config_others_fixed = { "General": { "HistogramFolder": "path", "Fixed": [{"Name": "par_a", "Value": 1.2}], } } ws_builder = workspace.WorkspaceBuilder(config_others_fixed) assert ws_builder._get_constant_parameter_setting("par_b") is None config_par_fixed = { "General": { "HistogramFolder": "path", "Fixed": [{"Name": "par_a", "Value": 1.2}], } } ws_builder = workspace.WorkspaceBuilder(config_par_fixed) assert ws_builder._get_constant_parameter_setting("par_a") == 1.2
def test_WorkspaceBuilder_get_Normalization_modifier(): systematic = { "Name": "sys", "Up": {"Normalization": 0.1}, "Down": {"Normalization": -0.05}, } expected_modifier = { "name": "sys", "type": "normsys", "data": {"hi": 1.1, "lo": 0.95}, } ws_builder = workspace.WorkspaceBuilder({"General": {"HistogramFolder": "path"}}) assert ws_builder.get_Normalization_modifier(systematic) == expected_modifier
def test_WorkspaceBuilder_get_measurement(): example_config = { "General": {"Measurement": "fit", "POI": "mu", "HistogramFolder": "path"}, "NormFactors": [ {"Name": "NF", "Nominal": 1.0, "Bounds": [0.0, 5.0], "Fixed": False} ], } expected_measurement = [ { "name": "fit", "config": { "poi": "mu", "parameters": [{"name": "NF", "inits": [1.0], "bounds": [[0.0, 5.0]]}], }, } ] ws_builder = workspace.WorkspaceBuilder(example_config) assert ws_builder.get_measurements() == expected_measurement # no norm factor settings example_config_no_NF_settings = { "General": {"Measurement": "fit", "POI": "mu", "HistogramFolder": "path"}, "NormFactors": [{"Name": "NF"}], } expected_measurement_no_NF_settings = [ {"name": "fit", "config": {"poi": "mu", "parameters": [{"name": "NF"}]}} ] ws_builder = workspace.WorkspaceBuilder(example_config_no_NF_settings) assert ws_builder.get_measurements() == expected_measurement_no_NF_settings # constant normfactor with mock.patch( "cabinetry.workspace.WorkspaceBuilder._get_constant_parameter_setting", return_value=1.2, ) as mock_find_const: expected_measurement_const_NF = [ { "name": "fit", "config": { "poi": "mu", "parameters": [{"name": "NF", "fixed": True, "inits": [1.2]}], }, } ] # same config, but patched function to treat NF as fixed ws_builder = workspace.WorkspaceBuilder(example_config_no_NF_settings) assert ws_builder.get_measurements() == expected_measurement_const_NF assert mock_find_const.call_args_list == [(("NF",), {})] # constant systematic with mock.patch( "cabinetry.workspace.WorkspaceBuilder._get_constant_parameter_setting", return_value=1.2, ) as mock_find_const: example_config_const_sys = { "General": { "Measurement": "fit", "POI": "mu", "Fixed": [{"Name": "par_A", "Value": 1.2}], "HistogramFolder": "path", }, "Systematics": [{"Name": "par_A"}], } expected_measurement_const_sys = [ { "name": "fit", "config": { "poi": "mu", "parameters": [{"name": "par_A", "fixed": True, "inits": [1.2]}], }, } ] ws_builder = workspace.WorkspaceBuilder(example_config_const_sys) assert ws_builder.get_measurements() == expected_measurement_const_sys assert mock_find_const.call_args_list == [(("par_A",), {})] # no constant systematic with mock.patch( "cabinetry.workspace.WorkspaceBuilder._get_constant_parameter_setting", return_value=None, ) as mock_find_const: example_config_sys = { "General": {"Measurement": "fit", "POI": "mu", "HistogramFolder": "path"}, "Systematics": [{"Name": "par_A"}], } expected_measurement_sys = [ {"name": "fit", "config": {"poi": "mu", "parameters": []}} ] ws_builder = workspace.WorkspaceBuilder(example_config_sys) assert ws_builder.get_measurements() == expected_measurement_sys assert mock_find_const.call_args_list == [(("par_A",), {})]
def test_WorkspaceBuilder(): config = {"General": {"HistogramFolder": "path/"}} ws_builder = workspace.WorkspaceBuilder(config) assert ws_builder.config == config assert ws_builder.histogram_folder == pathlib.Path("path/")