def test_gasoil_gascond_fails():
    """Interpolation between an object for gas condendensate (sgro > 0)
    and an object with sgro = 0 (regular gas-oil) should fail"""
    gascond = GasOil(sgro=0.1, sgcr=0.1)
    gasoil = GasOil(sgro=0.0, sgcr=0.1)

    gasoil.add_corey_gas()
    gasoil.add_corey_oil()
    gascond.add_corey_gas()
    gascond.add_corey_oil()

    # interpolation parameter at zero is no interpolation, just lookup,
    # so it works fine:
    check_table(interpolate_go(gasoil, gascond, parameter=0.0).table)
    check_table(interpolate_go(gasoil, gascond, parameter=epsilon).table)
    check_table(interpolate_go(gasoil, gascond, parameter=10 * epsilon).table)

    with pytest.raises(ValueError, match="Interpolated sgro"):
        interpolate_go(gasoil, gascond, parameter=100 * epsilon)

    with pytest.raises(ValueError, match="Interpolated sgro"):
        interpolate_go(gasoil, gascond, parameter=0.5)

    check_table(interpolate_go(gasoil, gascond, parameter=1.0 - epsilon).table)
    check_table(interpolate_go(gasoil, gascond, parameter=1.0).table)
示例#2
0
def test_tag_preservation():
    """Test that we can preserve tags/comments through interpolation"""
    wo_low = WaterOil(swl=0.1)
    wo_high = WaterOil(swl=0.2)
    wo_low.add_corey_water(nw=2)
    wo_high.add_corey_water(nw=3)
    wo_low.add_corey_oil(now=2)
    wo_high.add_corey_oil(now=3)
    interpolant1 = interpolate_wo(wo_low, wo_high, parameter=0.1, h=0.2)
    assert "Interpolated to 0.1" in interpolant1.tag
    sat_table_str_ok(interpolant1.SWOF())

    wo_high.tag = "FOOBAR"
    interpolant2 = interpolate_wo(wo_low, wo_high, parameter=0.1, h=0.2)
    assert "Interpolated to 0.1" in interpolant2.tag
    assert "between" in interpolant2.tag
    assert wo_high.tag in interpolant2.tag
    sat_table_str_ok(interpolant2.SWOF())
    # wo_low.tag was empty deliberately here.

    # When wo_log and wo_high has the same tag:
    wo_low.tag = "FOOBAR"
    interpolant3 = interpolate_wo(wo_low, wo_high, parameter=0.1, h=0.2)
    assert "Interpolated to 0.1" in interpolant3.tag
    assert "between" not in interpolant3.tag
    assert wo_high.tag in interpolant3.tag
    sat_table_str_ok(interpolant3.SWOF())

    # Explicit tag:
    interpolant4 = interpolate_wo(
        wo_low, wo_high, parameter=0.1, h=0.2, tag="Explicit tag"
    )
    assert interpolant4.tag == "Explicit tag"

    # Tag with newline
    interpolant6 = interpolate_wo(
        wo_low, wo_high, parameter=0.1, h=0.2, tag="Explicit tag\non two lines"
    )
    assert "Explicit tag" in interpolant6.tag
    print(interpolant6.SWOF())
    sat_table_str_ok(interpolant6.SWOF())

    # Empty tag:
    interpolant5 = interpolate_wo(wo_low, wo_high, parameter=0.1, h=0.2, tag="")
    assert interpolant5.tag == ""

    # Also sample check for GasOil (calls the same code)
    go_low = GasOil()
    go_high = GasOil()
    go_low.add_corey_gas(ng=2)
    go_high.add_corey_gas(ng=3)
    go_low.add_corey_oil(nog=2)
    go_high.add_corey_oil(nog=3)
    interpolant1 = interpolate_go(go_low, go_high, parameter=0.1, h=0.2)
    assert "Interpolated to 0.1" in interpolant1.tag
    sat_table_str_ok(interpolant1.SGOF())
def test_gascond_interpolation(sgro_low, sgro_high):
    """sgro is required to be either 0 or sgcr, and interpolations
    will crash when this is not the case. This test validates that
    we can let sgro and sgcr go to zero, and that we always are able
    to interpolate without crashes."""
    go_low = GasOil(sgro=sgro_low, sgcr=sgro_low)
    go_high = GasOil(sgro=sgro_high, sgcr=sgro_high)
    go_low.add_corey_gas()
    go_low.add_corey_oil()
    go_high.add_corey_gas()
    go_high.add_corey_oil()

    go_ip = interpolate_go(go_low, go_high, parameter=0.5)
    check_table(go_ip.table)
def test_ip_go_kroendmax():
    """Test behaviour of kroend/kromax under interpolation, gas condensate modelling"""
    go_low = GasOil(swl=0, sgro=0.1, sgcr=0.1)
    go_high = GasOil(swl=0, sgro=0)
    go_low.add_corey_gas()
    go_low.add_corey_oil(nog=2, kroend=0.5, kromax=1)
    go_high.add_corey_gas()
    go_high.add_corey_oil(nog=2, kroend=1)

    # Interpolate to midpoint between the curves above
    go_ip = interpolate_go(go_low, go_high, 0.5)

    # kro(sg=0) is 1 for all interpolants:
    assert float_df_checker(go_ip.table, "SG", 0.0, "KROG", 1.0)

    # kro(sg=mean(sgro)) = mean kroeend
    assert float_df_checker(go_ip.table, "SG", (0 + 0.1) / 2.0, "KROG", 0.75)

    assert np.isclose(go_ip.estimate_sgro(), (0 + 0.1) / 2.0)
示例#5
0
def test_interpolations_go_fromtable():
    """Test based on bug exposed in pyscal 0.6.1, where sgcr
    was underestimated in interpolations following add_fromtable().
    """
    base = pd.DataFrame(
        columns=["Sg", "krg", "krog"],
        data=[
            [0.0, 0.0, 1.0],
            [0.1, 0.0, 1.0],
            [0.2, 0.0, 1.0],  # sgcr
            [0.3, 0.1, 0.9],
            [0.8, 0.8, 0.0],  # sorg
            [0.9, 0.9, 0.0],
            [1.0, 1.0, 0.0],
        ],
    )
    opt = pd.DataFrame(
        columns=["Sg", "krg", "krog"],
        data=[
            [0.0, 0.0, 1.0],
            [0.1, 0.0, 1.0],
            [0.3, 0.0, 1.0],
            [0.4, 0.1, 0.2],  # sgcr
            [0.9, 0.9, 0.0],  # sorg
            [0.95, 0.95, 0.0],
            [1.0, 1.0, 0.0],
        ],
    )
    go_base = GasOil(h=0.01)
    go_base.add_fromtable(base)
    assert np.isclose(go_base.estimate_sgcr(), 0.2)
    assert np.isclose(go_base.estimate_sorg(), 0.2)
    go_opt = GasOil(h=0.01)
    go_opt.add_fromtable(opt)
    assert np.isclose(go_opt.estimate_sgcr(), 0.3)
    assert np.isclose(go_opt.estimate_sorg(), 0.1)

    go_ip = interpolate_go(go_base, go_opt, 0.5, h=0.01)
    assert np.isclose(go_ip.estimate_sgcr(), 0.25)
    assert np.isclose(go_ip.estimate_sorg(), 0.15)
示例#6
0
def test_interpolate_go(
    swl,
    sgcr,
    dsgcr,
    dswlhigh,
    sorg,
    dsorg,
    ng_l,
    ng_h,
    nog_l,
    nog_h,
    krgend_l,
    krgend_h,
    kroend_l,
    kroend_h,
):
    # pylint: disable=too-many-arguments,too-many-locals
    """Test many possible combinations of interpolation between two
    Corey gasoil curves, looking for numerical corner cases"""
    h = 0.01
    go_low = GasOil(swl=swl, sgcr=sgcr, sorg=sorg, h=h)
    go_high = GasOil(
        swl=swl + dswlhigh, sgcr=sgcr + dsgcr, sorg=max(sorg - dsorg, 0), h=h
    )
    go_low.add_corey_gas(ng=ng_l, krgend=krgend_l)
    go_high.add_corey_gas(ng=ng_h, krgend=krgend_h)
    go_low.add_corey_oil(nog=nog_l, kroend=kroend_l)
    go_high.add_corey_oil(nog=nog_h, kroend=kroend_h)
    ips = []
    ip_dist = 0.05
    for t in np.arange(0, 1 + ip_dist, ip_dist):
        go_ip = interpolate_go(go_low, go_high, t)
        check_table(go_ip.table)
        ips.append(go_ip)
        assert 0 < go_ip.crosspoint() < 1

        # sgcr is non-trivial, if exponents are high, an effective sgcr might
        # be larger than the value used to initialize the curve. Try to be
        # permissive enough here. This can even cause the interpolant to be
        # outside the low-high envelope, but it is the way it is supposed to
        # be when sgcr is interpolated separately.
        sgcr_low = min(
            go_low.sgcr, go_low.estimate_sgcr(), go_high.sgcr, go_high.estimate_sgcr()
        )
        sgcr_high = max(
            go_low.sgcr, go_low.estimate_sgcr(), go_high.sgcr, go_high.estimate_sgcr()
        )

        sgcr_ip = go_ip.estimate_sgcr()

        sgcr_lower_bound_ok = sgcr_low - h - epsilon < sgcr_ip
        sgcr_upper_bound_ok = sgcr_ip < sgcr_high + h + epsilon

        assert sgcr_lower_bound_ok
        assert sgcr_upper_bound_ok

    # Distances between low and interpolants:
    dists = [
        (go_low.table - interp.table)[["krg", "krog"]].sum().sum() for interp in ips
    ]
    print(
        "Interpolation, mean: {}, min: {}, max: {}, std: {} ip-par-dist: {}".format(
            np.mean(dists), min(dists), max(dists), np.std(np.diff(dists[1:])), ip_dist
        )
    )
    assert np.isclose(dists[0], 0)  # Reproducing go_low
    # All curves that are close in parameter t, should be close in sum().sum().
    # That means that diff of the distances should be similar,
    # that is the std.dev of the distances is low:
    ip_dist_std = np.std(
        np.diff(dists[1:])
    )  # This number depends on 'h' and 't' range, and
    # by how different the low and high is.
    # (avoiding the first which reproduces go_low
    if ip_dist_std > 1.0:  # number found from trial and error.
        print("ip_dist_std: {}".format(ip_dist_std))
        print(dists)
        _, mpl_ax = plt.subplots()
        go_low.plotkrgkrog(mpl_ax=mpl_ax, color="red")
        go_high.plotkrgkrog(mpl_ax=mpl_ax, color="blue")
        for interp in ips:
            interp.plotkrgkrog(mpl_ax=mpl_ax, color="green")
        plt.show()
        assert False
示例#7
0
def test_ip_go_kroend():
    """Test behaviour of kroend under interpolation"""
    go_low = GasOil(swl=0, sgcr=0.1, sorg=0.2)
    go_low.add_corey_gas(ng=2, krgend=0.5, krgmax=0.7)
    go_low.add_corey_oil(nog=2, kroend=0.6)

    go_high = GasOil(swl=0.02, sgcr=0.05, sorg=0.1)
    go_high.add_corey_gas(ng=2, krgend=0.5, krgmax=0.72)
    go_high.add_corey_oil(nog=2, kroend=0.7)

    # Interpolate to midpoint between the curves above
    go_ip = interpolate_go(go_low, go_high, 0.5)

    # kroend at sg zero:
    assert float_df_checker(go_ip.table, "sg", 0.0, "krog", (0.6 + 0.7) / 2.0)

    assert np.isclose(go_ip.swl, 0.01)
    assert np.isclose(go_ip.sorg, 0.15)

    # krgmax at 1 - swl:
    assert float_df_checker(go_ip.table, "sg", 1 - go_ip.swl, "krg", 0.71)
    # krgend at 1 - swl - sorg
    assert float_df_checker(go_ip.table, "sg", 1 - go_ip.swl - go_ip.sorg, "krg", 0.5)

    # If krgendanchor is None, then krgmax should be irrelevant
    go_low = GasOil(swl=0, sgcr=0.1, sorg=0.2, krgendanchor="")
    go_low.add_corey_gas(ng=5, krgend=0.5, krgmax=0.7)
    # krgmax will trigger warning message, intended, as the 0.7
    # value here will mean nothing.
    go_low.add_corey_oil(nog=2, kroend=0.6)

    go_high = GasOil(swl=0.02, sgcr=0.05, sorg=0.1, krgendanchor="")
    go_high.add_corey_gas(ng=4, krgend=0.5, krgmax=0.72)
    # krgmax will trigger warning message, intended.
    go_high.add_corey_oil(nog=2, kroend=0.7)

    # Interpolate to midpoint between the curves above
    go_ip = interpolate_go(go_low, go_high, 0.5, h=0.1)

    assert float_df_checker(go_ip.table, "sg", 0.0, "krog", (0.6 + 0.7) / 2.0)

    # Activate these line to see a bug, interpolation_go
    # does not honor krgendanchorA:
    # _, mpl_ax = plt.subplots()
    # go_low.plotkrgkrog(mpl_ax=mpl_ax, color="red")
    # go_high.plotkrgkrog(mpl_ax=mpl_ax, color="blue")
    # go_ip.plotkrgkrog(mpl_ax=mpl_ax, color="green")
    # plt.show()

    # krgmax is irrelevant, krgend is used here:
    assert float_df_checker(go_ip.table, "sg", 1 - 0.01, "krg", 0.5)

    # Also check that estimated new sgcr is between the inputs:
    assert 0.05 <= go_ip.estimate_sgcr() <= 0.1

    # Do we get into trouble if krgendanchor is different in low and high?
    go_low = GasOil(swl=0, sgcr=0.1, sorg=0.2, krgendanchor="sorg")
    go_low.add_corey_gas(ng=2, krgend=0.5, krgmax=0.7)
    go_low.add_corey_oil(nog=2, kroend=0.6)

    go_high = GasOil(swl=0.02, sgcr=0.05, sorg=0.1, krgendanchor="")
    go_high.add_corey_gas(ng=2, krgend=0.5)
    go_high.add_corey_oil(nog=2, kroend=0.7)

    # Interpolate to midpoint between the curves above
    go_ip = interpolate_go(go_low, go_high, 0.5)

    assert float_df_checker(go_ip.table, "sg", 0.0, "krog", (0.6 + 0.7) / 2.0)

    # max(krg) is here avg of krgmax and krgend from the differnt tables:
    assert float_df_checker(go_ip.table, "sg", 1 - 0.01, "krg", 0.6)

    # krgend at 1 - swl - sorg, non-trivial expression, so a numerical
    # value is used here in the test:
    assert float_df_checker(go_ip.table, "sg", 1 - 0.01 - 0.15, "krg", 0.4491271)

    # krog-zero at 1 - swl - sorg:
    assert float_df_checker(go_ip.table, "sg", 1 - 0.01 - 0.15, "krog", 0)
示例#8
0
    def interpolate(self, parameter, parameter2=None, h=0.02):
        """Interpolate between low, base and high

        Endpoints are located for input curves, and interpolated
        individually. Interpolation for the nonlinear part
        is done on a normalized interval between the endpoints

        Interpolation is linear in relperm-direction, and will thus not be
        linear in log-relperm-direction

        This method returns an WaterOilGas object which can be
        realized into printed tables. No attempt is made to
        parametrize the interpolant in L,E,T parameter space, or Corey-space.

        Args:
            parameter (float): Between -1 and 1, inclusive. -1 reproduces low/
                pessimistic curve, 0 gives base, 1 gives high/optimistic.
            parameter2 (float): If not None, used for the gas-oil interpolation,
                enables having interpolation uncorrelated for WaterOil and
                GasOil. Ignored for GasWater (no warning).
            h (float): Saturation step length in generated tables. Does not
                need to be the same as the tables interpolation is done from.
        """

        if parameter2 is not None:
            gasparameter = parameter2
        else:
            gasparameter = parameter

        # Either wateroil or gasoil can be None in the low, base, high
        # If they are None, it is a two-phase problem and we
        # should support this.
        do_gaswater = False
        do_wateroil = False
        do_gasoil = False
        if self.type == GasWater:
            do_gaswater = True
        elif self.type == WaterOilGas:
            do_wateroil = (self.base.wateroil is not None
                           and self.low.wateroil is not None
                           and self.high.wateroil is not None)

            do_gasoil = (self.base.gasoil is not None
                         and self.low.gasoil is not None
                         and self.high.gasoil is not None)

        if not do_gaswater:
            if not do_wateroil and not do_gasoil:
                raise ValueError(
                    "Neither WaterOil or GasOil is complete in SCAL recommendation"
                )

        if parameter2 is not None:
            if not do_gasoil:
                logger.warning("parameter2 is meaningless for water-oil only")
            if do_gaswater:
                logger.warning("parameter2 is meaningless for gas-water")

        # Initialize wateroil and gasoil curves to be filled with
        # interpolated curves:

        tags = set()
        if do_wateroil or do_gaswater:
            tags = tags.union(
                set([
                    self.base.wateroil.tag,
                    self.low.wateroil.tag,
                    self.high.wateroil.tag,
                ]))
        if do_gasoil:
            tags = tags.union(
                set([
                    self.base.gasoil.tag, self.low.gasoil.tag,
                    self.high.gasoil.tag
                ]))
        tagstring = "\n".join(tags)
        if do_gaswater:
            interpolant = GasWater(h=h, tag=tagstring)
            if gasparameter != parameter:
                logger.warning(
                    "Different interpolation parameters for Water and for "
                    "gas in GasWater, this is maybe not what you want")
        else:
            interpolant = WaterOilGas(h=h, tag=tagstring)

        if do_wateroil or do_gaswater:
            tag = (
                "SCAL recommendation interpolation to {}\n".format(parameter) +
                tagstring)
            if abs(parameter) > 1.0:
                logger.error("Interpolation parameter must be in [-1,1]")
                assert abs(parameter) <= 1.0
            elif np.isclose(parameter, 0.0):
                interpolant.wateroil = copy.deepcopy(self.base.wateroil)
                interpolant.wateroil.tag = tag
            elif np.isclose(parameter, -1.0):
                interpolant.wateroil = copy.deepcopy(self.low.wateroil)
                interpolant.wateroil.tag = tag
            elif np.isclose(parameter, 1.0):
                interpolant.wateroil = copy.deepcopy(self.high.wateroil)
                interpolant.wateroil.tag = tag
            elif parameter < 0.0:
                interpolant.wateroil = interpolate_wo(self.base.wateroil,
                                                      self.low.wateroil,
                                                      -parameter,
                                                      h=h,
                                                      tag=tag)
            elif parameter > 0.0:
                interpolant.wateroil = interpolate_wo(self.base.wateroil,
                                                      self.high.wateroil,
                                                      parameter,
                                                      h=h,
                                                      tag=tag)
        else:
            interpolant.wateroil = None

        if do_gasoil or do_gaswater:
            tag = ("SCAL recommendation interpolation to {}\n".format(
                gasparameter) + tagstring)
            if abs(gasparameter) > 1.0:
                logger.error("Interpolation parameter must be in [-1,1]")
                assert abs(gasparameter) <= 1.0
            elif np.isclose(gasparameter, 0.0):
                interpolant.gasoil = copy.deepcopy(self.base.gasoil)
                interpolant.gasoil.tag = tag
            elif np.isclose(gasparameter, -1.0):
                interpolant.gasoil = copy.deepcopy(self.low.gasoil)
                interpolant.gasoil.tag = tag
            elif np.isclose(gasparameter, 1.0):
                interpolant.gasoil = copy.deepcopy(self.high.gasoil)
                interpolant.gasoil.tag = tag
            elif gasparameter < 0.0:
                interpolant.gasoil = interpolate_go(self.base.gasoil,
                                                    self.low.gasoil,
                                                    -1 * gasparameter,
                                                    h=h,
                                                    tag=tag)
            elif gasparameter > 0.0:
                interpolant.gasoil = interpolate_go(self.base.gasoil,
                                                    self.high.gasoil,
                                                    gasparameter,
                                                    h=h,
                                                    tag=tag)
        else:
            interpolant.gasoil = None

        return interpolant