Models
Methods can be imported from digirock.models
.
Basic Models
Functions related to the moduli and mixed moduli of minerals
This module contains functions related to the calculation of
- modulus bounds
- moduli for mixed mineral materials
- Gassmann fluid substitution
Refs
MacBeth, 2004, A classification for the pressure-sensitivity properties of a sandstone rock frame
Smith, Sondergeld and Rai, 2003, Gassmann fluid substitutions: A tutorial, Geophysics, 68, pp430-440
dryframe_acoustic(ksat, kfl, k0, phi)
Dry frame bulk modulus \(K^*\) from material saturated modulus
This is essentially inverse Gassmann fluid substitution and assumes you know the bulk modulus of
the matrix material k0
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
ksat |
Union[numpy.ndarray, float] |
saturated bulk modulus |
required |
kfl |
Union[numpy.ndarray, float] |
fluid bulk modulus |
required |
k0 |
Union[numpy.ndarray, float] |
matrix bulk modulus |
required |
phi |
Union[numpy.ndarray, float] |
porosity (frac) |
required |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
backed-out dry fame bulk modulus |
Source code in digirock/models/_mod.py
def dryframe_acoustic(
ksat: NDArrayOrFloat, kfl: NDArrayOrFloat, k0: NDArrayOrFloat, phi: NDArrayOrFloat
) -> NDArrayOrFloat:
"""Dry frame bulk modulus $K^*$ from material saturated modulus
This is essentially inverse Gassmann fluid substitution and assumes you know the bulk modulus of
the matrix material `k0`.
$$
K^* = \\frac{K_{sat}\\left( \\frac{\\phi K_0}{K_{fl}} + 1 - \\phi \\right) - K_0}{\\frac{\\phi K_0}{K_{fl}}+\\frac{K_{sat}}{K_0}-1-\\phi}
$$
Args:
ksat: saturated bulk modulus
kfl: fluid bulk modulus
k0: matrix bulk modulus
phi: porosity (frac)
Returns:
backed-out dry fame bulk modulus
"""
return (ksat * (phi * k0 / kfl + 1 - phi) - k0) / (
phi * k0 / kfl + ksat / k0 - 1 - phi
)
dryframe_density(rhob, rhofl, phi)
Dry frame grain density
Primarily used for fluid substitution.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rhob |
array-like |
saturated rock bulk modulus |
required |
rhofl |
array-like |
fluid density |
required |
phi |
array-like |
porosity (frac) |
required |
Returns:
Type | Description |
---|---|
(array-like) |
dry frame grain density |
Source code in digirock/models/_mod.py
def dryframe_density(rhob, rhofl, phi):
"""Dry frame grain density
Primarily used for fluid substitution.
Args:
rhob (array-like): saturated rock bulk modulus
rhofl (array-like): fluid density
phi (array-like): porosity (frac)
Returns:
(array-like): dry frame grain density
"""
return (rhob - rhofl * phi) / (1 - phi)
dryframe_dpres(dry_mod, pres1, pres2, sse, ssp)
Calculates the dry rock frame for a given stress regime by factoring the difference between two formation pressure scenarios.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
dry_mod |
Union[numpy.ndarray, float] |
Dryframe modulus (MPa) |
required |
pres1 |
Union[numpy.ndarray, float] |
Pressure calibrated to dryframe modulus. (MPa) |
required |
pres2 |
Union[numpy.ndarray, float] |
Pressure of output (MPa) |
required |
sse |
Union[numpy.ndarray, float] |
Stress-sensitivity parameter E |
required |
ssp |
Union[numpy.ndarray, float] |
Stress-sensitivity parameter P |
required |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
the dry-frame modulus adjusted to pressure (pres2) |
References
[1] Amini and Alvarez (2014) [2] MacBeth (2004)
Source code in digirock/models/_mod.py
def dryframe_dpres(
dry_mod: NDArrayOrFloat,
pres1: NDArrayOrFloat,
pres2: NDArrayOrFloat,
sse: NDArrayOrFloat,
ssp: NDArrayOrFloat,
) -> NDArrayOrFloat:
"""Calculates the dry rock frame for a given stress regime by factoring the
difference between two formation pressure scenarios.
$$
m(P) = m \\frac{1 + S_E e^{\\tfrac{-P_1}{S_P}}}{1 + S_E e^{\\tfrac{-P_2}{S_P}}}
$$
Args:
dry_mod: Dryframe modulus (MPa)
pres1: Pressure calibrated to dryframe modulus. (MPa)
pres2: Pressure of output (MPa)
sse: Stress-sensitivity parameter E
ssp: Stress-sensitivity parameter P
Returns:
the dry-frame modulus adjusted to pressure (pres2)
References:
[1] Amini and Alvarez (2014)
[2] MacBeth (2004)
"""
return (
dry_mod
* (1 + (sse * np.exp(-pres1 / ssp)))
/ (1 + (sse * np.exp(-pres2 / ssp)))
)
dryframe_stress(mod_e, mod_p, inf, p)
Dry frame bulk modulus from stress sensitivity coefficients.
Based on MacBeth 2004 for sandstone rock frame.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
mod_e |
array-like |
modulus stress sensitivity metric *2 MPa |
required |
mod_p |
array-like |
modulus characteristic pressure constant *2 MPa |
required |
inf |
array-like |
modulus background high pressure asymptote MPa |
required |
p |
array-like |
the effective pressure MPa |
required |
Source code in digirock/models/_mod.py
def dryframe_stress(mod_e, mod_p, inf, p):
"""Dry frame bulk modulus from stress sensitivity coefficients.
Based on MacBeth 2004 for sandstone rock frame.
Args:
mod_e (array-like): modulus stress sensitivity metric *2 MPa
mod_p (array-like): modulus characteristic pressure constant *2 MPa
inf (array-like): modulus background high pressure asymptote MPa
p (array-like): the effective pressure MPa
"""
return inf / (1 + (mod_e * np.exp(-p / mod_p)))
gassmann_fluidsub(kdry, kfl, k0, phi)
Gassmann fluid substitution for saturated rock bulk modulus
Gassmann fluid substitution assumes: The rock is homogenous and isotropic, rocks with diverse mineral acoustic properties will violate this assumption. All the porespace is connected, this is propably not true for low porosity rocks. The frequencies being used to measure the rock properties fall within the seismic bandwidth. Logging frequencies are usually ok for high-porosity clean sands. Homogeonous mixing of the fluid. This is reasonable over geologic time but may be inappropriate for production timescales.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
kdry |
Union[numpy.ndarray, float] |
dry frame rock bulk modulus |
required |
kfl |
Union[numpy.ndarray, float] |
fluid bulk modulus |
required |
k0 |
Union[numpy.ndarray, float] |
matrix bulk modulus |
required |
phi |
Union[numpy.ndarray, float] |
porosity (frac) |
required |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
ksat saturated rock bulk modulus |
Source code in digirock/models/_mod.py
def gassmann_fluidsub(
kdry: NDArrayOrFloat, kfl: NDArrayOrFloat, k0: NDArrayOrFloat, phi: NDArrayOrFloat
) -> NDArrayOrFloat:
"""Gassmann fluid substitution for saturated rock bulk modulus
Gassmann fluid substitution assumes:
The rock is homogenous and isotropic, rocks with diverse mineral acoustic properties will
violate this assumption.
All the porespace is connected, this is propably not true for low porosity rocks.
The frequencies being used to measure the rock properties fall within the seismic
bandwidth. Logging frequencies are usually ok for high-porosity clean sands.
Homogeonous mixing of the fluid. This is reasonable over geologic time but may be
inappropriate for production timescales.
Args:
kdry: dry frame rock bulk modulus
kfl: fluid bulk modulus
k0: matrix bulk modulus
phi: porosity (frac)
Returns:
ksat saturated rock bulk modulus
"""
return kdry + np.power(1 - kdry / k0, 2) / (
safe_divide(phi, kfl)
+ safe_divide((1 - phi), k0)
- safe_divide(kdry, np.power(k0, 2))
)
reuss_lower_bound(mod, frac, *argv)
Calculate the Reuss lower bound for material moduli
Parameters:
Name | Type | Description | Default |
---|---|---|---|
mod |
Union[numpy.ndarray, float] |
first fluid modulus |
required |
frac |
Union[numpy.ndarray, float] |
first fluid volume fraction |
required |
argv |
Union[numpy.ndarray, float] |
additional fluid and volume fraction pairs. |
() |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
Reuss upper bound for modulus mix |
Source code in digirock/models/_mod.py
def reuss_lower_bound(
mod: NDArrayOrFloat, frac: NDArrayOrFloat, *argv: NDArrayOrFloat
) -> NDArrayOrFloat:
"""Calculate the Reuss lower bound for material moduli
Args:
mod: first fluid modulus
frac: first fluid volume fraction
argv: additional fluid and volume fraction pairs.
Returns:
Reuss upper bound for modulus mix
"""
args = _process_vfrac(*((mod, frac) + argv))
mod_sum = 0
for modi, vfraci in chunked(args, 2):
mod_sum = mod_sum + safe_divide(np.array(vfraci), np.array(modi))
return safe_divide(1, mod_sum)
saturated_density(rhog, rhofl, phi)
Saturated bulk density
Parameters:
Name | Type | Description | Default |
---|---|---|---|
rhog |
array-like |
dry frame grain density |
required |
rhofl |
array-like |
fluid density |
required |
phi |
array-like |
porosity (frac) |
required |
Returns:
Type | Description |
---|---|
(array-like) |
saturated rock bulk density (rhob) |
Source code in digirock/models/_mod.py
def saturated_density(rhog, rhofl, phi):
"""Saturated bulk density
Args:
rhog (array-like): dry frame grain density
rhofl (array-like): fluid density
phi (array-like): porosity (frac)
Returns:
(array-like): saturated rock bulk density (rhob)
"""
return rhog * (1 - phi) + rhofl * phi
voigt_upper_bound(mod, frac, *argv)
Calculate the Voigt upper bound for material moduli
Parameters:
Name | Type | Description | Default |
---|---|---|---|
mod |
Union[numpy.ndarray, float] |
first fluid modulus |
required |
frac |
Union[numpy.ndarray, float] |
first fluid volume fraction |
required |
argv |
Union[numpy.ndarray, float] |
additional fluid and volume fraction pairs. |
() |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
Voigt upper bound for modulus mix |
Source code in digirock/models/_mod.py
def voigt_upper_bound(
mod: NDArrayOrFloat, frac: NDArrayOrFloat, *argv: NDArrayOrFloat
) -> NDArrayOrFloat:
"""Calculate the Voigt upper bound for material moduli
Args:
mod: first fluid modulus
frac: first fluid volume fraction
argv: additional fluid and volume fraction pairs.
Returns:
Voigt upper bound for modulus mix
"""
args = _process_vfrac(*((mod, frac) + argv))
mod_sum = 0
for modi, vfraci in chunked(args, 2):
mod_sum = mod_sum + np.array(vfraci) * np.array(modi)
return mod_sum
vrh_avg(mod, frac, *argv)
Calculates the Voigt-Reuss-Hill average for a multi-modulus mix.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
mod |
Union[numpy.ndarray, float] |
first modulus |
required |
frac |
Union[numpy.ndarray, float] |
first volume fraction |
required |
argv |
Union[numpy.ndarray, float] |
additional modulus and volume fraction pairs. |
() |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
Voigt-Reuss-Hill average modulus |
Source code in digirock/models/_mod.py
def vrh_avg(
mod: NDArrayOrFloat, frac: NDArrayOrFloat, *argv: NDArrayOrFloat
) -> NDArrayOrFloat:
"""Calculates the Voigt-Reuss-Hill average for a multi-modulus mix.
Args:
mod: first modulus
frac: first volume fraction
argv: additional modulus and volume fraction pairs.
Returns:
Voigt-Reuss-Hill average modulus
"""
vub = voigt_upper_bound(mod, frac, *argv)
rlb = reuss_lower_bound(mod, frac, *argv)
return 0.5 * (vub + rlb)
Hashin-Shtrikman Model
Hashin-Shtrikman-Walpole Models for moduli mixing.
Refs
Mavko et. al. (2009) The Rock Physics Handbook, Cambridge Press
hs_kbounds2(k1, k2, mu1, f1)
Calculate the Hashin-Shtrikman bulk moduli bounds for an isotropic elastic mixture
Upper and lower bounds are computed by interchanging which constituent material is subscripted 1 and which is subscripted 2. In general:
- Upper bound -> stiffest material is subscripted 1
- Lower bound -> stiffest material is subscripted 1
Parameters:
Name | Type | Description | Default |
---|---|---|---|
k1 |
Union[numpy.ndarray, float] |
constituent one bulk modulus |
required |
k2 |
Union[numpy.ndarray, float] |
constituent two bulk modulus |
required |
mu1 |
Union[numpy.ndarray, float] |
constituent one shear modulus |
required |
f1 |
material one volume fraction 0 <= f1 <= 1 |
required |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
HS bulk modulus bounds |
Refs
Rock Physics Handbook p170
Source code in digirock/models/_hsw.py
def hs_kbounds2(
k1: NDArrayOrFloat, k2: NDArrayOrFloat, mu1: NDArrayOrFloat, f1
) -> NDArrayOrFloat:
"""Calculate the Hashin-Shtrikman bulk moduli bounds for an isotropic elastic mixture
Upper and lower bounds are computed by interchanging which constituent material is
subscripted 1 and which is subscripted 2. In general:
- Upper bound -> stiffest material is subscripted 1
- Lower bound -> stiffest material is subscripted 1
Args:
k1: constituent one bulk modulus
k2: constituent two bulk modulus
mu1: constituent one shear modulus
f1: material one volume fraction 0 <= f1 <= 1
Returns:
HS bulk modulus bounds
Refs:
Rock Physics Handbook p170
"""
return k1 + (1 - f1) / (1 / (k2 - k1) + f1 / (k1 + 4 * mu1 / 3))
hs_mubounds2(k1, mu1, mu2, f1)
Calculate the Hashin-Shtrikman shear moduli bounds for an isotropic elastic mixture
Upper and lower bounds are computed by interchanging which constituent material is subscripted 1 and which is subscripted 2. In general:
- Upper bound -> stiffest material is subscripted 1
- Lower bound -> stiffest material is subscripted 1
Parameters:
Name | Type | Description | Default |
---|---|---|---|
k1 |
Union[numpy.ndarray, float] |
constituent one bulk modulus |
required |
mu1 |
Union[numpy.ndarray, float] |
constituent one shear modulus |
required |
mu2 |
Union[numpy.ndarray, float] |
constituent two shear modulus |
required |
f1 |
Union[numpy.ndarray, float] |
material one volume fraction 0 <= f1 <= 1 |
required |
Returns:
Type | Description |
---|---|
Union[numpy.ndarray, float] |
HS shear modulus bounds (positive) |
Refs
Rock Physics Handbook p170
Source code in digirock/models/_hsw.py
def hs_mubounds2(
k1: NDArrayOrFloat, mu1: NDArrayOrFloat, mu2: NDArrayOrFloat, f1: NDArrayOrFloat
) -> NDArrayOrFloat:
"""Calculate the Hashin-Shtrikman shear moduli bounds for an isotropic elastic mixture
Upper and lower bounds are computed by interchanging which constituent material is
subscripted 1 and which is subscripted 2. In general:
- Upper bound -> stiffest material is subscripted 1
- Lower bound -> stiffest material is subscripted 1
Args:
k1: constituent one bulk modulus
mu1: constituent one shear modulus
mu2: constituent two shear modulus
f1: material one volume fraction 0 <= f1 <= 1
Return:
HS shear modulus bounds (positive)
Refs:
Rock Physics Handbook p170
"""
return mu1 + (1 - f1) / (
(1 / (mu2 - mu1)) + 2 * f1 * (k1 + 2 * mu1) / (5 * mu1 * (k1 + 4 * mu1 / 3))
)
hsw_avg(bulk_mod, shear_mod, frac, *argv)
Hashin-Shtrikman-Walpole average moduli for N materials.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
bulk_mod |
Union[numpy.ndarray, float] |
first component bulk modulus |
required |
shear_mod |
Union[numpy.ndarray, float] |
first component shear modulus |
required |
frac |
Union[numpy.ndarray, float] |
first component volume fraction |
required |
*argv |
Union[numpy.ndarray, float] |
additional triplets of bulk_mod, shear_mod and frac for additional components |
() |
Returns:
Type | Description |
---|---|
Tuple[Union[numpy.ndarray, float], Union[numpy.ndarray, float]] |
K_hs_avg, Mu_hs_avg |
Source code in digirock/models/_hsw.py
def hsw_avg(
bulk_mod: NDArrayOrFloat,
shear_mod: NDArrayOrFloat,
frac: NDArrayOrFloat,
*argv: NDArrayOrFloat,
) -> Tuple[NDArrayOrFloat, NDArrayOrFloat]:
"""Hashin-Shtrikman-Walpole average moduli for N materials.
Args:
bulk_mod: first component bulk modulus
shear_mod: first component shear modulus
frac: first component volume fraction
*argv: additional triplets of bulk_mod, shear_mod and frac for additional components
Returns:
K_hs_avg, Mu_hs_avg
"""
k_hsp, k_hsm, mu_hsp, mu_hsm = hsw_bounds(bulk_mod, shear_mod, frac, *argv)
return 0.5 * (k_hsp + k_hsm), 0.5 * (mu_hsp + mu_hsm)
hsw_bounds(bulk_mod, shear_mod, frac, *argv)
Hashin-Shtrikman-Walpole bounds
Parameters:
Name | Type | Description | Default |
---|---|---|---|
bulk_mod |
Union[numpy.ndarray, float] |
first component bulk modulus |
required |
shear_mod |
Union[numpy.ndarray, float] |
first component shear modulus |
required |
frac |
Union[numpy.ndarray, float] |
first component volume fraction |
required |
*argv |
Union[numpy.ndarray, float] |
additional triplets of bulk_mod, shear_mod and frac for additional components |
() |
Returns:
Type | Description |
---|---|
Tuple[Union[numpy.ndarray, float], Union[numpy.ndarray, float], Union[numpy.ndarray, float], Union[numpy.ndarray, float]] |
K_hsp, K_hsm, Mu_hsp, Mu_hsm |
Refs
Rock Physics Handbook p171-172
This example comes form the RPH p172
Examples:
hsw_bounds(35, 45, (1-0.27)*0.8, 75, 31, (1-0.27)*0.2, 2.2, 0) # porosity is 0.27
>>> (array([26.43276985]), array([7.07415429]), array([24.61588052]), array([0.]))
Source code in digirock/models/_hsw.py
def hsw_bounds(
bulk_mod: NDArrayOrFloat,
shear_mod: NDArrayOrFloat,
frac: NDArrayOrFloat,
*argv: NDArrayOrFloat,
) -> Tuple[NDArrayOrFloat, NDArrayOrFloat, NDArrayOrFloat, NDArrayOrFloat]:
"""Hashin-Shtrikman-Walpole bounds
$$
K^{HS^+} = \\Lambda(\\mu_{max})
$$
Args:
bulk_mod: first component bulk modulus
shear_mod: first component shear modulus
frac: first component volume fraction
*argv: additional triplets of bulk_mod, shear_mod and frac for additional components
Returns:
K_hsp, K_hsm, Mu_hsp, Mu_hsm
Refs:
Rock Physics Handbook p171-172
This example comes form the RPH p172
Examples:
```
hsw_bounds(35, 45, (1-0.27)*0.8, 75, 31, (1-0.27)*0.2, 2.2, 0) # porosity is 0.27
>>> (array([26.43276985]), array([7.07415429]), array([24.61588052]), array([0.]))
```
"""
args = _process_vfrac(*(bulk_mod, shear_mod, frac) + argv, i=2)
shear_min = _hsw_get_minmax(
*(v for i, v in enumerate(args) if i % 3 != 0), minmax="min"
)
shear_max = _hsw_get_minmax(
*(v for i, v in enumerate(args) if i % 3 != 0), minmax="max"
)
bulk_min = _hsw_get_minmax(
*(v for i, v in enumerate(args) if i % 3 != 1), minmax="min"
)
bulk_max = _hsw_get_minmax(
*(v for i, v in enumerate(args) if i % 3 != 1), minmax="max"
)
k_hsp = _hsw_bulk_modulus_avg(
shear_max, *(v for i, v in enumerate(args) if i % 3 != 1)
)
k_hsm = _hsw_bulk_modulus_avg(
shear_min, *(v for i, v in enumerate(args) if i % 3 != 1)
)
zeta_hsp = _hsw_zeta(bulk_max, shear_max)
zeta_hsm = _hsw_zeta(bulk_min, shear_min)
mu_hsp = _hsw_shear_modulus_avg(
zeta_hsp, *(v for i, v in enumerate(args) if i % 3 != 0)
)
mu_hsm = _hsw_shear_modulus_avg(
zeta_hsm, *(v for i, v in enumerate(args) if i % 3 != 0)
)
to_shp = check_broadcastable(
**{
"k_hsp": k_hsp,
"k_hsm": k_hsm,
"mu_hsp": mu_hsm,
"mu_hsm": mu_hsm,
}
)
return tuple(np.broadcast_to(ar, to_shp) for ar in (k_hsp, k_hsm, mu_hsp, mu_hsm))
Cemented Sand Model
Cemented Sand Model
Refs
Mavko et. al. (2009) The Rock Physics Handbook, Cambridge Press pp 255-257
dryframe_cemented_sand(k_sand, mu_sand, k_cem, mu_cem, phi0, phi, ncontacts=9, alpha='scheme1')
Dryframe moduli for Cemented-Sand model.
Assumes sand grains are in contact and cement fills the porespace between grains.
Scheme 1: Cement preferentially fills spaces around contacts increasing shear strength.
Scheme 2: Cement covers grains evenly but maintains contacts between sand grains.
alpha can also be NDArrayOrFloat
for a custom scheme.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
k_sand |
Union[numpy.ndarray, float] |
Bulk modulus of sand grains |
required |
mu_sand |
Union[numpy.ndarray, float] |
Shear modulus of sand grains |
required |
k_cem |
Union[numpy.ndarray, float] |
Bulk modulus of cement |
required |
mu_cem |
Union[numpy.ndarray, float] |
Shear modulus of cement |
required |
phi0 |
Union[numpy.ndarray, float] |
Material porosity without any cement. For perfect spherical grains phi0 = 0.36 |
required |
phi |
Union[numpy.ndarray, float] |
Material porosity after substituting in cement to porespace |
required |
ncontacts |
int |
Number of contacts between grains |
9 |
alpha |
Union[str, numpy.ndarray, float] |
The cement fill scheme to use, one of ['scheme1', 'scheme2', |
'scheme1' |
Returns:
Type | Description |
---|---|
Tuple[Union[numpy.ndarray, float], Union[numpy.ndarray, float]] |
Bulk and shear modului of cemented-sand. |
Source code in digirock/models/_cemented_sand.py
def dryframe_cemented_sand(
k_sand: NDArrayOrFloat,
mu_sand: NDArrayOrFloat,
k_cem: NDArrayOrFloat,
mu_cem: NDArrayOrFloat,
phi0: NDArrayOrFloat,
phi: NDArrayOrFloat,
ncontacts: int = 9,
alpha: Union[str, NDArrayOrFloat] = "scheme1",
) -> Tuple[NDArrayOrFloat, NDArrayOrFloat]:
"""Dryframe moduli for Cemented-Sand model.
Assumes sand grains are in contact and cement fills the porespace between grains.
Scheme 1: Cement preferentially fills spaces around contacts increasing shear strength.
Scheme 2: Cement covers grains evenly but maintains contacts between sand grains.
alpha can also be `NDArrayOrFloat` for a custom scheme.
Args:
k_sand: Bulk modulus of sand grains
mu_sand: Shear modulus of sand grains
k_cem: Bulk modulus of cement
mu_cem: Shear modulus of cement
phi0: Material porosity without any cement. For perfect spherical grains phi0 = 0.36
phi: Material porosity after substituting in cement to porespace
ncontacts: Number of contacts between grains
alpha: The cement fill scheme to use, one of ['scheme1', 'scheme2', `NDArrayOrFloat`]
Returns:
Bulk and shear modului of cemented-sand.
"""
pois_sand = poisson_ratio(k_sand, mu_sand)
pois_cem = poisson_ratio(k_cem, mu_cem)
alpha = _cemented_sand_alpha(phi0, phi, ncontacts, alpha)
lam_tau = mu_cem / (pi * mu_sand)
lam_n = (2 * mu_cem * (1 - pois_sand) * (1 - pois_cem)) / (
pi * mu_sand * (1 - 2 * pois_cem)
)
pois_sand2 = power(pois_sand, 2)
c_tau = (
10e-4
* (9.654 * pois_sand2 + 4.945 * pois_sand + 3.1)
* power(lam_tau, 0.01867 * pois_sand2 + 0.4011 * pois_sand - 1.8186)
)
b_tau = (0.0573 * pois_sand2 + 0.0937 * pois_sand + 0.202) * power(
lam_tau, 0.0274 * pois_sand2 + 0.0529 * pois_sand - 0.8765
)
a_tau = (
-0.01
* (2.26 * pois_sand2 + 2.07 * pois_sand + 2.3)
* power(lam_tau, 0.079 * pois_sand2 + 0.1754 * pois_sand - 1.342)
)
s_tau = a_tau * power(alpha, 2) + b_tau * alpha + c_tau
c_n = 0.00024649 * power(lam_n, -1.9864)
b_n = 0.20405 * power(lam_n, -0.89008)
a_n = -0.024153 * power(lam_n, -1.3646)
s_n = a_n * power(alpha, 2) + b_n * alpha + c_n
keff = (ncontacts * k_cem * s_n / 6) * (1 - phi0)
return (keff, 3 * keff / 5 + (3 * ncontacts * mu_cem * s_tau / 20.0) * (1 - phi0))