This document is mostly based on the SPE-7660 paper by Gary Pope. I first implement the simple water flooding analytical solution and then expand it to low salinity water flooding with and without ionic adsorption.
The two phase flow equation in a 1D porous medium reads $$\frac{\partial S_w}{\partial t}+\frac{u}{\varphi}\frac{df_w}{dS_w}\frac{\partial S_w}{\partial x} = 0 $$ The dimensionless time and space are defined as $$t_D = \frac{ut}{\varphi L}$$ and $$x_D = \frac{x}{L}$$ The velocity of a constant saturation front is calculated by $$V_{S_w} = (\frac{dx}{dt})_{S_w}=\frac{u}{\varphi}\frac{df_w}{dS_w}$$ The shock front is specified by $$\frac{f_w(S_{w,shock})-f_w(S_{w,init})}{S_{w,shock}-S_{w,init}}=\left(\frac{df_w}{dS_w}\right)_{S_{w,shock}}$$ The injected water front velocity (i.e., a tracer in the injected water, or the low salinity of the injected brine) is calculated by $$V_{c} = (\frac{dx}{dt})_{c}=\frac{u}{\varphi}\frac{f_w}{S_w}$$ an the water saturation that corresponds to the position of the salinity front is given by $$\frac{f_w(S_{w,s})-f_w(0)}{S_{w}-0.0}=\left(\frac{df_w}{dS_w}\right)_{S_{w,shock}}$$ which is the tangent line fron the point (0,0) to the $f_w-S_w$ (fractional flow) curve. The breakthrough time (in number of pore volume) is calculated by $$t_{D, bt} = \left(\frac{df_w}{dS_w}\right)^{-1}_{S_{w,shock}}$$ The other useful relation is the average saturation after breakthrough, which reads $$S_{w,av} = S_{or}+\left[(1-f_w)\left(\frac{df_w}{dS_w}\right)\right]_{x=L}, \;t_D>t_{D,bt}$$ The recovery factor then can be calculated based on the fact that the recovery curve is linear until the breakthrough, and after breakthrough it gradually reaches a plateau. The oil recovery factor before the breakthrough is calculated by $$R = \frac{(1-f_w(S_{w,init}))t_D}{1-S_{w,init}}, \;t_D<t_{D,bt}$$ and after breakthrough by $$R = \frac{S_{w,init}-S_{w,av}}{1-S_{w,init}}, \; t_D>t_{D,bt}$$ Let's try the above formulation in Julia.
The FractionalFlow.jl
package is built to solve and visualize the analytical solutions to several injection problem in the petroleum engineering, including water flooding, low salinity water flooding with and without ionic adsorption, and solvent flooding (carbonated water, DME, etc). There are several functions that are documented in the code. Here, I show by example how to define a problem, solve it, and visualize the results.
In [71]:
include("../FractionalFlow/FractionalFlow.jl")
using PyPlot
FF = FractionalFlow
Out[71]:
In [72]:
# define the problem
# relative permeabilities
rel_perms = FF.oil_water_rel_perms(krw0=0.4, kro0=0.9,
swc=0.15, sor=0.2, nw=2.0, no = 2.0)
FF.visualize(rel_perms)
Out[72]:
In [73]:
FF.print_relperm(rel_perms, title="Corey rel-perm parameters")
Out[73]:
In [74]:
# define the fluids
fluids = FF.oil_water_fluids(mu_water=1e-3, mu_oil=2e-3)
# define the fractional flow functions
fw, dfw = FF.fractional_flow_function(rel_perms, fluids)
# visualize the fractional flow
FF.visualize(rel_perms, fluids, label="lowsal")
tight_layout()
In [75]:
fluids.oil_viscosity
Out[75]:
In [76]:
core_flood = FF.core_flooding(u_inj=1.15e-5, pv_inject=5.0,
p_back=1e5, sw_init=0.2, sw_inj=1.0, rel_perms=rel_perms)
core_props = FF.core_properties()
wf_res = FF.water_flood(core_props, fluids, rel_perms, core_flood)
fw, dfw = FF.fractional_flow_function(rel_perms, fluids)
sw_tmp = range(0, 1, length=100)
# plot(sw_tmp, fw.(sw_tmp), xlabel = "Sw", ylabel="fw", label="")
# plot!(sw_tmp, dfw.(sw_tmp))
# figure(1)
# plot(pv, R)
# xlabel("PV injected")
# ylabel("Recovery factor")
# title("Water flooding")
# figure(2)
# plot(xt, sw)
# xlabel("x/t [-]")
# ylabel("Water saturation [-]")
FF.visualize(wf_res)
Out[76]:
In [77]:
fluids_hs = FF.oil_water_fluids(mu_water=1.5e-3, mu_oil=3e-3)
fluids_ls = FF.oil_water_fluids(mu_water=1e-3, mu_oil=3e-3)
rel_perms_hs = FF.oil_water_rel_perms(krw0=0.4, kro0=0.9,
swc=0.15, sor=0.2, nw=2.0, no = 2.0)
rel_perms_ls = FF.oil_water_rel_perms(krw0=0.3, kro0=0.95,
swc=0.15, sor=0.15, nw=2.0, no = 2.0)
core_flood = FF.core_flooding(u_inj=1.15e-5, pv_inject=5.0, p_back=1e5, sw_init=0.2, sw_inj=1.0, rel_perms=rel_perms_hs)
core_props = FF.core_properties()
ls_res = FF.low_sal_water_flood(core_props, fluids_ls, fluids_hs, rel_perms_hs,
rel_perms_ls, core_flood)
FF.visualize(ls_res)
Out[77]:
In [78]:
t_sec, pv_num, rec_fact, xt_num, sw_num, c_old, c_out_sal =
FF.forced_imb_implicit_upwind(core_props, fluids_ls, fluids_hs, rel_perms_hs,
rel_perms_ls, core_flood)
# plot(ls_res)
Out[78]:
In [79]:
figure(2)
plot(xt_num/(core_props.length)/pv_num[end], sw_num)
plot(xt_num/(core_props.length)/pv_num[end], 1.-c_old)
plot(ls_res.saturation_profile_xt[:,1], ls_res.saturation_profile_xt[:,2])
plot(ls_res.tracer_profile_xt[:,1], ls_res.tracer_profile_xt[:,2])
xlabel("x/t [-]")
ylabel("Water saturation [-]")
In [29]:
sor_hs = 0.25
sw_init = 1-sor_hs
fluids_hs = FF.oil_water_fluids(mu_water=1e-3, mu_oil=2e-3)
fluids_ls = FF.oil_water_fluids(mu_water=1e-3, mu_oil=2e-3)
rel_perms_hs = FF.oil_water_rel_perms(krw0=0.4, kro0=0.9,
swc=0.15, sor=sor_hs, nw=2.0, no = 2.0)
rel_perms_ls = FF.oil_water_rel_perms(krw0=0.3, kro0=0.95,
swc=0.15, sor=0.15, nw=2.0, no = 2.0)
core_flood = FF.core_flooding(u_inj=1.15e-5, pv_inject=30.0, p_back=1e5, sw_init=sw_init,
sw_inj=1.0, rel_perms=rel_perms_hs)
core_props = FF.core_properties()
ls_res = FF.low_sal_water_flood(core_props, fluids_ls, fluids_hs, rel_perms_hs,
rel_perms_ls, core_flood)
FF.visualize(ls_res)
Out[29]:
In [30]:
t_sec, pv_num, rec_fact, xt_num, sw_num, c_old, c_out_sal =
FF.forced_imb_implicit_upwind(core_props, fluids_ls, fluids_hs, rel_perms_hs,
rel_perms_ls, core_flood)
In [15]:
figure(2)
plot(xt_num/(core_props.length)/pv_num[end], sw_num)
plot(xt_num/(core_props.length)/pv_num[end], 1-c_old)
plot(ls_res.saturation_profile_xt[:,1], ls_res.saturation_profile_xt[:,2])
plot(ls_res.tracer_profile_xt[:,1], ls_res.tracer_profile_xt[:,2])
xlabel("x/t [-]")
ylabel("Water saturation [-]")
title("tertiary low-sal water flood")
Out[15]:
In [15]:
sor_hs = 0.20
sw_init = 1-sor_hs
fluids_hs = FF.oil_water_fluids(mu_water=1e-3, mu_oil=2e-3)
fluids_ls = FF.oil_water_fluids(mu_water=1e-3, mu_oil=2e-3)
rel_perms_hs = FF.oil_water_rel_perms(krw0=0.4, kro0=0.9,
swc=0.15, sor=sor_hs, nw=2.0, no = 2.0)
rel_perms_ls = FF.oil_water_rel_perms(krw0=0.3, kro0=0.95,
swc=0.15, sor=0.15, nw=2.0, no = 2.0)
core_flood = FF.core_flooding(u_inj=1.15e-5, pv_inject=30.0, p_back=1e5, sw_init=sw_init,
sw_inj=1.0, rel_perms=rel_perms_hs)
core_props = FF.core_properties()
ls_res = FF.single_ion_adsorption_water_flood_single_shock(core_props, fluids_ls, fluids_hs, rel_perms_hs,
rel_perms_ls, core_flood, 0.0)
FF.visualize(ls_res)
Out[15]:
In [17]:
t_sec, pv_num, rec_fact, xt_num, sw_num, c_old, c_out_sal =
FF.forced_imb_implicit_upwind(core_props, fluids_ls, fluids_hs, rel_perms_hs,
rel_perms_ls, core_flood)
Out[17]:
In [18]:
figure(2)
plot(xt_num/(core_props.length)/pv_num[end], sw_num)
plot(xt_num/(core_props.length)/pv_num[end], c_old)
plot(ls_res.saturation_profile_xt[:,1], ls_res.saturation_profile_xt[:,2])
plot(ls_res.tracer_profile_xt[:,1], ls_res.tracer_profile_xt[:,2])
xlabel("x/t [-]")
ylabel("Water saturation [-]")
Out[18]:
In [19]:
plot(xt_num/(core_props.length)/pv_num[end], sw_num)
# plot(xt_num/(core_props.length)/pv_num[end], c_old)
plot(ls_res.saturation_profile_xt[:,1], ls_res.saturation_profile_xt[:,2])
# plot(ls_res.tracer_profile_xt[:,1], ls_res.tracer_profile_xt[:,2])
xlabel("x/t [-]")
ylabel("Water saturation [-]")
Out[19]:
One necessary detail is the volumetric partition coefficient that is needed for finding the analytical solution. It can be done by doing some thermodynamic magic for finding the partial molar volumes of DME in the aqueous and in the oleic phase.
I've done it in another file, because it is boring for everybody else (not me, I love thermodynamics). The result is here. I have also shown the molar and mass partition coefficients
In [26]:
fluids_oil_water = FF.oil_water_fluids(mu_water=1e-3, mu_oil=2e-3)
fluids_solvent = FF.oil_water_fluids(mu_water=1.1e-3, mu_oil=1e-3)
rel_perms_oil_water = FF.oil_water_rel_perms(krw0=0.4, kro0=0.9,
swc=0.15, sor=0.2, nw=2.0, no = 2.0)
rel_perms_solvent = FF.oil_water_rel_perms(krw0=0.4, kro0=0.9,
swc=0.15, sor=0.05, nw=2.0, no = 2.0)
core_flood = FF.core_flooding(sw_init = 1-0.2)
core_props = FF.core_properties()
K_eq = 2.0
sol_res = FF.water_soluble_solvent_flood(core_props, fluids_solvent, fluids_oil_water,
rel_perms_oil_water, rel_perms_solvent, core_flood, K_eq)
FF.visualize(sol_res)
Out[26]:
In [17]:
typeof(sol_res)