From e82ce985be542029ca91e344889120def87b3cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Therese=20Natter=C3=B8y?= <61694854+tnatt@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:20:42 +0100 Subject: [PATCH] ENH: Add validation of required volume columns --- src/fmu/dataio/export/rms/inplace_volumes.py | 44 +++++++++++- .../test_export_rms_volumetrics.py | 72 +++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/fmu/dataio/export/rms/inplace_volumes.py b/src/fmu/dataio/export/rms/inplace_volumes.py index 30de69cbf..f7b215eef 100644 --- a/src/fmu/dataio/export/rms/inplace_volumes.py +++ b/src/fmu/dataio/export/rms/inplace_volumes.py @@ -201,6 +201,47 @@ def _convert_table_from_legacy_to_standard_format( table = self._add_missing_columns_to_table(table) return self._set_table_column_order(table) + def _is_column_missing_in_table(self, column: str) -> bool: + """Check if a column is present in the final dataframe and has values""" + return column not in self._dataframe or self._dataframe[column].isna().all() + + def _validate_table(self) -> None: + """ + Validate that the final table with volumes is according to the standard + defined for the inplace_volumes product. + """ + _logger.debug("Validating the dataframe...") + + has_oil = "oil" in self._dataframe[_FLUID_COLUMN].values + has_gas = "gas" in self._dataframe[_FLUID_COLUMN].values + + # check that one of oil and gas fluids are present + if not (has_oil or has_gas): + raise RuntimeError( + "One or both 'oil' and 'gas' needs to be selected as 'Main types'" + "in the volumetric job. Please update and rerun the volumetric job " + "before export." + ) + + # create list of missing or non-defined required columns + missing_calculations = [] + for col in ["BULK", "PORV", "HCPV"]: + if self._is_column_missing_in_table(col): + missing_calculations.append(col) + + if has_oil and self._is_column_missing_in_table("STOIIP"): + missing_calculations.append("STOIIP") + + if has_gas and self._is_column_missing_in_table("GIIP"): + missing_calculations.append("GIIP") + + if missing_calculations: + raise RuntimeError( + f"Required calculations {missing_calculations} are missing " + f"in the volumetric table {self._volume_table_name}. Please update and " + "rerun the volumetric job before export." + ) + def _export_volume_table(self) -> ExportResult: """Do the actual volume table export using dataio setup.""" @@ -227,7 +268,8 @@ def _export_volume_table(self) -> ExportResult: ) def export(self) -> ExportResult: - """Export the volume table.""" + """Validate and export the volume table.""" + self._validate_table() return self._export_volume_table() diff --git a/tests/test_export_rms/test_export_rms_volumetrics.py b/tests/test_export_rms/test_export_rms_volumetrics.py index c0c531812..412820f3a 100644 --- a/tests/test_export_rms/test_export_rms_volumetrics.py +++ b/tests/test_export_rms/test_export_rms_volumetrics.py @@ -185,6 +185,78 @@ def test_convert_table_from_legacy_to_standard_format( ) +@pytest.mark.parametrize("required_col", ["BULK", "PORV", "HCPV"]) +def test_validate_table_required_col_missing( + exportvolumetrics, voltable_standard, required_col +): + """Test that the job fails if a required volumetric column is missing""" + + df = voltable_standard.drop(columns=required_col) + exportvolumetrics._dataframe = df + + with pytest.raises(RuntimeError, match="missing"): + exportvolumetrics._validate_table() + + +@pytest.mark.parametrize("required_col", ["BULK", "PORV", "HCPV"]) +def test_validate_table_required_col_has_nan( + exportvolumetrics, voltable_standard, required_col +): + """Test that the job fails if a required volumetric column has nan values""" + + df = voltable_standard.copy() + df[required_col] = np.nan + + exportvolumetrics._dataframe = df + + with pytest.raises(RuntimeError, match="missing"): + exportvolumetrics._validate_table() + + +def test_validate_table_has_oil_or_gas(exportvolumetrics, voltable_standard): + """Test that the job fails if a required volumetric column has nan values""" + + df = voltable_standard.copy() + df = df[~df["FLUID"].isin(["oil", "gas"])] + + exportvolumetrics._dataframe = df + + with pytest.raises(RuntimeError, match="missing"): + exportvolumetrics._validate_table() + + +def test_validate_table_has_oil_and_stoiip(exportvolumetrics, voltable_standard): + """Test that the validation fails if oil columns are present but no STOIIP""" + + df = voltable_standard.copy() + df = df.drop(columns="STOIIP") + + exportvolumetrics._dataframe = df + + with pytest.raises(RuntimeError, match="missing"): + exportvolumetrics._validate_table() + + # validation should pass when no oil columns are present + exportvolumetrics._dataframe = df[~(df["FLUID"] == "oil")] + exportvolumetrics._validate_table() + + +def test_validate_table_has_gas_and_giip(exportvolumetrics, voltable_standard): + """Test that the validations fails if gas columns are present but no GIIP""" + + df = voltable_standard.copy() + df = df.drop(columns="GIIP") + + exportvolumetrics._dataframe = df + + with pytest.raises(RuntimeError, match="missing"): + exportvolumetrics._validate_table() + + # validation should pass when no gas columns are present + exportvolumetrics._dataframe = df[~(df["FLUID"] == "gas")] + exportvolumetrics._validate_table() + + @inside_rms def test_rms_volumetrics_export_config_missing( mock_project_variable,