Esempio n. 1
0
    def estimate_sorg(self):
        """Estimate sorg of the current krg or krog data.

        sorg is estimated by searching for a linear part in krg downwards
        from sg=1-swl. In practice it is impossible to infer sorg = 0,
        since we are limited by h, and the last segment from sg=1-swl-h
        to sg=1-swl can always be assumed linear.

        If krgend is anchored to sorg, krg data is used to infer sorg. If not,
        krg cannot be used for this, and krog is used. sorg might be overestimated
        when krog is used if it very close to zero before reaching sorw.

        If the curve is linear everywhere, sorg will be returned as sgcr + h

        Args:
            None
        Returns:
            float: The estimated sorg.
        """
        if self.krgendanchor == "sorg":
            assert "krg" in self.table
            assert self.table["krg"].sum() > 0
            return self.table["sg"].max() - utils.estimate_diffjumppoint(
                self.table, xcol="sg", ycol="krg", side="right")
        assert "krog" in self.table
        assert self.table["krog"].sum() > 0
        return self.table["sg"].max() - utils.estimate_diffjumppoint(
            self.table, xcol="sg", ycol="krog", side="right")
Esempio n. 2
0
    def estimate_sorw(self, curve="krw"):
        """Estimate sorw of the current krw data.

        This is mostly relevant when add_fromtable() has been used.
        sorw is estimated by searching for a linear part in krw downwards from sw=1.
        In practice it is impossible to infer sorw = 0, since we are limited by
        h, and the last segment from sw=1-h to sw=1 can always be assumed linear.
        Expect sorw = h if the real sorw = 0, but do not depend that it might
        not return zero in the future (one could argue that sorw = h should be
        specially treated to mean sorw = 0)

        If the curve is linear everywhere, sorw will be returned as swl + h

        krow is not used, and should probably not be, as it can be very close to
        zero before approaching sorw.

        Args:
            curve (str): Colum name of column to use, default is krw.
                If this is all linear, but krow is not, you might be better off
                with krow
        Returns:
            float: The estimated sorw.
        """
        assert curve in self.table
        assert self.table[curve].sum() > 0
        return self.table["sw"].max() - utils.estimate_diffjumppoint(
            self.table, xcol="sw", ycol=curve, side="right"
        )
Esempio n. 3
0
def test_diffjumppoint():
    """Test estimator for the jump in first derivative for some manually set up cases.

    This code is also extensively tested throuth test_addfromtable"""

    dframe = pd.DataFrame(columns=["x", "y"],
                          data=[[0, 0], [0.3, 0.2], [1, 1]])

    assert utils.estimate_diffjumppoint(dframe, side="right") == 0.3
    assert utils.estimate_diffjumppoint(dframe, side="left") == 0.3

    dframe = pd.DataFrame(columns=["x", "y"], data=[[0, 0], [1, 1]])
    # We don't really care what gets printed from this, just don't crash..
    assert 0 <= utils.estimate_diffjumppoint(dframe, side="right") <= 1
    assert 0 <= utils.estimate_diffjumppoint(dframe, side="left") <= 1

    dframe = pd.DataFrame(
        columns=["x", "y"],
        data=[
            [0, 0],
            [0.1, 0.1],
            [0.2, 0.2],  # Linear until here
            [0.3, 0.4],  # Nonlinear region
            [0.4, 0.45],  # Nonlinear region
            [0.7, 0.7],  # Linear from here
            [0.8, 0.8],
            [1, 1],
        ],
    )
    assert utils.estimate_diffjumppoint(dframe, side="left") == 0.2
    assert utils.estimate_diffjumppoint(dframe, side="right") == 0.7

    dframe = pd.DataFrame(
        columns=["x", "y"],
        data=[
            [0, 0],
            [0.1, 0.0],
            [0.2, 0.0],  # Linear until here
            [0.3, 0.4],  # Nonlinear region
            [0.9, 1],  # Start linear region again
            [1, 1],
        ],
    )
    assert utils.estimate_diffjumppoint(dframe, side="left") == 0.2
    assert utils.estimate_diffjumppoint(dframe, side="right") == 0.9
Esempio n. 4
0
    def estimate_sgcr(self, curve="krog"):
        """Estimate sgcr of the current krog data.

        sgcr is estimated by searching for a linear part in krog upwards from sg=0.
        In practice it is impossible to infer sgcr = 0, since we are limited by
        h, and we always have to assume that the first segment is linear.

        If the curve is linear everywhere, sgcr will be returned as the right endpoint.

        Args:
            curve (str): Column name to use for search for linearity. Default is krog,
                if all of that is linear, you may try krg instead.
        Returns:
            float: The estimated sgcr.
        """
        assert curve in self.table
        assert self.table[curve].sum() > 0
        return utils.estimate_diffjumppoint(
            self.table, xcol="sg", ycol=curve, side="left"
        )
Esempio n. 5
0
    def estimate_swcr(self, curve="krow"):
        """Estimate swcr of the current krw data.

        swcr is estimated by searching for a linear part in krw upwards from sw=swl.
        In practice it is impossible to infer swcr = 0, since we are limited by
        h, and the first segment is assumed linear anyways.

        If the curve is linear everywhere, swcr can end up at the right end
        of your saturation interval.

        Args:
            curve (str): Colum name of column to use, default is krow.
                If this is all linear, but krw is not, you might be better off
                with krw
        Returns:
            float: The estimated sgcr.
        """
        assert curve in self.table
        assert self.table[curve].sum() > 0
        return utils.estimate_diffjumppoint(
            self.table, xcol="sw", ycol=curve, side="left"
        )
Esempio n. 6
0
    def add_fromtable(
        self,
        df,
        swcolname="Sw",
        krwcolname="krw",
        krowcolname="krow",
        pccolname="pcow",
        krwcomment="",
        krowcomment="",
        pccomment="",
        sorw=None,
    ):
        """Interpolate relpermdata from a dataframe.

        The saturation range with endpoints must be set up beforehand,
        and must be compatible with the tabular input. The tabular
        input will be interpolated to the initialized Sw-table

        If you have krw and krow in different dataframes, call this
        function twice

        Calling function is responsible for checking if any data was
        actually added to the table.

        The relpermdata will be interpolated using a monotone cubic
        interpolator below 1-sorw, and linearly above 1-sorw. Capillary
        pressure data will be interpolated monotone cubicly over the
        entire saturation interval

        The python package ecl2df has a tool for converting Eclipse input
        files to dataframes.

        Args:
            df (pd.DataFrame): containing data
            swcolname (string): column name with the saturation data in the dataframe df
            krwcolname (string): name of column in df with krw
            krowcolname (string): name of column in df with krow
            pccolname (string): name of column in df with capillary pressure data
            krwcomment (string): Inserted into comment
            krowcomment (string): Inserted into comment
            pccomment (str): Inserted into comment
            sorw (float): Explicit sorw. If None, it will be estimated from
                the numbers in krw (or krow)
        """
        from scipy.interpolate import PchipInterpolator, interp1d

        # Avoid having to deal with multi-indices:
        if len(df.index.names) > 1:
            logging.warning(
                "add_fromtable() did a reset_index(), consider not supplying MultiIndex"
            )
            df = df.reset_index()

        if swcolname not in df:
            logging.critical(
                swcolname + " not found in dataframe, can't read table data"
            )
            raise ValueError
        if (df[swcolname].diff() < 0).any():
            raise ValueError("sw data not sorted")
        if krwcolname in df:
            if not sorw:
                sorw = df[swcolname].max() - utils.estimate_diffjumppoint(
                    df, xcol=swcolname, ycol=krwcolname, side="right"
                )
                logging.info("Estimated sorw in tabular data to %f", sorw)
            assert -epsilon <= sorw <= 1 + epsilon
            linearpart = df[swcolname] >= 1 - sorw
            nonlinearpart = df[swcolname] <= 1 - sorw  # (overlapping at sorw)
            if sum(linearpart) < 2:
                linearpart = pd.Series([False] * len(linearpart))
                nonlinearpart = ~linearpart
                sorw = 0
            if sum(nonlinearpart) < 2:
                nonlinearpart = pd.Series([False] * len(nonlinearpart))
                linearpart = ~nonlinearpart
            if not np.isclose(df[swcolname].min(), self.table["sw"].min()):
                raise ValueError("Incompatible swl")
            # Verify that incoming data is increasing (or level):
            if not (df[krwcolname].diff().dropna() > -epsilon).all():
                raise ValueError("Incoming krw not increasing")
            if sum(nonlinearpart) >= 2:
                pchip = PchipInterpolator(
                    df[nonlinearpart][swcolname].astype(float),
                    df[nonlinearpart][krwcolname].astype(float),
                )
                self.table.loc[self.table["sw"] <= 1 - sorw, "krw"] = pchip(
                    self.table.loc[self.table["sw"] <= 1 - sorw, "sw"]
                )
            if sum(linearpart) >= 2:
                linearinterpolator = interp1d(
                    df[linearpart][swcolname].astype(float),
                    df[linearpart][krwcolname].astype(float),
                )
                self.table.loc[self.table["sw"] > 1 - sorw, "krw"] = linearinterpolator(
                    self.table.loc[self.table["sw"] > 1 - sorw, "sw"]
                )
            self.sorw = sorw
            self.krwcomment = "-- krw from tabular input" + krwcomment + "\n"

        if krowcolname in df:
            if not sorw:
                sorw = df[swcolname].max() - utils.estimate_diffjumppoint(
                    df, xcol=swcolname, ycol=krowcolname, side="right"
                )
                logging.info("Estimated sorw in tabular data from krow to %s", sorw)
            assert -epsilon <= sorw <= 1 + epsilon
            linearpart = df[swcolname] >= 1 - sorw
            nonlinearpart = df[swcolname] <= 1 - sorw  # (overlapping at sorw)
            if sum(linearpart) < 2:
                linearpart = pd.Series([False] * len(linearpart))
                nonlinearpart = ~linearpart
                sorw = 0
            if sum(nonlinearpart) < 2:
                nonlinearpart = pd.Series([False] * len(nonlinearpart))
                linearpart = ~nonlinearpart
            if not np.isclose(df[swcolname].min(), self.table["sw"].min()):
                raise ValueError("Incompatible swl")
            if not (df[krowcolname].diff().dropna() < epsilon).all():
                raise ValueError("Incoming krow not decreasing")
            if sum(nonlinearpart) >= 2:
                pchip = PchipInterpolator(
                    df[nonlinearpart][swcolname].astype(float),
                    df[nonlinearpart][krowcolname].astype(float),
                )
                self.table.loc[self.table["sw"] <= 1 - sorw, "krow"] = pchip(
                    self.table.loc[self.table["sw"] <= 1 - sorw, "sw"]
                )
            if sum(linearpart) >= 2:
                linearinterpolator = interp1d(
                    df[linearpart][swcolname].astype(float),
                    df[linearpart][krowcolname].astype(float),
                )
                self.table.loc[
                    self.table["sw"] > 1 - sorw, "krow"
                ] = linearinterpolator(
                    self.table.loc[self.table["sw"] > 1 - sorw, "sw"]
                )
            self.sorw = sorw
            self.krowcomment = "-- krow from tabular input" + krowcomment + "\n"
        if pccolname in df:
            # Incoming dataframe must cover the range:
            if df[swcolname].min() > self.table["sw"].min():
                raise ValueError("Too large swl for pc interpolation")
            if df[swcolname].max() < self.table["sw"].max():
                raise ValueError("max(sw) of incoming data not large enough")
            if np.isinf(df[pccolname]).any():
                logging.warning(
                    (
                        "Infinity pc values detected. Will be dropped. "
                        "Risk of extrapolation"
                    )
                )
            df = df.replace([np.inf, -np.inf], np.nan)
            df.dropna(subset=[pccolname], how="all", inplace=True)
            # If nonzero, then it must be decreasing:
            if df[pccolname].abs().sum() > 0:
                if not (df[pccolname].diff().dropna() < 0.0).all():
                    raise ValueError("Incoming pc not decreasing")
            pchip = PchipInterpolator(
                df[swcolname].astype(float), df[pccolname].astype(float)
            )
            self.table["pc"] = pchip(self.table["sw"])
            if np.isnan(self.table["pc"]).any() or np.isinf(self.table["pc"]).any():
                raise ValueError("inf/nan in interpolated data, check input")
            self.pccomment = "-- pc from tabular input" + pccomment + "\n"