Introduction

Pore-scale network modeling has been used as a tool for predicting transport properties of reservoir rock. Fatt (1956) was the first researcher who used network models for this purpose. Since then, the network models’ complexity and accuracy has been increasing. Using pore-scale modeling, porosity, tortuosity, absolute permeability, relative permeabilities, capillary pressure, and resistivity of a rock sample can now be predicted with considerable precision, without performing the time-consuming and expensive RCAL and SCAL experiments.

Alongside pore-scale network modeling, there is another method called “Direct Modeling” that is also capable of predicting transport properties. In this method, the multiphase fluid flow is simulated within the pore space of the rock (Blunt et al. 2013). The pore space geometry can be acquired from micro-CT scan of the rock sample. The most popular approach for the direct modeling is the lattice Boltzmann method (Boek and Venturoli 2010; Chen and Doolen 1998; Hao and Cheng 2010; Kang et al. 2006; Manwart et al. 2002; Pan et al. 2004; Porter et al. 2009; Ramstad et al. 2012; Schaap et al. 2007; Yoon et al. 2015). Other methods are also available, such as solving Navier–Stokes equation within the porous medium (Raeini et al. 2012; Renardy et al. 2001; Renardy and Renardy 2002). Nevertheless, direct modeling is computationally demanding and its runtime is unacceptably high on ordinary computers (Valvatne 2004).

Pore-scale network modeling is much cheaper than direct modeling in terms of computational resources. However, unlike direct modeling, the micro-ct images cannot be directly used in pore-scale network modeling. Before that, an equivalent 3D network of pores and connecting throats must be extracted from the image. Then, in the network modeling step, a capillary-dominated multiphase flow is simulated within the extracted network (Arns et al. 2007; Bakke and Øren 1997; Blunt et al. 2013, 2002; Bultreys et al. 2015; Chatzis and Dullien 1985, 1977; Dias and Payatakes 1986; Larson et al. 1981; Øren and Bakke 2002, 2003; Øren et al. 1998; Patzek 2000; Piri and Blunt 2005a, b; Rajaram et al. 1997; Valvatne and Blunt 2004; Valvatne et al. 2005; Zhang et al. 2015). In recent years, more complex processes such as non-Newtonian flow, reactive transport, phase exchange, and viscous dominated flow has been included in pore-scale network modeling (Balhoff and Wheeler 2009; Idowu and Blunt 2010; Lopez et al. 2003; Løvoll et al. 2005; Nguyen et al. 2006; Qin and Hassanizadeh 2015; Tørå et al. 2012; Yiotis et al. 2006).

Pore-scale network modeling has attracted a lot of attention in recent years and it is becoming a routine service in the petroleum industry (Blunt et al. 2013). However, despite existing a rather rich literature, there are only two source codes available for pore network modeling:

  • OpenPNM (Open-source Pore Network Modeling package) (Gostick et al. 2016), which can simulate transport and percolation phenomena in porous media. OpenPNM has been used in several areas of science and engineering; however, it lacks the ability to model all of the underlying physics of petroleum engineering processes. In addition, it has been implemented in python, which is an interpreted language. Such languages fall short from compiled codes (e.g., C/C++) in terms of performance. Therefore, simulating a large network with OpenPNM can be very slow.

  • Two-phase network modeling code—“Poreflow” software (2008, Valvatne 2004)—which has been written in C++. Although its source code is accessible free of charge from the website of Imperial College London (2008), it cannot be technically considered as an open-source software. Poreflow has been designed specifically for petroleum engineering applications. Nevertheless, it supports only a limited number of geometries for pores/throats cross section. In addition, investigating the code reveals that performance has not been a concern in Poreflow implementation. Parallel programming techniques have not been employed in Poreflow, and hence, it cannot benefit from multi-core/cluster system to reduce its runtime.

In the current research, an open-source software for pore network modeling was implemented in C++, which we call it “Starfish”. Starfish has been specifically developed for petroleum engineering applications. It benefits from an objected oriented design and it can handle wide ranges of network sizes and pore/throat geometries. Parallel computing was used extensively in Starfish code to reduce its runtime, and its efficient solver package enables it to simulate very large networks with considerable accuracy.

Starfish is accessible from https://github.com/khazali/Starfish.

Network model and employed algorithms

Pore space description

The pore and throats in the pore network are assumed to have a uniform duct shape with a circular or triangular cross section, depending on their shape factor (Mason and Morrow 1991). The shape factor is one of the input data. The shape factor and the surface area of the network element are related, as shown in the following equation:

$$A=GP_{{\text{l}}}^{2}=\frac{{{r^2}}}{{4G}}.$$
(1)

The shape factor of a triangle can vary between zero for a slit-shaped triangle to \({{\sqrt 3 } \mathord{\left/ {\vphantom {{\sqrt 3 } {36}}} \right. \kern-0pt} {36}}\) for an equilateral one. The shape factor of a circle is 1/4π. Starfish assumes any shape factor greater than \({{\sqrt 3 } \mathord{\left/ {\vphantom {{\sqrt 3 } {36}}} \right. \kern-0pt} {36}}\) and 1/4π belongs to an equilateral polygon.

For triangular elements, the corner half-angle β2 is randomly chosen between (Patzek 2000)

$${\beta _{2,{\rm min} }}=\arctan \left\{ {\frac{2}{{\sqrt 3 }}\cos \left[ {\frac{{\arccos \left( { - 12\sqrt 3 G} \right)}}{3}+\frac{{4\pi }}{3}} \right]} \right\}$$
(2)

and

$${\beta _{2,\hbox{max} }}=\arctan \left\{ {\frac{2}{{\sqrt 3 }}\cos \left[ {\frac{{\arccos \left( { - 12\sqrt 3 G} \right)}}{3}} \right]} \right\}.$$
(3)

Then, β1 and β2 can be calculated as

$${\beta _1}= - \frac{1}{2}{\beta _2}+\frac{1}{2}\arcsin \left( {\frac{{\tan {\beta _2}+4G}}{{\tan {\beta _2} - 4G}}\sin {\beta _2}} \right)$$
(4)
$${\beta _3}=\frac{\pi }{2} - {\beta _1} - {\beta _2}$$
(5)

subjected to the constraint of β1 ≤ β2 ≤ β3.

Primary drainage

Starfish by default assumes that it is dealing with a water-wet system. Nevertheless, by swapping the receding and the advancing contact angles and replacing them with their supplementary angles (i.e., calling the actual oil, “water”, and calling the actual water, “oil”), Starfish is able to handle oil-wet systems, too. Therefore, in this paper and, of course, in the Starfish, water is always the wetting phase and oil is always the non-wetting phase.

Piston-like displacement

We follow Øren et al.’s (Øren et al. 1998) generalization of Mayer–Stowe–Princen (MSP) (Mason and Morrow 1991) method to calculate the threshold capillary occurrence (entry) pressure for piston-like displacement during the drainage process. It can be expressed as

$${P_{\text{c}}}=\frac{{\sigma \cos {\theta _{\text{r}}}}}{r}\left( {1+2\sqrt {\pi G} } \right){F_{\text{d}}} - \left( {{\rho _{\text{w}}} - {\rho _{\text{o}}}} \right)gh,$$
(6)

where Fd is a dimensionless correction factor for wetting fluid that might be retained in the corners. Fd is equal to unity for a circular element, but for a polygonal element, it can be calculated as

$${F_{\text{d}}}=\frac{{1+\sqrt {1 - \frac{{4GC}}{{{{\cos }^2}{\theta _{\text{r}}}}}} }}{{1+2\sqrt {\pi G} }}.$$
(7)

C is a function of corner half-angles and is given by

$$C=\sum\limits_{{i=1}}^{n} {\left[ {\cos {\theta _{\text{r}}}\frac{{\cos \left( {{\theta _{\text{r}}}+{\beta _i}} \right)}}{{\sin {\beta _i}}} - \left( {\frac{\pi }{2} - {\theta _{\text{r}}} - {\beta _i}} \right)} \right]} ,$$
(8)

in which n is the number of corners of the element, whose half-angles satisfy the following condition (Valvatne 2004):

$${\beta _i}<\frac{\pi }{2} - {\theta _{\text{r}}}.$$
(9)

Such corners will retain wetting phase even after non-wetting phase invades the element. Figure 1 shows a triangular element with wetting phase in its corners and non-wetting phase in its center. Unlike triangular elements, a circular element cannot retain wetting phase and will be completely filled by non-wetting phase when it is invaded.

Fig. 1
figure 1

Element that has been invaded by non-wetting phase during drainage process

Displacement process

Drainage is a bond invasion–percolation process, and therefore, the events requiring less capillary pressure happens sooner. During the drainage, piston-like displacement is the only event that can take place within the network elements.

Before the drainage starts, the network is completely saturated with water (wetting phase). Oil (non-wetting phase) is present at the network inlet. Then, the current capillary pressure in the network is gradually increased by keeping the water pressure constant and increasing the oil pressure, from zero to a predefined maximum value (the amount of increment and the maximum value is defined by CAPILLARYINCREMENT and CAPILLARYLIMIT macros in Starfish code, respectively). In each step, all network elements with at least one oil-filled neighboring element are invaded by oil if their threshold capillary occurrence pressure is less than or equal to the current capillary pressure. Then, the fluids’ saturations in the entire network elements are updated using the following relations:

$${S_{\text{w}}}=\frac{{{A_{\text{w}}}}}{A}$$
(10)
$${S_{\text{o}}}=1 - {S_{\text{w}}}.$$
(11)

A w is zero in circular elements. In triangular elements, Aw can be expressed as (Øren et al. 1998)

$${A_{\text{w}}}={R^2}\sum\limits_{{i=1}}^{n} {\left[ {\cos {\theta _{\text{r}}}\frac{{\cos \left( {{\theta _r}+{\beta _i}} \right)}}{{\sin {\beta _i}}} - \left( {\frac{\pi }{2} - {\theta _{\text{r}}} - {\beta _i}} \right)} \right]}$$
(12)

and

$$R=\frac{\sigma }{{{P_{{\text{c}},{\text{cur}}}}}}.$$
(13)

Knowing the saturation in all elements, the total fluids saturation of the network can be calculated by

$${S_{{\text{w}},{\text{total}}}}=\frac{{\sum\nolimits_{i} {\left( {{S_{{\text{w}},i}} \cdot {V_i}+{V_{{\text{clay}},i}}} \right)} }}{{\sum\nolimits_{i} {{V_i}} }}.$$
(14)

The sigma is over all of the network elements. Moreover

$${S_{{\text{o}},{\text{total}}}}=1 - {S_{{\text{w}},{\text{total}}}}.$$
(15)

In each step, the total water saturation and the current capillary pressure in the network are printed in the outputs.

The wetting phase in the network elements must constitute a connected phase to the outlet; otherwise, the non-wetting phase cannot displace it. If the wetting phase in an element or a cluster element loses its connection to the network outlet, it is trapped and no longer is in pressure communication with the outlet. Therefore, the capillary pressure in that element(s) will not change anymore. During the drainage, trapping is only possible if an element or a cluster of elements is surrounded by oil-filled circular elements. The wetting phase remains connected through the triangular elements, which can retain it in their corners.

Primary imbibition

Given enough time, the oil having direct contact with the rock in center of elements can change the rock wettability. However, during the drainage, oil cannot displace water in the corners of the pore space; therefore, the corners will remain water-wet. In addition, due to surface roughness, contact angles depend on the flow direction. As a result, imbibition is a more complex process than the drainage and involves more displacement mechanisms. These mechanisms are piston-like displacement, pore body filling and snap-off.

In the current state, Starfish cannot handle extreme wettability alterations (from completely water-wet to completely oil-wet). Nevertheless, this ability will be added to the code in the future versions.

Piston-like displacement

Imbibition process is the act of displacing oil by water. If an element has at least one water-filled neighbor, and the following condition holds, spontaneous piston-like imbibition will occur in that element (Patzek 2000):

$${\theta _{\text{a}}} \leq \arccos \left[ {\frac{{ - 4G\sum\nolimits_{{i=1}}^{n} {\cos \left( {{\theta _{\text{r}}}+{\beta _i}} \right)} }}{{\frac{r}{{{R_{{\rm min} }}}} - \cos {\theta _{\text{r}}}+12G\sin {\theta _{\text{r}}}}}} \right].$$
(16)

The threshold capillary occurrence pressure for spontaneous imbibition is expressed as

$${P_{\text{c}}}=\frac{\sigma }{R} - \left( {{\rho _{\text{w}}} - {\rho _{\text{o}}}} \right)gh.$$
(17)

For a circular element, R is simply equal to r. However, for a triangular element we have (Patzek 2000)

$$R=\frac{{\frac{{{r^2}}}{{4G}} - R\sum\nolimits_{{i=1}}^{n} {{b_i}\cos {\theta _{{\text{h}},i}}+{R^2}\sum\nolimits_{{i=1}}^{n} {\left( {\frac{\pi }{2} - {\theta _{{\text{h}},i}} - {\beta _i}} \right)} } }}{{2R\sum\nolimits_{{i=1}}^{n} {{\alpha _i}+\left( {\frac{r}{{2G}} - 2\sum\nolimits_{{i=1}}^{n} {{b_i}} } \right)\cos {\theta _{\text{a}}}} }},$$
(18)

in which

$${\theta _{{\text{h}},i}}={\rm min} \left\{ {\arccos \left[ {\frac{{{R_{{\rm min} }}}}{R}\cos \left( {{\theta _{\text{r}}}+{\beta _i}} \right)} \right] - {\beta _i},{\theta _{\text{a}}}} \right\}$$
(19)
$${b_i}=\left\{ \begin{gathered} {R_{{\rm min} }}\frac{{\cos \left( {{\theta _{\text{r}}}+{\beta _i}} \right)}}{{\sin {\beta _i}}}{\text{ }}{\theta _{{\text{h}},i}} \leq {\theta _{\text{a}}} \hfill \\ R\frac{{\cos \left( {{\theta _{\text{a}}}+{\beta _i}} \right)}}{{\sin {\beta _i}}}{\text{ }}{\theta _{{\text{h}},i}}>{\theta _{\text{a}}} \hfill \\ \end{gathered} \right.$$
(20)
$${\alpha _i}=\left\{ \begin{gathered} \arcsin \left( {\frac{{{b_i}}}{{{r_{\text{p}}}}}\sin {\beta _i}} \right){\text{ }}{\theta _{{\text{h}},i}} \leq {\theta _{\text{a}}} \hfill \\ \frac{\pi }{2} - {\theta _{\text{a}}} - {\beta _i}{\text{ }}{\theta _{{\text{h}},i}}>{\theta _{\text{a}}} \hfill \\ \end{gathered} \right..$$
(21)

i is the index of the corners retaining water and

$${R_{{\rm min} }}=\frac{\sigma }{{{P_{{\text{c}},\hbox{max} }}}}.$$
(22)

Equations 1821 form a non-linear system, which can be solved by numerical methods. Starfish first uses Newton’s method. If it fails, the fixed-point iteration is subsequently applied. Details of the used Newton’s method can be found in the “Appendix”. Fixed-point iteration is much simpler, it is enough to calculate θh,i, bi, and αi with an initial guess for R from Eqs. 1921, which then, are put into Eq. 18 to update the value of R. This procedure is repeated until convergence. A good initial guess for R is its previous value (computed for a higher current capillary pressure). In our experience, Newton’s method fails in much less cases than fixed-point iteration; nevertheless, the combination of Newton’s method and fixed-point iteration did not fail in any of the test cases.

Where Eq. 16 does not hold, piston-like displacement can only take place in negative values of current capillary pressure, i.e., forced imbibition. In this case, the threshold capillary occurrence pressure can be calculated using Eq. 6, but with θr replaced by π − θa (Valvatne 2004). If piston-like displacement occurs within an element during the forced imbibition and θa > π/2 + βi, a layer of oil is sandwiched between the water entering the center and the retained water in the corner of the element. Such oil layers can play a significant role in the oil phase connectivity and prevention of its trapping. This layer of oil will collapse at the current capillary pressure of (Valvatne 2004)

$${P_{{\text{c}},{\text{cur}}}}=\frac{{\sigma \cos \left[ {\arccos \left( {2\sin {\beta _i}+\cos {\theta _{\text{a}}}} \right)+{\beta _i}} \right]}}{{{b_i}\sin {\beta _i}}}.$$
(23)

Pore body filling

During the spontaneous imbibition, the required threshold capillary occurrence pressure for filling a pore body is a function of the largest attainable radius of curvature of water/oil interface. The curvature itself depends on the number of oil-filled throats connected to the pore (Lenormand et al. 1983). If only one of the connected throats is oil filled, pore body filling is similar to piston-like displacement and the same equations are applicable. Nevertheless, if the number of connected oil-filled throats is more than one, the threshold capillary occurrence pressure is expressed as (Blunt 1998)

$${P_{\text{c}}}=\frac{{2\sigma \cos {\theta _{\text{a}}}}}{r} - \sigma \sum\nolimits_{{i=1}}^{m} {{\lambda _i}{x_i}} - \left( {{\rho _{\text{w}}} - {\rho _{\text{o}}}} \right)gh,$$
(24)

where m is the number of connected oil-filled throats, λi are arbitrary numbers, and xi are random numbers between zero and one. λi can be related to absolute permeability of the network (Valvatne 2004):

$${\lambda _i}=\left\{ {\begin{array}{*{20}{l}} 0&{i=1} \\ {\frac{{0.03}}{{\sqrt {\frac{K}{{1.01325 \times 10^{15}}}} }}}&{i=2,3,...,m} \end{array}} \right..$$
(25)

In the forced imbibition process, pore body filling does not depend on the number of connected oil-filled throats, and the equations for piston-like displacement can be used.

Snap-off

Snap-off only occurs in non-circular elements with no adjacent oil-filled element. If water layers in the corner of such element swell so much that fluid/fluid interface becomes unstable, snap-off takes place and the element is instantly filled with water. Water in sharper corners swell in higher capillary pressures. During the spontaneous imbibition, if only water in the sharpest corner swells, snap-off occurs when it reaches the water in the most oblique corner at a threshold capillary occurrence pressure of (Valvatne 2004)

$$\begin{aligned} P_{{\text{c}}} & = \frac{\sigma }{r}\left( {\frac{{\cos \theta _{{\text{a}}} \cot \beta _{1} - \sin \theta _{{\text{a}}} + \cos \theta _{{{\text{h}},3}} \cot \beta _{3} - \sin \theta _{{{\text{h}},3}} }}{{\cot \beta _{1} + \cot \beta _{2} }}} \right) \\ & \quad- \left( {\rho _{{\text{w}}} - \rho _{{\text{o}}} } \right)gh. \\ \end{aligned}$$
(26)

If two or more corner water start to swell, snap-off occurs at the threshold capillary occurrence pressure of (Valvatne 2004)

$${P_{\text{c}}}=\frac{\sigma }{r}\left( {\cos {\theta _{\text{a}}} - \frac{{2\sin {\theta _{\text{a}}}}}{{\cot {\beta _1}+\cot {\beta _2}}}} \right) - \left( {{\rho _{\text{w}}} - {\rho _{\text{o}}}} \right)gh.$$
(27)

The event with higher threshold capillary occurrence pressure is always favored.

During forced imbibition, as soon as the following condition becomes true, snap-off occurs within the element (Valvatne 2004):

$${\theta _{{\text{h}},1}}=\left\{ {\begin{array}{*{20}{l}} {{\theta _{\text{a}}}}&{{\theta _{\text{a}}} \leq \pi - {\beta _1}} \\ {{\theta _{\text{a}}} - {\beta _1}}&{{\theta _{\text{a}}}>\pi - {\beta _1}} \end{array}} \right..$$
(28)

Threshold capillary occurrence pressure of snap-off during forced imbibition is calculated as (Valvatne 2004)

$${P_{\text{c}}}=\left\{ \begin{gathered} \frac{{\sigma \cos \left( {{\theta _{\text{a}}}+{\beta _1}} \right)}}{{{R_{{\rm min} }}\cos \left( {{\theta _{\text{r}}}+{\beta _1}} \right)}} - \left( {{\rho _{\text{w}}} - {\rho _{\text{o}}}} \right)gh{\text{ }}{\theta _{\text{a}}} \leq \pi - {\beta _1} \hfill \\ \frac{{ - \sigma }}{{{R_{{\rm min} }}\cos \left( {{\theta _{\text{r}}}+{\beta _1}} \right)}} - \left( {{\rho _{\text{w}}} - {\rho _{\text{o}}}} \right)gh{\text{ }}{\theta _{\text{a}}}>\pi - {\beta _1} \hfill \\ \end{gathered} \right..$$
(29)

Snap-off is the least favored displacement event, and only happens when other two displacement events are topologically impossible.

Displacement process

At the end of the primary drainage, water is introduced at the network inlet and the current capillary pressure is allowed to fall. In Starfish, the current capillary pressure reduction takes place from (+ CAPILLARYLIMIT) to (− CAPILLARYLIMIT) with a step size of (− CAPILLARYINCREMENT). In each step, all possible events having threshold capillary occurrence pressure higher than the current capillary pressure in the network, will happen. After that, fluid’s saturations in the entire network element are updated (using the same Eqs. 1015, but with θr replaced by θh,i) and printed in the outputs along with the current capillary pressure.

During the imbibition, the connectivity of the non-wetting phase must be checked in each step of capillary pressure reduction. Just like the drainage process, if the non-wetting phase in an element or a cluster element loses its connection to the network outlet, it is trapped and the capillary pressure in that element(s) will not change anymore. In the imbibition process, trapping is more common than the drainage process, because the non-wetting phase can be disconnected from the outlet more easily. Unlike the wetting phase, the non-wetting phase will not be retained within the elements once one of the displacement events happens. Snap-off events are able to isolate a clusters of oil surrounded by narrow throats and reduce the non-wetting phase connectivity further.

Absolute and relative permeability calculation

For permeability calculation, the conservation of mass equation is written for every pore i:

$$\sum\limits_{j} {{q_{p,ij}}=0} .$$
(30)

The sigma is the over all throats connected to pore i. The equation is valid if the flow is capillary dominant (viscous pressure drop is negligible compared to capillary pressure) and incompressible. The flow rate qp, between two pores i and k connected by throat j is expressed as

$${q_{p,ik}}={G_{p,ik}}\left( {{\Phi _{p,i}} - {\Phi _{p,k}}} \right),$$
(31)

where

$${G_{p,ik}}=\frac{1}{{\frac{{{L_i}}}{{{g_{p,i}}}}+\frac{{{L_j}}}{{{g_{p,j}}}}+\frac{{{L_k}}}{{{g_{p,k}}}}}}$$
(32)

and

$${\Phi _{p,i}}={P_i}+{\rho _p}g{h_i}.$$
(33)

Single-phase fluid conductance in a circular element is derived analytically from Hagen-Poiseuille equation:

$${g_p}=\nu \frac{{{A^2}G}}{{{\mu _p}}}$$
(34)

with ν = 0.5. For triangular elements, the same equation is used, but with ν = 0.6 (Øren et al. 1998). For polygonal elements, the single-phase fluid conductance can be calculated from (Tamayol and Bahrami 2010)

$${g_p}=\frac{{2{A^2}\sqrt G }}{{14.18+\frac{{0.5}}{N} - \frac{{26.4}}{{{N^2}}}+\frac{{102.18}}{{{N^3}}}}},$$
(35)

where N represent the number of sides.

To calculated oil conductance in an element containing both phases, we used Eq. 36 proposed by Øren et al. (1998):

$${g_{\text{o}}}=\nu \frac{{{{\left( {{S_{\text{o}}}A} \right)}^2}G}}{{{\mu _{\text{o}}}}}.$$
(36)

Water conductance calculation is more complex as suggested by Valvatne (2004):

$${A_{\text{c}}}={\left[ {\frac{{{b_i}\sin {\beta _i}}}{{\cos \left( {{\theta _{{\text{h}},i}}+{\beta _i}} \right)}}} \right]^2}\left[ {\frac{{\cos {\theta _{{\text{h,}}i}}\cos \left( {{\theta _{{\text{h}},i}}+{\beta _i}} \right)}}{{\sin {\beta _i}}}+{\theta _{{\text{h}},i}}+{\beta _i} - \frac{\pi }{2}} \right]$$
(37)
$${G_{\text{c}}}=\frac{{{A_{\text{c}}}}}{{4b_{i}^{2}{{\left[ {1 - \frac{{\sin {\beta _i}}}{{\cos \left( {{\theta _{{\text{h}},i}}+{\beta _i}} \right)}}\left( {{\theta _{{\text{h}},i}}+{\beta _i} - \frac{\pi }{2}} \right)} \right]}^2}}}$$
(38)
$${G^*}=\frac{{\sin {\beta _i}\cos {\beta _i}}}{{4{{\left( {1+\sin {\beta _i}} \right)}^2}}}$$
(39)
$${C_{\text{w}}}=0.364+0.28\frac{{{G^*}}}{{{G_{\text{c}}}}}$$
(40)
$${g_{\text{w}}}={C_{\text{w}}}\frac{{A_{{\text{c}}}^{2}{G_{\text{c}}}}}{{{\mu _{\text{w}}}}}.$$
(41)

In each step of current capillary pressure increment (for drainage) and decrement (for imbibition), relative permeability is calculated. To this purpose, the location and the state of the fluids within the network are assumed to be frozen, and the fluid’s conductivity is calculated. By solving Eq. 30 for an arbitrary pressure difference (ΔP) imposed on network ends, the pressure within each pore is acquired. Having the pressures, the flow rate and the velocity of the fluids in all throats are determined. Then, the flow rate of each phase in the throats connected to the network outlet is summed to get the total outflow rate of each phase. Now, the effective permeability of each phase can be calculated from Darcy’s law:

$${K_p}=1.01325 \times 10^{15}\frac{{{Q_p}{\mu _p}}}{{\Delta Y \cdot \Delta Z}} \cdot \frac{{\Delta X}}{{\Delta P}}.$$
(42)

Since the effective permeability of water in a network fully saturated with it (i.e., initial condition for drainage) is the absolute permeability of the network, the relative permeabilities are also calculable.

Note that the calculation of the permeabilities is an entirely separate procedure from the drainage/imbibition simulation, and hence, the imposed pressure difference is not the same as the current capillary pressure. In addition, except some minor round-off effects, the imposed pressure difference has no influence on the permeabilities value, because it is cancelled out during the calculations.

Code overview

Linear solver

Equation 30 leads to a system of linear equations, with its unknowns being the pressure in the pores. In most cases, the system is ill-conditioned, and a preconditioner is required to solve it properly. In Starfish, one can choose a linear solver library from two available options: PARALUTION (2016) v1.1.0 and PETSc (Balay et al. 1997) v3.8.3.

PARALUTION is an open-source library, which provides simple preconditioner and iterative linear solver routines. We have tried many preconditioner/linear solver combinations in PARALUTION and it was found that the Truncated Neumann Series (TNS) (Dubois et al. 1979) as the preconditioner and the Conjugate Gradient (CG) as the linear solver gives the best results. However, all of the implemented preconditioners in PARALUTION lose the ability to reduce the condition number of the linear system as the network size and its complexity grows. Consequently, the number of iterations of the linear solver increases and the accuracy of the results is decreased.

To address the shortcomings of PARALUTION, Starfish was modified to utilize the PETSc library. PETSc is also an open-source project and provides numerous scalable preconditioners/iterative linear solvers. PETSc was compiled using Cygwin alongside with Intel® compilers, MKL and MPI. Test runs reveal that PETSc has a clear advantage over PARALUTION in performance and accuracy. The most accurate and fastest results with PETSc were attained from combination of Jacobi preconditioner and CG solver.

Classes

NetworkElement

The NetworkElement class is the representative of the pore-scale network elements, i.e., pores and throats. It contains the properties and methods which the pores and throats share.

Pore and throat

The pore and throat classes inherit from NetworkElement and represents the pores and the throats in the network, respectively. Most of the methods and properties of the pore and the throats are the same for the drainage process. However, during the imbibitions process, the pores and throats go through different events. Therefore, most of the non-inherited members of these classes are related to the imbibition process.

ElementList

The ElementList class is used for storing the indexes of inlet and outlet pore/throats. Some of member functions in this class are reserved for future use (or deletion).

MIfstream

The MIfstream inherits from ifstream in C++ standard library. It adds two methods to the standard file input methods which can greatly help reading from text files. One of these methods (FileSearch) has been written to read keyword-based files, but it is currently unused and reserved.

Primary functions

ReadStatoilFormat

With assistance of Pore and Throat methods, this function reads the input files and allocates the necessary memory for dynamic arrays.

Drainage and imbibition

These two functions simulate primary drainage and primary imbibition processes and write the outputs.

RecursiveSweepForConnection

It determines the fluids connectivity throughout the network. Starting from the throats connecting to either ends of the network, it sweeps all adjacent network elements containing a specific phase (water or oil, depending on the function argument). If a network element has no neighbor containing that phase, sweep stops in that element. If the sweep does not get to the other end of the network, that phase is assumed to be trapped in the swept cluster of elements. The trapped phase has no connectivity, and hence, its conductance is zero in the trapped area.

Employing depth-first search (DFS) algorithm, RecursiveSweepForConnection does its job using an indirect recursion, where throats sweep their adjacent pores and those pores, in turn, sweep their adjacent throats.

CalcRelPerm

CalcRelPerm first calculates the fluids conductance of pores and throats. Then, using Poiseuille equation, the pressure in the pores and the flow rate of each phase in the throats are obtained. After that, the total outflow rate of each phase is calculated by summation of the flow rates of that phase in all of the throats connected to the network outlet. Finally, the outflow rates of the water and oil phases are put in Darcy’s equation to get the effective and relative permeabilities.

CalcAbsPerm

This function is just like CalcRelPerm function, with the difference that it calculates the permeability of a single-phase fluid which completely saturates the network, or the “absolute permeability”.

IO style

Input style

Starfish uses Statoil format for the network data files. In the Statoil format, there are two files (prefix_link1.dat and prefix_link2.dat) which contain throats data and two files (prefix_node1.dat and prefix_node2.dat) which contain pores data. The details of these files can be found in (Sochi 2010). Since fluids and rock/fluid data are not included in Statoil-format files, Starfish reads such data from another input file (prefix_fluid.dat). In this file, the following data must be entered, respectively, separated by space/Tab/new line characters:

  • Water density.

  • Oil density.

  • Water/oil interfacial tension.

  • Receding contact angle (in degrees).

  • Advancing contact angle (in degrees).

  • Water viscosity.

  • Oil viscosity.

The used unit system in all input files is SI. The prefix in files name is arbitrary and must be the same for all five input files. Before the simulation starts, Starfish asks the user to enter the prefix and the path of the input files.

Output style

Starfish writes capillary pressure, water relative permeability, and oil relative permeability as functions of water saturation in its output files. The outputs of the drainage process and imbibitions process are written in prefix_drainage.dat file and prefix_imbibition.dat file, respectively. In both output files, the absolute permeability and the wettability type of the network is printed at the top. The path and the prefix of the output files are the same as the input files. During the execution of Starfish, a copy of all output data is printed on the screen.

Parallel computing

The computational load of pore-scale network modeling is often considerable. Therefore, we employed parallel computing techniques to reduce the runtime of Starfish. We used MPI everywhere in the code that data transfer overload between the processes is negligible. In other parallelizable parts of the code, OpenMP API was adopted.

Results

To validate the Starfish model, we simulated a network extracted from reconstructed Berea sandstone (Dong and Blunt 2009). Table 1 shows the rock and fluids properties used in the simulation. The receding and advancing contact angles were obtained from a correlation proposed by Morrow (Mason and Morrow 1991). In Figs. 2, 3, 4, and 5, the simulation results are plotted against the steady-state experimental data from Oak (1990, Valvatne 2004).

Table 1 Rock and fluids properties for Berea sandstone
Fig. 2
figure 2

Simulated and experimental water relative permeability in drainage process

Fig. 3
figure 3

Simulated and experimental oil relative permeability in drainage process

Fig. 4
figure 4

Simulated and experimental water relative permeability in imbibition process

Fig. 5
figure 5

Simulated and experimental oil relative permeability in imbibition process

Clearly, Starfish predictions show a good match with the experimental data.

Future works

Starfish is still under development, and the following features are being added to the code:

  • Handling mixed-wet networks and extreme wettability changes.

  • Modeling of second drainage and subsequent flooding cycles.

  • Support for rectangular and polygonal elements.

  • Implementing more accurate methods for calculation of fluids conductance.

  • The ability to predict three-phase relative permeabilities.

In addition, as any other engineering simulation software, increasing Starfish performance and decreasing its runtime is very important. To this end, the performance bottlenecks will be identified and resolved, more efficient algorithms and calculation methods especially for preconditioner/iterative solver will be implemented and the time-consuming parts of the code will be gradually re-written using parallel programming techniques.

As an open-source project, the participation of other interested programmers in the development of Starfish is also possible. The Git system allows programmers to send pull requests, which if proved beneficial, are applied to Starfish code.

Summary and conclusion

Replacing the expensive SCAL experiments with a low cost, fast computer simulation was always a tempting ambition in petroleum engineering. Only in recent years, with emerging high-performance computers, it has become possible. Pore-scale network modeling is one of the tools that can predict capillary pressure, absolute and relative permeabilities of a reservoir rock sample. In the current paper, we introduced Starfish, an open-source, object-oriented pore-scale network modeling software; and its code details, employed algorithms and ongoing development efforts were discussed. In addition, it was observed that Starfish predictions for Berea sandstone and the experimental data are a good match.