def df( deck: Union[str, EclFiles, "opm.libopmcommon_python.Deck"], keywords: Optional[List[str]] = None, ntequl: Optional[int] = None, ) -> pd.DataFrame: """Extract EQUIL related keyword data, EQUIL, RSVD, RVVD PBVD and PDVD. How each data value in the EQUIL records are to be interpreted depends on the phase configuration in the deck, which means that we need more than the EQUIL section alone to determine the dataframe. If ntequl is not supplied and EQLDIMS is not in the deck, the equil data is not well defined in terms of OPM. This means that we have to infer the correct number of EQUIL lines from what gives us successful parsing from OPM. In those cases, the deck must be supplied as a string, if not, extra EQUIL lines are possibly already removed by the OPM parser in eclfiles.str2deck(). Arguments: deck: Eclipse deck or string with deck. If not string, EQLDIMS must be present in the deck. keywords: Requested keywords for which to extract data. ntequl: If not None, should state the NTEQUL in EQLDIMS. If None and EQLDIMS is not present, it will be inferred. Return: pd.DataFrame, at least with columns KEYWORD and EQLNUM """ if isinstance(deck, EclFiles): deck = deck.get_ecldeck() deck = inferdims.inject_xxxdims_ntxxx("EQLDIMS", "NTEQUL", deck, ntequl) ntequl = deck["EQLDIMS"][0][inferdims.DIMS_POS["NTEQUL"]].get_int(0) wanted_keywords = common.handle_wanted_keywords(keywords, deck, SUPPORTED_KEYWORDS) frames = [] for keyword in wanted_keywords: # Construct the associated function names function_name = keyword.lower() + "_fromdeck" function = globals()[function_name] dframe = function(deck, ntequl=ntequl) frames.append(dframe.assign(KEYWORD=keyword)) nonempty_frames = [frame for frame in frames if not frame.empty] if nonempty_frames: dframe = pd.concat(nonempty_frames, axis=0, sort=False, ignore_index=True) logger.info( "Extracted keywords %s for %g EQLNUMs", dframe["KEYWORD"].unique(), len(dframe["EQLNUM"].unique()), ) return dframe logger.warning("No equil data found") return pd.DataFrame()
def df(deck, keywords=None, ntsfun=None): """Extract the data in the saturation function keywords as a Pandas DataFrames. Data for all saturation functions are merged into one dataframe. The two first columns in the dataframe are 'KEYWORD' (which can be SWOF, SGOF, etc.), and then SATNUM which is an index counter from 1 and onwards. Then follows the data for each individual keyword that is found in the deck. SATNUM data can only be parsed correctly if TABDIMS is present and stating how many saturation functions there should be. If you have a string with TABDIMS missing, you must supply this as a string to this function, and not a parsed deck, as the default parser in EclFiles is very permissive (and only returning the first function by default). Arguments: deck (opm.io deck or str): Incoming data deck. Always supply as a string if you don't know TABDIMS-NTSFUN. keywords (list of str): Requested keywords for which to to extract data. ntsfun (int): Number of SATNUMs defined in the deck, only needed if TABDIMS with NTSFUN is not found in the deck. If not supplied (or None) and NTSFUN is not defined, it will be attempted inferred. Return: pd.DataFrame, columns 'KEYWORD', 'SW', 'KRW', 'KROW', 'PC', .. """ if isinstance(deck, EclFiles): # NB: If this is done on include files and not on DATA files # we can loose data for SATNUM > 1 deck = deck.get_ecldeck() deck = inferdims.inject_xxxdims_ntxxx("TABDIMS", "NTSFUN", deck, ntsfun) assert "TABDIMS" in deck ntsfun = deck["TABDIMS"][0][inferdims.DIMS_POS["NTSFUN"]].get_int(0) keywords = common.handle_wanted_keywords(keywords, deck, SUPPORTED_KEYWORDS) frames = [] for keyword in keywords: # Construct the associated function names function_name = keyword.lower() + "_fromdeck" function = globals()[function_name] dframe = function(deck, ntsfun=ntsfun) frames.append(dframe.assign(KEYWORD=keyword)) nonempty_frames = [frame for frame in frames if not frame.empty] if nonempty_frames: dframe = pd.concat(nonempty_frames, axis=0, sort=False, ignore_index=True) # We want to sort the keywords by the order they appear in # SUPPORTED_KEYWORDS (mainly to get WaterOil before GasOil) # We do that by converting to a Categorical series: dframe["KEYWORD"] = pd.Categorical(dframe["KEYWORD"], SUPPORTED_KEYWORDS) dframe.sort_values(["SATNUM", "KEYWORD"], inplace=True) dframe["KEYWORD"] = dframe["KEYWORD"].astype(str) return dframe return pd.DataFrame()
def df( deck: Union[str, "opm.libopmcommon_python.Deck"], keywords: Optional[List[str]] = None, ntpvt: Optional[int] = None, ) -> pd.DataFrame: """Extract all (most) PVT data from a deck. If you want to call this function on Eclipse include files, read them in to strings as in this example: > pvt_df = pvt.df(open("pvt.inc").read()) Arguments: deck: Incoming data deck. Always supply as a string if you don't know TABDIMS-NTSFUN. keywords: List of keywords for which data is wanted. All data will be merged into one dataframe. pvtnumcount: Number of PVTNUMs defined in the deck, only needed if TABDIMS with NTPVT is not found in the deck. If not supplied (or None) and NTPVT is not defined, it will be attempted inferred. Return: pd.DataFrame """ if isinstance(deck, EclFiles): deck = deck.get_ecldeck() deck = inferdims.inject_xxxdims_ntxxx("TABDIMS", "NTPVT", deck, ntpvt) ntpvt = deck["TABDIMS"][0][inferdims.DIMS_POS["NTPVT"]].get_int(0) wanted_keywords = common.handle_wanted_keywords(keywords, deck, SUPPORTED_KEYWORDS) frames = [] for keyword in wanted_keywords: # Construct the associated function names function_name = keyword.lower() + "_fromdeck" function = globals()[function_name] dframe = function(deck, ntpvt=ntpvt) frames.append(dframe.assign(KEYWORD=keyword)) nonempty_frames = [frame for frame in frames if not frame.empty] if nonempty_frames: return pd.concat(nonempty_frames, axis=0, sort=False, ignore_index=True) return pd.DataFrame()
def test_handle_wanted_keywords(wanted, deckstr, supported, expected): """Test that we can handle list of wanted, supported and available keywords.""" deck = eclfiles.EclFiles.str2deck(deckstr) assert common.handle_wanted_keywords(wanted, deck, supported) == expected
def df( deck: Union[str, "opm.libopmcommon_python.Deck"], keywords: Optional[List[str]] = None, ntsfun: Optional[int] = None, ) -> pd.DataFrame: """Extract the data in the saturation function keywords as a Pandas DataFrames. Data for all saturation functions are merged into one dataframe. The two first columns in the dataframe are 'KEYWORD' (which can be SWOF, SGOF, etc.), and then SATNUM which is an index counter from 1 and onwards. Then follows the data for each individual keyword that is found in the deck. SATNUM data can only be parsed correctly if TABDIMS is present and stating how many saturation functions there should be. If you have a string with TABDIMS missing, you must supply this as a string to this function, and not a parsed deck, as the default parser in EclFiles is very permissive (and only returning the first function by default). Arguments: deck: Incoming data deck. Always supply as a string if you don't know TABDIMS-NTSFUN. keywords: Requested keywords for which to to extract data. ntsfun: Number of SATNUMs defined in the deck, only needed if TABDIMS with NTSFUN is not found in the deck. If not supplied (or None) and NTSFUN is not defined, it will be attempted inferred. Return: pd.DataFrame, columns 'KEYWORD', 'SW', 'KRW', 'KROW', 'PC', .. """ if isinstance(deck, EclFiles): # NB: If this is done on include files and not on DATA files # we can loose data for SATNUM > 1 deck = deck.get_ecldeck() deck = inferdims.inject_xxxdims_ntxxx("TABDIMS", "NTSFUN", deck, ntsfun) assert "TABDIMS" in deck wanted_keywords = common.handle_wanted_keywords(keywords, deck, SUPPORTED_KEYWORDS) frames = [] for keyword in wanted_keywords: frames.append( interpolate_defaults( common.ecl_keyworddata_to_df( deck, keyword, renamer=RENAMERS[keyword], recordcountername="SATNUM").assign(KEYWORD=keyword))) nonempty_frames = [frame for frame in frames if not frame.empty] if nonempty_frames: dframe = pd.concat(nonempty_frames, axis=0, sort=False, ignore_index=True) # We want to sort the keywords by the order they appear in # SUPPORTED_KEYWORDS (mainly to get WaterOil before GasOil) # We do that by converting to a Categorical series: dframe["KEYWORD"] = pd.Categorical(dframe["KEYWORD"], SUPPORTED_KEYWORDS) dframe.sort_values(["SATNUM", "KEYWORD"], inplace=True) dframe["KEYWORD"] = dframe["KEYWORD"].astype(str) logger.info( "Extracted keywords %s for %i SATNUMs", dframe["KEYWORD"].unique(), len(dframe["SATNUM"].unique()), ) return dframe return pd.DataFrame()