diff --git a/src/fmu/tools/sensitivities/_excel2dict.py b/src/fmu/tools/sensitivities/_excel2dict.py index a89a8876..a02b96e7 100644 --- a/src/fmu/tools/sensitivities/_excel2dict.py +++ b/src/fmu/tools/sensitivities/_excel2dict.py @@ -161,6 +161,38 @@ def _find_onebyone_input_sheet(input_filename): return design_input_sheet[0] +def _check_designinput(dsgn_input): + """Checks for valid input in designinput sheet""" + + # Check for duplicate sensnames + sensitivity_names = [] + for row in dsgn_input.itertuples(): + if _has_value(row.sensname): + if row.sensname in sensitivity_names: + raise ValueError( + "sensname '{}' was found on more than one row in designinput sheet. " + "Two sensitivities can not share the same sensname. " + "Please correct this and rerun".format(row.sensname) + ) + else: + sensitivity_names.append(row.sensname) + + +def _check_for_mixed_sensitivities(sens_name, sens_group): + """Checks for valid input in designinput sheet. A sensitivity cannot contain +two different sensitivity types""" + + types = sens_group.groupby("type", sort=False) + if len(types) > 1: + raise ValueError( + "The sensitivity with sensname '{}' in designinput sheet contains more " + "than one sensitivity type. For each sensname all parameters must be specified " + "using the same type (seed, scenario, dist, ref, background, extern)".format( + sens_name + ) + ) + + def _excel2dict_onebyone(input_filename, sheetnames=None): """Reads spesification for onebyone design @@ -246,6 +278,7 @@ def _excel2dict_onebyone(input_filename, sheetnames=None): # Read input for sensitivities inputdict["sensitivities"] = OrderedDict() designinput = pd.read_excel(input_filename, design_inp_sheet) + _check_designinput(designinput) designinput["sensname"].fillna(method="ffill", inplace=True) @@ -270,6 +303,8 @@ def _excel2dict_onebyone(input_filename, sheetnames=None): # Read each sensitivity for sensname, group in grouped: + _check_for_mixed_sensitivities(sensname, group) + sensdict = OrderedDict() if group["type"].iloc[0] == "ref": diff --git a/tests/test_excel2dict.py b/tests/test_excel2dict.py index 3cd742db..906dc518 100644 --- a/tests/test_excel2dict.py +++ b/tests/test_excel2dict.py @@ -5,6 +5,7 @@ from __future__ import print_function import os +import pytest import pandas as pd @@ -77,3 +78,55 @@ def test_excel2dict_design(tmpdir): inputdict_to_yaml(dict_design, "dictdesign.yaml") assert os.path.exists("dictdesign.yaml") assert "RMS_SEED" in "".join(open("dictdesign.yaml").readlines()) + + +def test_duplicate_sensname_exception(tmpdir): + mock_erroneous_designinput = pd.DataFrame( + data=[ + ["sensname", "numreal", "type", "param_name"], + ["rms_seed", "", "seed"], + ["rms_seed", "", "seed"], + ] + ) + tmpdir.chdir() + defaultvalues = pd.DataFrame() + + writer = pd.ExcelWriter("designinput3.xlsx") + MOCK_GENERAL_INPUT.to_excel( + writer, sheet_name="general_input", index=False, header=None + ) + mock_erroneous_designinput.to_excel( + writer, sheet_name="designinput", index=False, header=None + ) + defaultvalues.to_excel(writer, sheet_name="defaultvalues", index=False, header=None) + writer.save() + + with pytest.raises( + ValueError, match="Two sensitivities can not share the same sensname" + ): + dict_design = excel2dict_design("designinput3.xlsx") + + +def test_mixed_senstype_exception(tmpdir): + mock_erroneous_designinput = pd.DataFrame( + data=[ + ["sensname", "numreal", "type", "param_name"], + ["rms_seed", "", "seed"], + ["", "", "dist"], + ] + ) + tmpdir.chdir() + defaultvalues = pd.DataFrame() + + writer = pd.ExcelWriter("designinput4.xlsx") + MOCK_GENERAL_INPUT.to_excel( + writer, sheet_name="general_input", index=False, header=None + ) + mock_erroneous_designinput.to_excel( + writer, sheet_name="designinput", index=False, header=None + ) + defaultvalues.to_excel(writer, sheet_name="defaultvalues", index=False, header=None) + writer.save() + + with pytest.raises(ValueError, match="contains more than one sensitivity type"): + dict_design = excel2dict_design("designinput4.xlsx")