div.output_prompt { visibility: hidden; } *{ font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif !important } .input,#header { display: none; }

Modified salinity water flooding

The simplest model for the modify salinity water flooding assumes that the relative permeability of water and oil (mostly oil) is altered due to the change of the salinity of the injected water. Here, I follow the procedure described by Pope (SPE-7660) to find the fractional flow solution for the secondary and tertiary modified salinity water flooding. I will compare the analytical solution with a numerical solution (finite volume, upwind, fine mesh). Then, I will present a special case for the tertiary water flooding where the Pope's approach seems to give erroneous results. I then try to present an alternative solution procedure.

Secondary modified salinity water flood

First, we inject the low salinity water to a reservoir that is not water flooded. The injected brine pushes the formation brine, and the formation brine pushes oil. Moreover, the injected brine mobilizes more oil, since it changes the transport properties of oil and water in the reservoir, i.e., has a different sets of relative permeability curves and fractional flow curve. Let's define the relative permeability curves, and visualize them.


In [85]:
include("FractionalFlow.jl")
using PyPlot
FF = FractionalFlow
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=0.25, 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_sec = FF.low_sal_water_flood(core_props, fluids_ls, fluids_hs, rel_perms_hs, 
        rel_perms_ls, core_flood);


low sal sw_shock = 0.7233666450788676
low sal breakthrough time = 0.7792345274868723
high sal sw_shock = 0.5033633510803514
high sal breakthrough time = 0.4749856705176971
WARNING: replacing module FractionalFlow

In [86]:
FF.print_relperm(rel_perms_hs, title="high salinity (formation brine)")


Out[86]:

high salinity (formation brine)

krw0kro0nwnoSwcSor
0.40.92.02.00.150.25

In [87]:
FF.print_relperm(rel_perms_ls, title="low salinity (injected brine)")


Out[87]:

low salinity (injected brine)

krw0kro0nwnoSwcSor
0.30.952.02.00.150.15

In [88]:
FF.print_core_properties(core_props, title = "core properties")


Out[88]:

core properties

lengthdiameterporositypermeability
0.150.030.31.0e-12

In [89]:
FF.print_fluids(fluids_hs, title = "viscosity")


Out[89]:

viscosity

mu_watermu_oil
0.0020.001

In [90]:
FF.print_core_flood(core_flood, title="core flooding condition")


Out[90]:

core flooding condition

u_inj_m_spv_injectedSw_initSw_inj
1.15e-55.00.21.0

In [91]:
figure()
FF.visualize(rel_perms_hs, label = "HS")
FF.visualize(rel_perms_ls, label = "LS")
figure()
FF.visualize(rel_perms_hs, fluids_hs, label="HS")
FF.visualize(rel_perms_ls, fluids_ls, label="LS")
tight_layout()
figure()
FF.visualize_solution(ls_res_sec)
figure()
FF.visualize_profiles(ls_res_sec)
title("Secondary low-sal");


Here, I compare the above solution with the numerical solution of the same problem:


In [92]:
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);


Progress:  97%|████████████████████████████████████████ |  ETA: 0:00:01

In [93]:
plot(xt_num/(core_props.length)/pv_num[end], sw_num, label = "Sw-numerical")
plot(xt_num/(core_props.length)/pv_num[end], 1-c_old, label = "tracer-numerical")
plot(ls_res_sec.saturation_profile_xt[:,1], ls_res_sec.saturation_profile_xt[:,2], label = "Sw-analytical")
plot(ls_res_sec.tracer_profile_xt[:,1], ls_res_sec.tracer_profile_xt[:,2], label = "tracer-analytical")
xlabel("x/t [-]")
ylabel("Water saturation [-]")
title("Secondary low sal water flood")
legend();


Tertiary low-salinity water flooding

We assume that the reservoir is flooded with the formation brine (i.e, high salinity) and has reached the residual oil saturation. It means that the initial saturation of the reservoir is 1-$S_{or}^{HS}$. For this system, the solution looks like the following:


In [94]:
core_flood = FF.core_flooding(u_inj=1.15e-5, pv_inject=5.0, p_back=1e5, 
    sw_init=1-rel_perms_hs.sor, sw_inj=1.0, rel_perms=rel_perms_hs)
ls_res_ter = FF.low_sal_water_flood(core_props, fluids_ls, fluids_hs, rel_perms_hs, 
        rel_perms_ls, core_flood)

# figure()
# FF.visualize(rel_perms_hs, label = "HS")
# FF.visualize(rel_perms_ls, label = "LS")
# figure()
# FF.visualize(rel_perms_hs, fluids_hs, label="HS")
# FF.visualize(rel_perms_ls, fluids_ls, label="LS")
# tight_layout()
figure()
FF.visualize_solution(ls_res_ter)
figure()
FF.visualize_profiles(ls_res_ter)
title("Tertiary low-sal");


low sal sw_shock = 0.7233666450788676
low sal breakthrough time = 0.7792345274868723
high sal sw_shock = 0.5033633510803514
high sal breakthrough time = 0.6966577483203314

In [95]:
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);


Progress:  98%|████████████████████████████████████████ |  ETA: 0:00:00

In [96]:
plot(xt_num/(core_props.length)/pv_num[end], sw_num, label = "Sw-numerical")
plot(xt_num/(core_props.length)/pv_num[end], 1-c_old, label = "tracer-numerical")
plot(ls_res_ter.saturation_profile_xt[:,1], ls_res_ter.saturation_profile_xt[:,2], label = "Sw-analytical")
plot(ls_res_ter.tracer_profile_xt[:,1], ls_res_ter.tracer_profile_xt[:,2], label = "tracer-analytical")
xlabel("x/t [-]")
ylabel("Water saturation [-]")
title("Tertiary low sal water flood")
legend();


Again, we can see that the solution matches reasonably with the numerical results.

A special case

One special case happens when the high salinity residual oil saturation is very close to the low salinity residual oil saturation. In this case, the line that connects the intersection of the high salinity fractional flow curve and the tangent line from the origin to the low salinity fractional curve to the initial reservoir saturation (i.e., 1-$S_{w,or}^{HS}$, cuts through the low salinity fractional flow curve, as shown below. In this case the above procedure for finding the analytical solution procedure does not work:


In [97]:
rel_perms_hs = FF.oil_water_rel_perms(krw0=0.4, kro0=0.9, 
        swc=0.15, sor=0.20, 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=1-rel_perms_hs.sor, sw_inj=1.0, rel_perms=rel_perms_hs)
ls_res_ter = FF.low_sal_water_flood(core_props, fluids_ls, fluids_hs, rel_perms_hs, 
        rel_perms_ls, core_flood)


low sal sw_shock = 0.7233666450788676
low sal breakthrough time = 0.7792345274868723
high sal sw_shock = 0.5577460825529506
high sal breakthrough time = 0.8522910391556234
INFO: This function does not work on this problem. Consider calling the single_ion_adsorption_water_flood_single_shock function.
Out[97]:
FractionalFlow.FracFlowResults(Function[FractionalFlow.#23, FractionalFlow.#23], FractionalFlow.Line[FractionalFlow.Line(Real[-0.0, 0.0], Real[0.723367, 0.928304]), FractionalFlow.Line(Real[0.8, 1.0], Real[0.557746, 0.715762])], Real[0.0 0.0; 0.852291 0.0; … ; 4.80541 0.175833; 5.0 0.178515], Real[0.0 0.0; 3335.05 0.0; … ; 18803.8 0.175833; 19565.2 0.178515], Real[1.94026e-15 0.85; 0.00831185 0.848721; … ; 1.17331 0.8; 3.33333 0.8], Real[0.0 1.0; 1.28331 1.0; 1.28331 0.0; 3.33333 0.0])

In [105]:
FF.print_relperm(rel_perms_hs, title = "high salinity rel perm")


Out[105]:

high salinity rel perm

krw0kro0nwnoSwcSor
0.40.92.02.00.150.2

In [99]:
figure()
FF.visualize(rel_perms_hs, label = "HS")
FF.visualize(rel_perms_ls, label = "LS")
figure()
FF.visualize(rel_perms_hs, fluids_hs, label="HS")
FF.visualize(rel_perms_ls, fluids_ls, label="LS")
tight_layout()
figure()
FF.visualize_solution(ls_res_ter)
figure()
FF.visualize_profiles(ls_res_ter)
title("Secondary low-sal");



In [100]:
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);


Progress:  98%|████████████████████████████████████████ |  ETA: 0:00:00

In [101]:
plot(xt_num/(core_props.length)/pv_num[end], sw_num, label = "Sw-numerical")
plot(xt_num/(core_props.length)/pv_num[end], 1-c_old, label = "tracer-numerical")
plot(ls_res_ter.saturation_profile_xt[:,1], ls_res_ter.saturation_profile_xt[:,2], label = "Sw-analytical")
plot(ls_res_ter.tracer_profile_xt[:,1], ls_res_ter.tracer_profile_xt[:,2], label = "tracer-analytical")
xlabel("x/t [-]")
ylabel("Water saturation [-]")
title("Tertiary low sal water flood")
legend();


The correct solution

To construct the correct saturation profile, I assumed that we should follow the same procedure, but interpret the results in the right way. It means that the low salinity shock front saturation is represented by the intersection of the red line (see the solution procedure above) and the low salinity fractional flow curve (orange curve). This interpretation produces the following results:


In [102]:
ls_res_ter = FF.single_ion_adsorption_water_flood_single_shock(core_props, fluids_ls, fluids_hs, rel_perms_hs, 
        rel_perms_ls, core_flood, 0.0)

figure()
FF.visualize_solution(ls_res_ter)
figure()
FF.visualize_profiles(ls_res_ter)
title("Secondary low-sal");


low sal sw_shock = 0.7233666450788676
low sal breakthrough time = 0.7792345274868723
high sal sw_shock = 0.5577460825529506
high sal breakthrough time = 0.8522910391556234
sw_shock = 0.7870029917024813
low sal breakthrough time = 1.9087615410426133
swmax 0.8224218409093991

In [103]:
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);


Progress:  99%|█████████████████████████████████████████|  ETA: 0:00:00

In [104]:
plot(xt_num/(core_props.length)/pv_num[end], sw_num, label = "Sw-numerical")
plot(xt_num/(core_props.length)/pv_num[end], 1-c_old, label = "tracer-numerical")
plot(ls_res_ter.saturation_profile_xt[:,1], ls_res_ter.saturation_profile_xt[:,2], label = "Sw-analytical")
plot(ls_res_ter.tracer_profile_xt[:,1], ls_res_ter.tracer_profile_xt[:,2], label = "tracer-analytical")
xlabel("x/t [-]")
ylabel("Water saturation [-]")
title("Tertiary low sal water flood")
legend();


The above solution assumes that there is no adsorption of ions on the rock surface. However, it is quite easy to include the adsorption in the equations and in the solution procedure.
If the above solution is correct, it explains several issues with the observations in the lab. for instance, sometimes the extra oil recovery observed before the breakthrough of the injected low salinity water. Sometimes, the tertiary recovery is extremely slow and needs the injection of many pore volumes of water. It is explained by the above fractional flow solution very well. I can probably think of other issues that I have observed in the lab.