def test_filters(self, data_grid): """Test filters as argument""" data_grid["filters"] = { "reek_sim_facies2.roff": { "include": ["FINESAND", "COARSESAND"], } } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert ["FINESAND", "COARSESAND"] == list(pdf.dataframe["FACIES"].unique()) assert pdf.dataframe["PORO"].mean() == pytest.approx(0.2374, abs=0.001) data_grid["filters"] = { "reek_sim_facies2.roff": { "exclude": "FINESAND", } } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert "FINESAND" not in list(pdf.dataframe["FACIES"].unique()) data_grid["filters"] = { "reek_sim_poro.roff": { "range": [0.15, 0.25], } } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert pdf.dataframe["PORO"].mean() == pytest.approx(0.2027, abs=0.001) assert pdf.dataframe["PORO"].min() > 0.15 assert pdf.dataframe["PORO"].max() < 0.25
def run(self, data, reuse=False, project=None): """Main routine for evaluating grid quality and stop/warn if too bad The routine depends on existing XTGeo functions for this purpose. Args: data (dict or str): The input data either as a Python dictionary or a path to a YAML file reuse (bool or list): Reusing some "timeconsuming to read" data in the instance. If True, then grid and gridprops will be reused as default. Alternatively it can be a list for more fine grained control, e.g. ["grid", "gridprops", "wells"] project (Union[object, str]): For usage inside RMS, None if running files """ self._data = self.handle_data(data, project) self._validate_input(self._data, project) QCC.verbosity = self._data.get("verbosity", 0) # parse data that are special for this check QCC.print_info("Parsing additional data...") self.ldata = _LocalData() self.ldata.parse_data(data) if isinstance(self.gdata, QCData): self.gdata.parse(data=data, reuse=reuse, project=project) else: self.gdata = QCData() self.gdata.parse(data) dfr = self.check_gridquality() QCC.print_debug(f"Results: \n{dfr}") self.evaluate_qcreport(dfr, "grid quality")
def test_gridprops(self, data_grid): """Test creating property dataframe from grid properties""" pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert pdf.dataframe["PORO"].mean() == pytest.approx(0.1677, abs=0.001) assert pdf.dataframe["PORO"].max() == pytest.approx(0.3613, abs=0.001) assert set(pdf.dataframe.columns) == set( ["PORO", "PERM", "ZONE", "FACIES"])
def test_codenames(self, data_grid): """Test modifying codenames on selectors""" data_grid["selectors"] = { "ZONE": { "name": "reek_sim_zone.roff", "codes": { 1: "TOP", 2: "MID" } }, "FACIES": { "name": "reek_sim_facies2.roff", "codes": { 1: "SAND", 2: "SAND" }, }, } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert set(["TOP", "MID", "Below_Low_reek"]) == { x for x in list(pdf.dataframe["ZONE"].unique()) if x is not None } assert set(["SAND", "SHALE"]) == { x for x in list(pdf.dataframe["FACIES"].unique()) if x is not None }
def test_wells(self, data_wells): """Test creating property dataframe from wells""" pdf = WellLogs2df(data=data_wells, project=None, xtgdata=QCData()) assert pdf.dataframe["PORO"].mean() == pytest.approx(0.1539, abs=0.001) assert pdf.dataframe["PORO"].max() == pytest.approx(0.3661, abs=0.001) assert set(pdf.dataframe.columns) == set( ["PORO", "PERM", "ZONE", "FACIES"])
def __init__(self): self._method = None self._data = None # input data dictionary self._path = "." self._gdata = QCData() # QCData instance, stores XTGeo data self._ldata = None # special data instance, for local data parsed per method self._reports = [ ] # List of all report, used to determin write/append mode
def __init__(self): self._propstats = [] # list of PropStat() instances self._dataframe = pd.DataFrame( ) # merged dataframe with continous stats self._dataframe_disc = pd.DataFrame( ) # merged dataframe with discrete stats self._xtgdata = QCData() # QCData instance, general XTGeo data
def test_blockedwells(self, data_bwells): """Test creating property dataframe from blocked wells""" pdf = WellLogs2df( data=data_bwells, project=None, xtgdata=QCData(), blockedwells=True ) assert pdf.dataframe["PORO"].mean() == pytest.approx(0.1709, abs=0.001) assert pdf.dataframe["PORO"].max() == pytest.approx(0.3640, abs=0.001) assert set(pdf.dataframe.columns) == set(["PORO", "FACIES"])
def __init__(self): self._xtgdata = QCData() # QCData instance, general XTGeo data self._dfs = [] # list of dataframes with aggregated statistics self._selectors_all = [] self._proptypes_all = [] self._ids = [] self._dataframe = pd.DataFrame() # merged dataframe with statistics
def test_selector_filters(self, data_grid): """Test filters on selector""" data_grid["selectors"] = { "FACIES": {"name": "reek_sim_facies2.roff", "include": "FINESAND"}, } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert ["FINESAND"] == list(pdf.dataframe["FACIES"].unique()) # test exclude values using list data_grid["selectors"] = { "FACIES": { "name": "reek_sim_facies2.roff", "exclude": ["FINESAND", "SHALE"], }, } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert "FINESAND" not in list(pdf.dataframe["FACIES"].unique()) assert "SHALE" not in list(pdf.dataframe["FACIES"].unique())
def test_filters_and_selector_filters(self, data_grid): """ Test filters on both selector and as separate argument Wanted behaviour is to ignore the filter on the selector """ data_grid["selectors"] = { "FACIES": {"name": "reek_sim_facies2.roff", "exclude": "FINESAND"}, } data_grid["filters"] = { "reek_sim_facies2.roff": { "include": ["FINESAND", "COARSESAND"], } } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert ["FINESAND", "COARSESAND"] == list(pdf.dataframe["FACIES"].unique()) assert pdf.dataframe["PORO"].mean() == pytest.approx(0.2374, abs=0.001)
def test_filters_and_property_filters(self, data_grid): """ Test filters on both properties and as separate argument. Wanted behaviour is to ignore the filter on the property """ data_grid["properties"] = { "PORO": {"name": "reek_sim_poro.roff", "range": [0.2, 0.4]}, } data_grid["filters"] = { "reek_sim_poro.roff": { "range": [0.15, 0.25], } } pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert pdf.dataframe["PORO"].mean() == pytest.approx(0.2027, abs=0.001) assert pdf.dataframe["PORO"].min() > 0.15 assert pdf.dataframe["PORO"].max() < 0.25
def test_props_and_selectors_as_list(self, data_grid): """Test""" data_grid["properties"] = ["reek_sim_poro.roff", "reek_sim_permx.roff"] data_grid["selectors"] = [ "reek_sim_zone.roff", "reek_sim_facies2.roff" ] pdf = GridProps2df(data=data_grid, project=None, xtgdata=QCData()) assert pdf.dataframe["reek_sim_poro.roff"].mean() == pytest.approx( 0.1677, abs=0.001) assert pdf.dataframe["reek_sim_poro.roff"].max() == pytest.approx( 0.3613, abs=0.001) assert set(pdf.dataframe.columns) == set([ "reek_sim_poro.roff", "reek_sim_permx.roff", "reek_sim_zone.roff", "reek_sim_facies2.roff", ])
def test_qcdata(): """Testing getting data with _QCForwardData class""" qcdata = QCData() qcdata.parse(data=DATA1) assert isinstance(qcdata, QCData) assert isinstance(qcdata.grid, xtgeo.Grid) assert isinstance(qcdata.gridprops, xtgeo.GridProperties) assert isinstance(qcdata.wells, xtgeo.Wells) assert qcdata._project is None assert qcdata.grid.ncol == 40 zone = qcdata.gridprops.get_prop_by_name(ZONENAME) assert isinstance(zone, xtgeo.GridProperty) assert zone.name == ZONENAME assert zone.values.mean() == pytest.approx(1.92773, abs=0.01) assert zone.ncol == 40 op1 = qcdata.wells.get_well("OP_1") assert ZONELOGNAME in op1.dataframe.columns
def run( self, data: Union[dict, str], reuse: Optional[bool] = False, project: Optional[Any] = None, ): """Main routine for evaluating blockedwells vs gridproperties The routine depends on existing XTGeo functions for this purpose. Args: data (dict or str): The input data either as a Python dictionary or a path to a YAML file reuse (bool or list): Reusing some "timeconsuming to read" data in the instance. If True, then grid and gridprops will be reused as default. Alternatively it can be a list for more fine grained control, e.g. ["grid", "gridprops", "bwells"] project (Union[object, str]): For usage inside RMS, None if running files """ self._data = self.handle_data(data, project) self._validate_input(self._data, project) QCC.verbosity = self._data.get("verbosity", 0) # parse data that are special for this check QCC.print_info("Parsing additional data...") self.ldata = _LocalData() self.ldata.parse_data(self._data) # now need to retrieve blocked properties and grid properties from the "compare" # dictionary: wsettings = {"lognames": list(self.ldata.compare.keys())} if project: # inside RMS, get gridprops implicitly from compare values self._data["gridprops"] = list(self.ldata.compare.values()) if not isinstance(self.gdata, QCData): self.gdata = QCData() self.gdata.parse(data=self._data, reuse=reuse, project=project, wells_settings=wsettings) dfr, comb = self.compare_bw_props() QCC.print_debug(f"Results: \n{dfr}") status = self.evaluate_qcreport(dfr, "blocked wells vs grid props", stopaction=False) # make it possible to print the underlying dataframe, either some wells (.e.g # the failing) or all wells. If 'fail' it will only show those lines that # contains FAIL show = self.ldata.show_data if show is None or show is False: pass elif isinstance(show, dict): if "lines" not in show or "wellstatus" not in show: raise ValueError( f"The 'showdata' entry is in an invalid form or format: {show}" ) lines = show["lines"].upper() wstatus = show["wellstatus"].upper() print( f"\n** Key 'show_data' is active, here showing lines with {lines} " f"for wells classified as {wstatus} **") # filter out all line with word FAIL or WARN or ... , h/t HAVB fcomb = comb[comb.astype(str).agg("".join, axis=1).str.contains(lines)] if len(fcomb) > 0: mask = dfr["STATUS"] == wstatus wells = [ well for well in dfr[mask]["WELL"].unique() if well != "all" ] if wells: print(f"Wells within {wstatus} criteria are: {wells}:\n") print(fcomb[fcomb["WELLNAME"].isin(wells)].to_string()) else: print(f"No wells within {wstatus} criteria") else: print(f"No lines are matching {lines}. Wrong input?:\n") else: print("Show all well cells for all wells:") if len(comb) > 0: print(comb.to_string()) if status == "STOP": QCC.force_stop("STOP criteria is found!")