def test_interpolate_wo(): """Discrete test scenarios for wateroil interpolation""" swl_l = random.uniform(0, 0.1) swcr_l = swl_l + random.uniform(0, 0.1) sorw_l = random.uniform(0, 0.2) swl_h = random.uniform(0, 0.1) swcr_h = swl_h + random.uniform(0, 0.1) sorw_h = random.uniform(0, 0.2) wo_low = WaterOil(swl=swl_l, swcr=swcr_l, sorw=sorw_l, h=0.001) wo_high = WaterOil(swl=swl_h, swcr=swcr_h, sorw=sorw_h, h=0.001) wo_low.add_corey_water(nw=random.uniform(1, 3), krwend=random.uniform(0.5, 1)) wo_high.add_corey_water(nw=random.uniform(1, 3), krwend=random.uniform(0.5, 1)) wo_low.add_corey_oil(now=random.uniform(1, 3), kroend=random.uniform(0.5, 1)) wo_high.add_corey_oil(now=random.uniform(1, 3), kroend=random.uniform(0.5, 1)) wo_low.add_simple_J(a=random.uniform(0.1, 2), b=random.uniform(-2, -1)) wo_high.add_simple_J(a=random.uniform(0.1, 2), b=random.uniform(-2, 1)) print(" ** Low curve (red):\n" + wo_low.swcomment + wo_low.krwcomment + wo_low.krowcomment + wo_low.pccomment) print(" ** High curve (blue):\n" + wo_high.swcomment + wo_high.krwcomment + wo_high.krowcomment + wo_high.pccomment) from matplotlib import pyplot as plt _, mpl_ax = plt.subplots() wo_low.plotkrwkrow(mpl_ax, color="red") wo_high.plotkrwkrow(mpl_ax, color="blue") for tparam in np.arange(0, 1, 0.1): wo_ip = utils.interpolate_wo(wo_low, wo_high, tparam, h=0.001) wo_ip.plotkrwkrow(mpl_ax, color="green") mpl_ax.set_title("WaterOil, random Corey, linear y-scale") plt.show() # Plot again with log yscale: _, mpl_ax = plt.subplots() wo_low.plotkrwkrow(mpl_ax, color="red") wo_high.plotkrwkrow(mpl_ax, color="blue") for tparam in np.arange(0, 1, 0.1): wo_ip = utils.interpolate_wo(wo_low, wo_high, tparam, h=0.001) wo_ip.plotkrwkrow(mpl_ax, color="green", logyscale=True) mpl_ax.set_title("WaterOil, random Corey, log y-scale") plt.show() # Capillary pressure _, mpl_ax = plt.subplots() wo_low.plotpc(mpl_ax, color="red", logyscale=True) wo_high.plotpc(mpl_ax, color="blue", logyscale=True) for tparam in np.arange(0, 1, 0.1): wo_ip = utils.interpolate_wo(wo_low, wo_high, tparam, h=0.001) wo_ip.plotpc(mpl_ax, color="green", logyscale=True) mpl_ax.set_title("WaterOil, capillary pressure") plt.show()
def test_interpolate_wo_pc(swl, dswcr, dswlhigh, sorw, a_l, a_h, b_l, b_h): """ Generate two random WaterOil curves, interpolate pc between them and check that the difference between each interpolant is small, this essentially checks that we can go continously between the two functions. """ wo_low = WaterOil(swl=swl, swcr=swl + dswcr, sorw=sorw) wo_high = WaterOil(swl=swl + dswlhigh, swcr=swl + dswlhigh + dswcr, sorw=max(sorw - 0.01, 0)) wo_low.add_corey_water() wo_high.add_corey_water() wo_low.add_corey_oil() wo_high.add_corey_oil() wo_low.add_simple_J(a=a_l, b=b_l) wo_high.add_simple_J(a=a_h, b=b_h) ips = [] ip_dist = 0.05 for t in np.arange(0, 1 + ip_dist, ip_dist): wo_ip = utils.interpolate_wo(wo_low, wo_high, t) check_table(wo_ip.table) ips.append(wo_ip) assert 0 < wo_ip.crosspoint() < 1 # Distances between low and interpolants: dists = [(wo_low.table - interp.table)[["pc"]].sum().sum() for interp in ips] assert np.isclose(dists[0], 0) # Distance between high and the last interpolant assert (wo_high.table - ips[-1].table)[["pc"]].sum().sum() < 0.01 # Distances between low and interpolants: dists = [(wo_low.table - interp.table)[["pc"]].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 wo_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 # (avoiding the first which reproduces go_low if ip_dist_std > 1.0: # Found by trial and error print("ip_dist_std: {}".format(ip_dist_std)) print(dists) from matplotlib import pyplot as plt _, mpl_ax = plt.subplots() wo_low.plotpc(mpl_ax=mpl_ax, color="red", logyscale=True) wo_high.plotpc(mpl_ax=mpl_ax, color="blue", logyscale=True) for interp in ips: interp.plotpc(mpl_ax=mpl_ax, color="green", logyscale=True) plt.show() assert False
def interpolation_art(repeats=50, interpolants=30, curvetype="corey"): """This code was used to create the Pyscal logo""" from matplotlib import pyplot as plt cmap = plt.get_cmap("viridis") _, mpl_ax = plt.subplots() for _ in range(repeats): swl = random.uniform(0, 0.1) swcr = swl + random.uniform(0, 0.1) sorw = random.uniform(0, 0.2) wo_low = WaterOil(swl=swl, swcr=swcr, sorw=sorw) wo_high = WaterOil(swl=swl + 0.1, swcr=swcr + 0.1, sorw=sorw + 0.1) if curvetype == "corey": wo_low.add_corey_water(nw=random.uniform(1, 3), krwend=random.uniform(0.5, 1)) wo_high.add_corey_water(nw=random.uniform(1, 3), krwend=random.uniform(0.5, 1)) wo_low.add_corey_oil(now=random.uniform(1, 3), kroend=random.uniform(0.5, 1)) wo_high.add_corey_oil(now=random.uniform(1, 3), kroend=random.uniform(0.5, 1)) elif curvetype == "let": wo_low.add_LET_water( l=random.uniform(1, 3), e=random.uniform(1, 3), t=random.uniform(1, 3), krwend=random.uniform(0.5, 1), ) wo_high.add_LET_water( l=random.uniform(1, 3), e=random.uniform(1, 3), t=random.uniform(1, 3), krwend=random.uniform(0.5, 1), ) wo_low.add_LET_oil( l=random.uniform(1, 3), e=random.uniform(1, 3), t=random.uniform(1, 3), kroend=random.uniform(0.5, 1), ) wo_high.add_LET_oil( l=random.uniform(1, 3), e=random.uniform(1, 3), t=random.uniform(1, 3), kroend=random.uniform(0.5, 1), ) else: print("ERROR, wrong curvetype") color = cmap(random.random()) for tparam in np.arange(0, 1, 1.0 / interpolants): wo_ip = utils.interpolate_wo(wo_low, wo_high, tparam) wo_ip.plotkrwkrow(mpl_ax, color=color, alpha=0.3) plt.show()
def test_ip_kromax(): """Test behaviour of kroend/kromax under interpolation""" wo_low = WaterOil(swl=0, swcr=0.1, sorw=0.2) wo_low.add_corey_water(nw=2, krwend=0.5, krwmax=0.7) wo_low.add_corey_oil(now=2, kroend=0.6, kromax=0.9) wo_high = WaterOil(swl=0.02, swcr=0.05, sorw=0.1) wo_high.add_corey_water(nw=2, krwend=0.5, krwmax=0.72) wo_high.add_corey_oil(now=2, kroend=0.6, kromax=0.8) # Interpolate to midpoint between the curves above wo_ip = utils.interpolate_wo(wo_low, wo_high, 0.5) # kromax at mean swl: assert float_df_checker(wo_ip.table, "sw", 0.01, "krow", 0.85) # kroend is 0.6 in low and high, but swcr has changed: assert float_df_checker(wo_ip.table, "sw", 0.075, "krow", 0.6) assert float_df_checker(wo_ip.table, "sw", 1, "krw", 0.71) assert float_df_checker(wo_ip.table, "sw", 1 - 0.15, "krw", 0.5)
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 = utils.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 = utils.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 = utils.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 = utils.interpolate_wo(wo_low, wo_high, parameter=0.1, h=0.2, tag="Explicit tag") assert interpolant4.tag == "Explicit tag" # Tag with newline interpolant6 = utils.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 = utils.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 = utils.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 interpolate(self, parameter, parameter2=None, h=0.02): """Interpolate between low, base and high parameter = -1 reproduces low curve parameter = 0 reproduces base curve parameter = 1 reproduces high curve 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. If a second parameter is supplied ("parameter2") this is used for the gas-oil interpolation. This enables the gas-oil interpolant to be fully uncorrelated to the water-oil interpolant. CHECK how this affects endpoints and Eclipse consistency!! """ 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_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_wateroil and not do_gasoil: raise ValueError( "Neither wateroil or gasoil is complete in SCAL recommendation" ) if parameter2 is not None and not do_gasoil: logger.warning("parameter2 is meaningless for water-oil only") # Initialize wateroil and gasoil curves to be filled with # interpolated curves: tags = set() if do_wateroil: 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) interpolant = WaterOilGas(h=h, tag=tagstring) if do_wateroil: 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 = self.base.wateroil interpolant.wateroil.tag = tag elif np.isclose(parameter, -1.0): interpolant.wateroil = self.low.wateroil interpolant.wateroil.tag = tag elif np.isclose(parameter, 1.0): interpolant.wateroil = self.high.wateroil interpolant.wateroil.tag = tag elif parameter < 0.0: interpolant.wateroil = utils.interpolate_wo(self.base.wateroil, self.low.wateroil, -parameter, h=h, tag=tag) elif parameter > 0.0: interpolant.wateroil = utils.interpolate_wo(self.base.wateroil, self.high.wateroil, parameter, h=h, tag=tag) else: interpolant.wateroil = None if do_gasoil: 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 = self.base.gasoil interpolant.gasoil.tag = tag elif np.isclose(gasparameter, -1.0): interpolant.gasoil = self.low.gasoil interpolant.gasoil.tag = tag elif np.isclose(gasparameter, 1.0): interpolant.gasoil = self.high.gasoil interpolant.gasoil.tag = tag elif gasparameter < 0.0: interpolant.gasoil = utils.interpolate_go(self.base.gasoil, self.low.gasoil, -1 * gasparameter, h=h, tag=tag) elif gasparameter > 0.0: interpolant.gasoil = utils.interpolate_go(self.base.gasoil, self.high.gasoil, gasparameter, h=h, tag=tag) else: interpolant.gasoil = None return interpolant