rock-physics-open 0.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rock_physics_open/__init__.py +0 -0
- rock_physics_open/equinor_utilities/__init__.py +0 -0
- rock_physics_open/equinor_utilities/anisotropy.py +211 -0
- rock_physics_open/equinor_utilities/classification_functions/__init__.py +17 -0
- rock_physics_open/equinor_utilities/classification_functions/class_stats.py +68 -0
- rock_physics_open/equinor_utilities/classification_functions/lin_class.py +53 -0
- rock_physics_open/equinor_utilities/classification_functions/mahal_class.py +63 -0
- rock_physics_open/equinor_utilities/classification_functions/norm_class.py +73 -0
- rock_physics_open/equinor_utilities/classification_functions/poly_class.py +45 -0
- rock_physics_open/equinor_utilities/classification_functions/post_prob.py +27 -0
- rock_physics_open/equinor_utilities/classification_functions/two_step_classification.py +60 -0
- rock_physics_open/equinor_utilities/conversions.py +10 -0
- rock_physics_open/equinor_utilities/gen_utilities/__init__.py +11 -0
- rock_physics_open/equinor_utilities/gen_utilities/dict_to_float.py +38 -0
- rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +113 -0
- rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +131 -0
- rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +88 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +15 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/base_pressure_model.py +170 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/dummy_vars.py +53 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +137 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +77 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/polynomial_model.py +132 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +209 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +241 -0
- rock_physics_open/equinor_utilities/optimisation_utilities/__init__.py +19 -0
- rock_physics_open/equinor_utilities/optimisation_utilities/opt_subst_utilities.py +455 -0
- rock_physics_open/equinor_utilities/snapshot_test_utilities/__init__.py +10 -0
- rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +184 -0
- rock_physics_open/equinor_utilities/snapshot_test_utilities/snapshots.py +97 -0
- rock_physics_open/equinor_utilities/std_functions/__init__.py +43 -0
- rock_physics_open/equinor_utilities/std_functions/backus_ave.py +68 -0
- rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +77 -0
- rock_physics_open/equinor_utilities/std_functions/gassmann.py +165 -0
- rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +224 -0
- rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +51 -0
- rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +67 -0
- rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +120 -0
- rock_physics_open/equinor_utilities/std_functions/rho.py +69 -0
- rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +149 -0
- rock_physics_open/equinor_utilities/std_functions/walton.py +45 -0
- rock_physics_open/equinor_utilities/std_functions/wood_brie.py +94 -0
- rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.gif +0 -0
- rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.ico +0 -0
- rock_physics_open/equinor_utilities/various_utilities/__init__.py +24 -0
- rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +90 -0
- rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +56 -0
- rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +56 -0
- rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +64 -0
- rock_physics_open/equinor_utilities/various_utilities/hs_average.py +59 -0
- rock_physics_open/equinor_utilities/various_utilities/pressure.py +96 -0
- rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +101 -0
- rock_physics_open/equinor_utilities/various_utilities/timeshift.py +104 -0
- rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +170 -0
- rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +83 -0
- rock_physics_open/fluid_models/__init__.py +9 -0
- rock_physics_open/fluid_models/brine_model/__init__.py +5 -0
- rock_physics_open/fluid_models/brine_model/brine_properties.py +178 -0
- rock_physics_open/fluid_models/gas_model/__init__.py +5 -0
- rock_physics_open/fluid_models/gas_model/gas_properties.py +319 -0
- rock_physics_open/fluid_models/oil_model/__init__.py +5 -0
- rock_physics_open/fluid_models/oil_model/dead_oil_density.py +65 -0
- rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +30 -0
- rock_physics_open/fluid_models/oil_model/live_oil_density.py +82 -0
- rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +24 -0
- rock_physics_open/fluid_models/oil_model/oil_bubble_point.py +69 -0
- rock_physics_open/fluid_models/oil_model/oil_properties.py +146 -0
- rock_physics_open/sandstone_models/__init__.py +59 -0
- rock_physics_open/sandstone_models/cemented_shalysand_sandyshale_models.py +304 -0
- rock_physics_open/sandstone_models/constant_cement_models.py +204 -0
- rock_physics_open/sandstone_models/constant_cement_optimisation.py +125 -0
- rock_physics_open/sandstone_models/contact_cement_model.py +138 -0
- rock_physics_open/sandstone_models/curvefit_sandstone_models.py +143 -0
- rock_physics_open/sandstone_models/friable_models.py +177 -0
- rock_physics_open/sandstone_models/friable_optimisation.py +115 -0
- rock_physics_open/sandstone_models/friable_shalysand_sandyshale_models.py +235 -0
- rock_physics_open/sandstone_models/patchy_cement_fluid_substitution_model.py +477 -0
- rock_physics_open/sandstone_models/patchy_cement_model.py +384 -0
- rock_physics_open/sandstone_models/patchy_cement_optimisation.py +254 -0
- rock_physics_open/sandstone_models/unresolved_cemented_sandshale_models.py +134 -0
- rock_physics_open/sandstone_models/unresolved_friable_sandshale_models.py +126 -0
- rock_physics_open/shale_models/__init__.py +19 -0
- rock_physics_open/shale_models/dem.py +174 -0
- rock_physics_open/shale_models/dem_dual_por.py +61 -0
- rock_physics_open/shale_models/kus_tok.py +59 -0
- rock_physics_open/shale_models/multi_sca.py +133 -0
- rock_physics_open/shale_models/pq.py +102 -0
- rock_physics_open/shale_models/sca.py +90 -0
- rock_physics_open/shale_models/shale4_mineral.py +147 -0
- rock_physics_open/shale_models/shale4_mineral_dem_overlay.py +92 -0
- rock_physics_open/span_wagner/__init__.py +5 -0
- rock_physics_open/span_wagner/co2_properties.py +444 -0
- rock_physics_open/span_wagner/coefficients.py +165 -0
- rock_physics_open/span_wagner/equations.py +104 -0
- rock_physics_open/span_wagner/tables/__init__.py +0 -0
- rock_physics_open/span_wagner/tables/carbon_dioxide_density.npz +0 -0
- rock_physics_open/span_wagner/tables/lookup_table.py +33 -0
- rock_physics_open/t_matrix_models/Equinor_logo.ico +0 -0
- rock_physics_open/t_matrix_models/__init__.py +35 -0
- rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +124 -0
- rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +123 -0
- rock_physics_open/t_matrix_models/curvefit_t_matrix_min.py +86 -0
- rock_physics_open/t_matrix_models/parse_t_matrix_inputs.py +297 -0
- rock_physics_open/t_matrix_models/run_t_matrix.py +243 -0
- rock_physics_open/t_matrix_models/t_matrix_C.py +210 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +137 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +167 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +76 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +89 -0
- rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +176 -0
- rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +162 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/__init__.py +12 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/array_functions.py +75 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_c_eff.py +163 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_isolated.py +95 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd.py +40 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_eff.py +116 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_uuv.py +18 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_pressure.py +140 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_t.py +71 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_td.py +42 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_theta.py +43 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_x.py +33 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_z.py +50 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/check_and_tile.py +43 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/g_tensor.py +140 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/iso_av.py +60 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/iso_ave_all.py +55 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/pressure_input.py +44 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/t_matrix_vec.py +278 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/velocity_vti_angles.py +81 -0
- rock_physics_open/t_matrix_models/tmatrix_python.dll +0 -0
- rock_physics_open/t_matrix_models/tmatrix_python.so +0 -0
- rock_physics_open/ternary_plots/__init__.py +3 -0
- rock_physics_open/ternary_plots/gen_ternary_plot.py +73 -0
- rock_physics_open/ternary_plots/shale_prop_ternary.py +337 -0
- rock_physics_open/ternary_plots/ternary_patches.py +277 -0
- rock_physics_open/ternary_plots/ternary_plot_utilities.py +197 -0
- rock_physics_open/ternary_plots/unconventionals_ternary.py +75 -0
- rock_physics_open/version.py +34 -0
- rock_physics_open-0.3.2.dist-info/METADATA +90 -0
- rock_physics_open-0.3.2.dist-info/RECORD +145 -0
- rock_physics_open-0.3.2.dist-info/WHEEL +5 -0
- rock_physics_open-0.3.2.dist-info/licenses/LICENSE +165 -0
- rock_physics_open-0.3.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import numpy.typing as npt
|
|
7
|
+
|
|
8
|
+
INITIATE = False
|
|
9
|
+
|
|
10
|
+
SYSTEM_AND_DEBUG_FCN = [
|
|
11
|
+
"pydev",
|
|
12
|
+
"ipython-input",
|
|
13
|
+
"interactiveshell",
|
|
14
|
+
"async_helpers",
|
|
15
|
+
"handle_snapshots",
|
|
16
|
+
"run_code",
|
|
17
|
+
"run_ast_nodes",
|
|
18
|
+
"run_cell_async",
|
|
19
|
+
"_pseudo_sync_runner",
|
|
20
|
+
"_run_cell",
|
|
21
|
+
"run_cell",
|
|
22
|
+
"add_exec",
|
|
23
|
+
"do_add_exec",
|
|
24
|
+
"add_exec",
|
|
25
|
+
"ipython_exec_code",
|
|
26
|
+
"console_exec",
|
|
27
|
+
"do_it",
|
|
28
|
+
"process_internal_commands",
|
|
29
|
+
"_do_wait_suspend",
|
|
30
|
+
"do_wait_suspend",
|
|
31
|
+
"compare_snapshots",
|
|
32
|
+
"handle_snapshots",
|
|
33
|
+
"wrapper",
|
|
34
|
+
"run_tests",
|
|
35
|
+
"<module>",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_snapshot_name(
|
|
40
|
+
step: int = 1,
|
|
41
|
+
include_filename: bool = True,
|
|
42
|
+
include_function_name: bool = True,
|
|
43
|
+
include_extension: bool = True,
|
|
44
|
+
include_snapshot_dir: bool = True,
|
|
45
|
+
) -> str:
|
|
46
|
+
"""
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
step: number of steps in the trace to collect information from
|
|
50
|
+
include_snapshot_dir: absolute directory name included in snapshot name
|
|
51
|
+
include_filename: whether to include filename in snapshot name
|
|
52
|
+
include_function_name: whether to include function name in snapshot name
|
|
53
|
+
include_extension: whether to include extension in snapshot name
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
name of snapshot file
|
|
58
|
+
"""
|
|
59
|
+
trace = inspect.stack()
|
|
60
|
+
for frame in trace[step:]:
|
|
61
|
+
if not any(keyword in frame.function for keyword in SYSTEM_AND_DEBUG_FCN):
|
|
62
|
+
break
|
|
63
|
+
else:
|
|
64
|
+
frame = trace[step]
|
|
65
|
+
|
|
66
|
+
dir_name = Path(frame.filename).parents[1] / "data" / "snapshots"
|
|
67
|
+
file_name = Path(frame.filename).stem if include_filename else ""
|
|
68
|
+
function_name = frame.function if include_function_name else ""
|
|
69
|
+
extension = ".npz" if include_extension else ""
|
|
70
|
+
parts = [part for part in [file_name, function_name] if part]
|
|
71
|
+
base_name = "_".join(parts) + extension
|
|
72
|
+
return str(dir_name / base_name) if include_snapshot_dir else base_name
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def store_snapshot(snapshot_name: str, *args: np.ndarray) -> bool:
|
|
76
|
+
"""
|
|
77
|
+
Examples
|
|
78
|
+
--------
|
|
79
|
+
In case there are multiple arrays to store:
|
|
80
|
+
store_snapshot(snapshot_name='snap_to_store.npz', *args)
|
|
81
|
+
|
|
82
|
+
Important: If there is only one array to store:
|
|
83
|
+
store_snapshot(snapshot_name='snap_to_store.npz', args)
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
np.savez(snapshot_name, *args)
|
|
87
|
+
except IOError as e:
|
|
88
|
+
raise IOError(f"Could not store snapshot {snapshot_name}: {e}")
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def read_snapshot(snapshot_name: str) -> tuple[npt.NDArray[Any], ...]:
|
|
93
|
+
try:
|
|
94
|
+
with np.load(snapshot_name) as stored_npz:
|
|
95
|
+
return tuple(stored_npz[arr_name] for arr_name in stored_npz.files)
|
|
96
|
+
except IOError as e:
|
|
97
|
+
raise ValueError(f"unable to load snapshot {snapshot_name}: {e}")
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from .backus_ave import backus_average
|
|
2
|
+
from .dvorkin_nur import dvorkin_contact_cement
|
|
3
|
+
from .gassmann import gassmann, gassmann2, gassmann_dry
|
|
4
|
+
from .hashin_shtrikman import (
|
|
5
|
+
hashin_shtrikman,
|
|
6
|
+
hashin_shtrikman_average,
|
|
7
|
+
hashin_shtrikman_walpole,
|
|
8
|
+
multi_hashin_shtrikman,
|
|
9
|
+
)
|
|
10
|
+
from .hertz_mindlin import hertz_mindlin
|
|
11
|
+
from .moduli_velocity import moduli, velocity
|
|
12
|
+
from .reflection_eq import aki_richards, smith_gidlow
|
|
13
|
+
from .rho import rho_b, rho_m
|
|
14
|
+
from .voigt_reuss_hill import multi_voigt_reuss_hill, reuss, voigt, voigt_reuss_hill
|
|
15
|
+
from .walton import walton_smooth
|
|
16
|
+
from .wood_brie import brie, multi_wood, wood
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"backus_average",
|
|
20
|
+
"dvorkin_contact_cement",
|
|
21
|
+
"gassmann",
|
|
22
|
+
"gassmann2",
|
|
23
|
+
"gassmann_dry",
|
|
24
|
+
"hashin_shtrikman",
|
|
25
|
+
"hashin_shtrikman_average",
|
|
26
|
+
"hashin_shtrikman_walpole",
|
|
27
|
+
"multi_hashin_shtrikman",
|
|
28
|
+
"hertz_mindlin",
|
|
29
|
+
"moduli",
|
|
30
|
+
"velocity",
|
|
31
|
+
"aki_richards",
|
|
32
|
+
"smith_gidlow",
|
|
33
|
+
"rho_b",
|
|
34
|
+
"rho_m",
|
|
35
|
+
"multi_voigt_reuss_hill",
|
|
36
|
+
"reuss",
|
|
37
|
+
"voigt",
|
|
38
|
+
"voigt_reuss_hill",
|
|
39
|
+
"walton_smooth",
|
|
40
|
+
"brie",
|
|
41
|
+
"multi_wood",
|
|
42
|
+
"wood",
|
|
43
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def backus_average(
|
|
6
|
+
vp1: npt.NDArray[np.float64],
|
|
7
|
+
vs1: npt.NDArray[np.float64],
|
|
8
|
+
rho1: npt.NDArray[np.float64],
|
|
9
|
+
vp2: npt.NDArray[np.float64],
|
|
10
|
+
vs2: npt.NDArray[np.float64],
|
|
11
|
+
rho2: npt.NDArray[np.float64],
|
|
12
|
+
f1: npt.NDArray[np.float64],
|
|
13
|
+
) -> tuple[
|
|
14
|
+
npt.NDArray[np.float64],
|
|
15
|
+
npt.NDArray[np.float64],
|
|
16
|
+
npt.NDArray[np.float64],
|
|
17
|
+
npt.NDArray[np.float64],
|
|
18
|
+
npt.NDArray[np.float64],
|
|
19
|
+
]:
|
|
20
|
+
"""
|
|
21
|
+
Backus average for a combination of two phases. The individual phases are isotropic
|
|
22
|
+
but the resulting effective medium is not.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
vp1 : np.ndarray
|
|
27
|
+
Pressure wave velocity for phase 1 [m/s].
|
|
28
|
+
vs1 : np.ndarray
|
|
29
|
+
Shear wave velocity for phase 1 [m/s].
|
|
30
|
+
rho1 : np.ndarray
|
|
31
|
+
Density for phase 1 [kg/m^3].
|
|
32
|
+
vp2 : np.ndarray
|
|
33
|
+
Pressure wave velocity for phase 2 [m/s].
|
|
34
|
+
vs2 : np.ndarray
|
|
35
|
+
Shear wave velocity for phase 2 [m/s].
|
|
36
|
+
rho2 : np.ndarray
|
|
37
|
+
Density for phase 2 [kg/m^3].
|
|
38
|
+
f1 : np.ndarray
|
|
39
|
+
Fraction of phase 1.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
tuple
|
|
44
|
+
vpv, vsv, vph, vsh, rho : np.ndarray
|
|
45
|
+
vpv: vertical pressure velocity, vsv: vertical shear velocity, vph: horizontal pressure velocity,
|
|
46
|
+
vsh: horizontal shear velocity, rho: density.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
a = (
|
|
50
|
+
4 * f1 * rho1 * vs1**2 * (1 - vs1**2 / vp1**2)
|
|
51
|
+
+ 4 * (1 - f1) * rho2 * vs2**2 * (1 - (vs2 / vp2) ** 2)
|
|
52
|
+
+ (f1 * (1 - 2 * (vs1 / vp1) ** 2) + (1 - f1) * (1 - 2 * (vs2 / vp2) ** 2)) ** 2
|
|
53
|
+
* (1 / (f1 / (rho1 * vp1**2) + (1 - f1) / (rho2 * vp2**2)))
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
c = 1 / (f1 / (rho1 * vp1**2) + (1 - f1) / (rho2 * vp2**2))
|
|
57
|
+
d = 1 / (f1 / (rho1 * vs1**2) + (1 - f1) / (rho2 * vs2**2))
|
|
58
|
+
|
|
59
|
+
m = f1 * rho1 * vs1**2 + (1 - f1) * rho2 * vs2**2
|
|
60
|
+
|
|
61
|
+
rho = f1 * rho1 + (1 - f1) * rho2
|
|
62
|
+
|
|
63
|
+
vpv = np.sqrt(c / rho)
|
|
64
|
+
vsv = np.sqrt(d / rho)
|
|
65
|
+
vph = np.sqrt(a / rho)
|
|
66
|
+
vsh = np.sqrt(m / rho)
|
|
67
|
+
|
|
68
|
+
return vpv, vsv, vph, vsh, rho
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def dvorkin_contact_cement(
|
|
6
|
+
frac_cem: npt.NDArray[np.float64],
|
|
7
|
+
por0_sst: npt.NDArray[np.float64],
|
|
8
|
+
mu0_sst: npt.NDArray[np.float64],
|
|
9
|
+
k0_sst: npt.NDArray[np.float64],
|
|
10
|
+
mu0_cem: npt.NDArray[np.float64],
|
|
11
|
+
k0_cem: npt.NDArray[np.float64],
|
|
12
|
+
vs_red: npt.NDArray[np.float64],
|
|
13
|
+
c: float,
|
|
14
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
|
15
|
+
"""
|
|
16
|
+
Dvorkin-Nur contact cement model for estimation of elastic moduli.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
frac_cem : numpy.ndarray
|
|
21
|
+
Cement fraction of volume [ratio].
|
|
22
|
+
por0_sst : numpy.ndarray
|
|
23
|
+
Critical porosity of sand [ratio].
|
|
24
|
+
mu0_sst : numpy.ndarray
|
|
25
|
+
Mineral shear modulus of sand [Pa].
|
|
26
|
+
k0_sst : numpy.ndarray
|
|
27
|
+
Mineral bulk modulus of sand [Pa].
|
|
28
|
+
mu0_cem : numpy.ndarray
|
|
29
|
+
Mineral shear modulus of cement [Pa].
|
|
30
|
+
k0_cem : numpy.ndarray
|
|
31
|
+
Mineral bulk modulus of cement [Pa].
|
|
32
|
+
vs_red : numpy.ndarray
|
|
33
|
+
Shear modulus reduction factor [ratio].
|
|
34
|
+
c : float
|
|
35
|
+
Coordination number (grain contacts per grain) [unitless].
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
tuple
|
|
40
|
+
k_cc, mu_cc : numpy.ndarray.
|
|
41
|
+
k_cc: bulk modulus [Pa], mu_cc: shear modulus [Pa].
|
|
42
|
+
"""
|
|
43
|
+
alpha = (2 * frac_cem / (3 * (1 - por0_sst))) ** 0.5
|
|
44
|
+
poiss = (3 * k0_sst - 2 * mu0_sst) / (2 * (3 * k0_sst + mu0_sst))
|
|
45
|
+
poiss_c = (3 * k0_cem - 2 * mu0_cem) / (2 * (3 * k0_cem + mu0_cem))
|
|
46
|
+
a_an = (2 * mu0_cem / (np.pi * mu0_sst)) * (
|
|
47
|
+
(1 - poiss) * (1 - poiss_c) / (1 - 2 * poiss_c)
|
|
48
|
+
)
|
|
49
|
+
a_at = mu0_cem / (np.pi * mu0_sst)
|
|
50
|
+
|
|
51
|
+
a_t = (
|
|
52
|
+
-1e-2
|
|
53
|
+
* (2.26 * poiss**2 + 2.07 * poiss + 2.3)
|
|
54
|
+
* a_at ** (0.079 * poiss**2 + 0.1754 * poiss - 1.342)
|
|
55
|
+
)
|
|
56
|
+
b_t = (0.0573 * poiss**2 + 0.0937 * poiss + 0.202) * a_at ** (
|
|
57
|
+
0.0274 * poiss**2 + 0.0529 * poiss - 0.8765
|
|
58
|
+
)
|
|
59
|
+
c_t = (
|
|
60
|
+
1e-4
|
|
61
|
+
* (9.654 * poiss**2 + 4.945 * poiss + 3.1)
|
|
62
|
+
* a_at ** (0.01867 * poiss**2 + 0.4011 * poiss - 1.8186)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
s_t = a_t * alpha**2 + b_t * alpha + c_t
|
|
66
|
+
|
|
67
|
+
c_n = 0.00024649 * a_an ** (-1.9864)
|
|
68
|
+
b_n = 0.20405 * a_an ** (-0.89008)
|
|
69
|
+
a_n = -0.024153 * a_an ** (-1.3646)
|
|
70
|
+
|
|
71
|
+
s_n = a_n * alpha**2 + b_n * alpha + c_n
|
|
72
|
+
|
|
73
|
+
m0_cem = k0_cem + 4 / 3 * mu0_cem
|
|
74
|
+
k_cc = (1 / 6) * c * (1 - por0_sst) * m0_cem * s_n
|
|
75
|
+
mu_cc = (3 / 5) * k_cc + vs_red * (3 / 20) * c * (1 - por0_sst) * mu0_cem * s_t
|
|
76
|
+
|
|
77
|
+
return k_cc, mu_cc
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from typing import cast
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import numpy.typing as npt
|
|
6
|
+
|
|
7
|
+
from rock_physics_open.equinor_utilities.gen_utilities import dim_check_vector
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def gassmann(
|
|
11
|
+
k_dry: npt.NDArray[np.float64],
|
|
12
|
+
por: npt.NDArray[np.float64],
|
|
13
|
+
k_fl: npt.NDArray[np.float64],
|
|
14
|
+
k_min: npt.NDArray[np.float64],
|
|
15
|
+
) -> npt.NDArray[np.float64]:
|
|
16
|
+
"""
|
|
17
|
+
Fluid substitution according to the Gassmann equation.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
k_dry : np.ndarray
|
|
22
|
+
Dry rock bulk modulus [Pa].
|
|
23
|
+
por : np.ndarray
|
|
24
|
+
Porosity [fraction].
|
|
25
|
+
k_fl : np.ndarray
|
|
26
|
+
Fluid bulk modulus.
|
|
27
|
+
k_min : np.ndarray
|
|
28
|
+
Mineral bulk modulus [Pa].
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
np.ndarray
|
|
33
|
+
k_sat: bulk modulus for saturated rock [Pa]
|
|
34
|
+
"""
|
|
35
|
+
k_dry, por, k_fl, k_min = cast(
|
|
36
|
+
list[npt.NDArray[np.float64]],
|
|
37
|
+
dim_check_vector((k_dry, por, k_fl, k_min)),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
idx = np.logical_or(k_dry == k_min, por == 0)
|
|
41
|
+
k_sat = np.ones(k_dry.shape) * np.nan
|
|
42
|
+
b = k_dry[~idx] / (k_min[~idx] - k_dry[~idx]) + k_fl[~idx] / (
|
|
43
|
+
(k_min[~idx] - k_fl[~idx]) * por[~idx]
|
|
44
|
+
)
|
|
45
|
+
idx1 = b < 0
|
|
46
|
+
if any(idx1):
|
|
47
|
+
b[idx1] = np.nan
|
|
48
|
+
|
|
49
|
+
k_sat[~idx] = b / (1 + b) * k_min[~idx]
|
|
50
|
+
k_sat[idx] = k_min[idx]
|
|
51
|
+
|
|
52
|
+
return k_sat
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def gassmann2(
|
|
56
|
+
k_sat_1: npt.NDArray[np.float64],
|
|
57
|
+
k_fl_1: npt.NDArray[np.float64],
|
|
58
|
+
k_fl_2: npt.NDArray[np.float64],
|
|
59
|
+
por: npt.NDArray[np.float64],
|
|
60
|
+
k_min: npt.NDArray[np.float64],
|
|
61
|
+
) -> npt.NDArray[np.float64]:
|
|
62
|
+
"""
|
|
63
|
+
Fluid substitution by Gassmann method with substitution of one fluid to another
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
k_sat_1 : np.ndarray
|
|
68
|
+
bulk modulus for saturated rock with original fluid [Pa]
|
|
69
|
+
k_fl_1 : np.ndarray
|
|
70
|
+
bulk modulus for original fluid [Pa]
|
|
71
|
+
k_fl_2 : np.ndarray
|
|
72
|
+
bulk modulus for replaced fluid [Pa]
|
|
73
|
+
por : np.ndarray
|
|
74
|
+
porosity of rock [fraction]
|
|
75
|
+
k_min : np.ndarray
|
|
76
|
+
mineral bulk modulus of rock [Pa]
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
np.ndarray
|
|
81
|
+
k_sat_2: bulk modulus of rock saturated with replaced fluid [Pa]
|
|
82
|
+
"""
|
|
83
|
+
k_sat_1, k_fl_1, k_fl_2, por, k_min = cast(
|
|
84
|
+
list[npt.NDArray[np.float64]],
|
|
85
|
+
dim_check_vector((k_sat_1, k_fl_1, k_fl_2, por, k_min)),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
idx = np.any(
|
|
89
|
+
np.array([k_sat_1 == k_min, por == 0, k_fl_1 == k_min, k_fl_2 == k_min]), axis=0
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
k_sat_2 = np.ones(k_sat_1.shape) * np.nan
|
|
93
|
+
|
|
94
|
+
b = (
|
|
95
|
+
k_fl_2[~idx] / (por[~idx] * (k_min[~idx] - k_fl_2[~idx]))
|
|
96
|
+
- k_fl_1[~idx] / (por[~idx] * (k_min[~idx] - k_fl_1[~idx]))
|
|
97
|
+
+ k_sat_1[~idx] / (k_min[~idx] - k_sat_1[~idx])
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
idx1 = b < 0
|
|
101
|
+
if any(idx1):
|
|
102
|
+
warn_str = (
|
|
103
|
+
"{0:d} unstable solution(s) to Gassmann equation, changed to NaN".format(
|
|
104
|
+
np.sum(idx1)
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
warnings.warn(warn_str, UserWarning)
|
|
108
|
+
b[idx1] = np.nan
|
|
109
|
+
|
|
110
|
+
k_sat_2[~idx] = b / (1 + b) * k_min[~idx]
|
|
111
|
+
k_sat_2[idx] = k_sat_1[idx]
|
|
112
|
+
|
|
113
|
+
return k_sat_2
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def gassmann_dry(
|
|
117
|
+
k_sat: npt.NDArray[np.float64],
|
|
118
|
+
por: npt.NDArray[np.float64],
|
|
119
|
+
k_fl: npt.NDArray[np.float64],
|
|
120
|
+
k_min: npt.NDArray[np.float64],
|
|
121
|
+
) -> npt.NDArray[np.float64]:
|
|
122
|
+
"""
|
|
123
|
+
Dry rock properties of saturated rock by Gassmann equation
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
k_sat : np.ndarray
|
|
128
|
+
saturated rock bulk modulus [Pa]
|
|
129
|
+
por : np.ndarray
|
|
130
|
+
porosity of rock [fraction]
|
|
131
|
+
k_fl : np.ndarray
|
|
132
|
+
bulk modulus of fluid [Pa]
|
|
133
|
+
k_min : np.ndarray
|
|
134
|
+
bulk modulus of mineral [Pa]
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
np.ndarray
|
|
139
|
+
k_dry: dry rock bulk modulus [Pa]
|
|
140
|
+
"""
|
|
141
|
+
k_sat, por, k_fl, k_min = cast(
|
|
142
|
+
list[npt.NDArray[np.float64]],
|
|
143
|
+
dim_check_vector((k_sat, por, k_fl, k_min)),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
idx = np.any(np.array([k_sat == k_min, por == 0, k_fl == k_min]), axis=0)
|
|
147
|
+
k_dry = np.ones(k_sat.shape)
|
|
148
|
+
b = k_sat[~idx] / (k_min[~idx] - k_sat[~idx]) - k_fl[~idx] / (
|
|
149
|
+
(k_min[~idx] - k_fl[~idx]) * por[~idx]
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
idx1 = b < 0
|
|
153
|
+
if any(idx1):
|
|
154
|
+
warn_str = (
|
|
155
|
+
"{0:d} unstable solution(s) to Gassmann equation, changed to NaN".format(
|
|
156
|
+
np.sum(idx1)
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
warnings.warn(warn_str, UserWarning)
|
|
160
|
+
b[idx1] = np.nan
|
|
161
|
+
|
|
162
|
+
k_dry[~idx] = b / (1 + b) * k_min[~idx]
|
|
163
|
+
k_dry[idx] = k_min[idx]
|
|
164
|
+
|
|
165
|
+
return k_dry
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
from typing import Literal, cast
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import numpy.typing as npt
|
|
5
|
+
|
|
6
|
+
from rock_physics_open.equinor_utilities.gen_utilities import dim_check_vector
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def hashin_shtrikman(
|
|
10
|
+
k1: npt.NDArray[np.float64],
|
|
11
|
+
mu1: npt.NDArray[np.float64],
|
|
12
|
+
k2: npt.NDArray[np.float64],
|
|
13
|
+
mu2: npt.NDArray[np.float64],
|
|
14
|
+
f: npt.NDArray[np.float64],
|
|
15
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
|
16
|
+
"""
|
|
17
|
+
Hashin-Sktrikman upper or lower according to ordering of phases.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
k1 : np.ndarray
|
|
22
|
+
Bulk modulus of phase 1 [Pa].
|
|
23
|
+
mu1 : np.ndarray
|
|
24
|
+
Shear modulus of phase 1 [Pa].
|
|
25
|
+
k2 : np.ndarray
|
|
26
|
+
Bulk modulus of phase 2 [Pa].
|
|
27
|
+
mu2 : np.ndarray
|
|
28
|
+
Shear modulus of phase 2 [Pa].
|
|
29
|
+
f : np.ndarray
|
|
30
|
+
Fraction of phase 1 [fraction].
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
tuple
|
|
35
|
+
k, mu : np.ndarray.
|
|
36
|
+
k: effective bulk modulus [Pa], mu: effective shear modulus [Pa].
|
|
37
|
+
"""
|
|
38
|
+
k = k1 + (1 - f) * (k2 - k1) / (1 + (k2 - k1) * f * (k1 + 4 / 3 * mu1) ** -1)
|
|
39
|
+
mu = mu1 + (1 - f) * (mu2 - mu1) / (
|
|
40
|
+
1 + 2 * (mu2 - mu1) * f * (k1 + 2 * mu1) / (5 * mu1 * (k1 + 4 / 3 * mu1))
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
return k, mu
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def hashin_shtrikman_average(
|
|
47
|
+
k1: npt.NDArray[np.float64],
|
|
48
|
+
mu1: npt.NDArray[np.float64],
|
|
49
|
+
k2: npt.NDArray[np.float64],
|
|
50
|
+
mu2: npt.NDArray[np.float64],
|
|
51
|
+
f: npt.NDArray[np.float64],
|
|
52
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
|
53
|
+
"""
|
|
54
|
+
Average of Hashin-Shtrikman upper and lower bound.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
k1 : np.ndarray
|
|
59
|
+
Bulk modulus of phase 1 [Pa].
|
|
60
|
+
mu1 : np.ndarray
|
|
61
|
+
Shear modulus of phase 1 [Pa].
|
|
62
|
+
k2 : np.ndarray
|
|
63
|
+
Bulk modulus of phase 2 [Pa].
|
|
64
|
+
mu2 : np.ndarray
|
|
65
|
+
Shear modulus of phase 2 [Pa].
|
|
66
|
+
f : np.ndarray
|
|
67
|
+
Fraction of phase 1 [fraction].
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
tuple
|
|
72
|
+
k_av, mu_av : np.ndarray.
|
|
73
|
+
k_av: effective bulk modulus [Pa], mu_av: effective shear modulus [Pa]
|
|
74
|
+
"""
|
|
75
|
+
k_hs1, mu_hs1 = hashin_shtrikman(k1, mu1, k2, mu2, f)
|
|
76
|
+
k_hs2, mu_hs2 = hashin_shtrikman(k2, mu2, k1, mu1, 1 - f)
|
|
77
|
+
|
|
78
|
+
k_av = (k_hs1 + k_hs2) / 2
|
|
79
|
+
mu_av = (mu_hs1 + mu_hs2) / 2
|
|
80
|
+
|
|
81
|
+
return k_av, mu_av
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def hashin_shtrikman_walpole(
|
|
85
|
+
k1: npt.NDArray[np.float64],
|
|
86
|
+
mu1: npt.NDArray[np.float64],
|
|
87
|
+
k2: npt.NDArray[np.float64],
|
|
88
|
+
mu2: npt.NDArray[np.float64],
|
|
89
|
+
f1: npt.NDArray[np.float64],
|
|
90
|
+
bound: Literal["upper", "lower"] = "lower",
|
|
91
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
|
92
|
+
"""
|
|
93
|
+
Hashin-Shtrikman upper bound is obtained when the stiffest material is
|
|
94
|
+
termed 1 and vice versa for lower bound. Tricky in cases like Quartz -
|
|
95
|
+
Calcite where the K and Mu have opposed values. HS - Walpole is
|
|
96
|
+
generalised to regard highest and lowest values in each case. The default
|
|
97
|
+
is to generate lower bound.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
k1 : np.ndarray
|
|
102
|
+
Bulk modulus of phase 1 [Pa].
|
|
103
|
+
mu1 : np.ndarray
|
|
104
|
+
Shear modulus of phase 1 [Pa].
|
|
105
|
+
k2 : np.ndarray
|
|
106
|
+
Bulk modulus of phase 2 [Pa].
|
|
107
|
+
mu2 : np.ndarray
|
|
108
|
+
Shear modulus of phase 2 [Pa].
|
|
109
|
+
f1 : np.ndarray or float
|
|
110
|
+
Fraction of phase 1 [fraction].
|
|
111
|
+
bound: str
|
|
112
|
+
'upper' or 'lower' selection of upper of lower bound of effective medium.
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
tuple
|
|
116
|
+
k, mu : np.ndarray.
|
|
117
|
+
k: effective bulk modulus [Pa], mu: effective shear modulus [Pa].
|
|
118
|
+
"""
|
|
119
|
+
k1, mu1, k2, mu2, f1 = cast(
|
|
120
|
+
list[npt.NDArray[np.float64]],
|
|
121
|
+
dim_check_vector((k1, mu1, k2, mu2, f1)),
|
|
122
|
+
)
|
|
123
|
+
if bound.lower() not in ["lower", "upper"]:
|
|
124
|
+
raise ValueError(f'{__file__}: bound must be one of "lower" or "upper"')
|
|
125
|
+
|
|
126
|
+
idx_k = k1 == k2
|
|
127
|
+
idx_mu = mu1 == mu2
|
|
128
|
+
f2 = 1 - f1
|
|
129
|
+
|
|
130
|
+
if bound.lower() == "lower":
|
|
131
|
+
k_m = np.minimum(k1, k2)
|
|
132
|
+
mu_m = np.minimum(mu1, mu2)
|
|
133
|
+
else:
|
|
134
|
+
k_m = np.maximum(k1, k2)
|
|
135
|
+
mu_m = np.maximum(mu1, mu2)
|
|
136
|
+
|
|
137
|
+
k = np.zeros(k1.shape)
|
|
138
|
+
mu = np.zeros(k1.shape)
|
|
139
|
+
|
|
140
|
+
if np.any(idx_k):
|
|
141
|
+
k[idx_k] = k1[idx_k]
|
|
142
|
+
if np.any(~idx_k):
|
|
143
|
+
k[~idx_k] = k1[~idx_k] + f2[~idx_k] / (
|
|
144
|
+
(k2[~idx_k] - k1[~idx_k]) ** -1
|
|
145
|
+
+ f1[~idx_k] * (k1[~idx_k] + 4 / 3 * mu_m[~idx_k]) ** -1
|
|
146
|
+
)
|
|
147
|
+
if np.any(idx_mu):
|
|
148
|
+
mu[idx_mu] = mu1[idx_mu]
|
|
149
|
+
if np.any(~idx_mu):
|
|
150
|
+
mu[~idx_mu] = mu1[~idx_mu] + f2[~idx_mu] / (
|
|
151
|
+
(mu2[~idx_mu] - mu1[~idx_mu]) ** -1
|
|
152
|
+
+ f1[~idx_mu]
|
|
153
|
+
* (
|
|
154
|
+
mu1[~idx_mu]
|
|
155
|
+
+ mu_m[~idx_mu]
|
|
156
|
+
/ 6
|
|
157
|
+
* (9 * k_m[~idx_mu] + 8 * mu_m[~idx_mu])
|
|
158
|
+
/ (k_m[~idx_mu] + 2 * mu_m[~idx_mu])
|
|
159
|
+
)
|
|
160
|
+
** -1
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return k, mu
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def multi_hashin_shtrikman(
|
|
167
|
+
*coeffs: npt.NDArray[np.float64],
|
|
168
|
+
mode: Literal["average", "upper", "lower"] = "average",
|
|
169
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
|
170
|
+
"""
|
|
171
|
+
Hashin-Shtrikman effective medium calculation for multi-mineral case.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
coeffs : np.ndarray
|
|
176
|
+
Triplets of vectors with k (bulk modulus [Pa]), mu (shear modulus [Pa]) and fraction for each mineral.
|
|
177
|
+
mode : str
|
|
178
|
+
'average', 'upper' or 'lower'.
|
|
179
|
+
|
|
180
|
+
Returns
|
|
181
|
+
-------
|
|
182
|
+
tuple
|
|
183
|
+
k_hs, mu_hs : np.ndarray.
|
|
184
|
+
k_hs, mu_hs - bulk modulus and shear modulus for effective medium [Pa].
|
|
185
|
+
"""
|
|
186
|
+
if not len(coeffs) % 3 == 0:
|
|
187
|
+
raise ValueError(
|
|
188
|
+
"multi_hashin_shtrikman: inputs not vectors of k, mu and fraction for each mineral"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
k_arr = np.array(coeffs[::3])
|
|
192
|
+
mu_arr = np.array(coeffs[1::3])
|
|
193
|
+
f = np.array(coeffs[2::3])
|
|
194
|
+
if not np.all(
|
|
195
|
+
cast(npt.NDArray[np.float64], np.around(np.sum(f, axis=0), decimals=6)) == 1.0
|
|
196
|
+
):
|
|
197
|
+
raise ValueError("multi_hashin_shtrikman: all fractions do not add up to 1.0")
|
|
198
|
+
|
|
199
|
+
if mode.lower() not in ["average", "upper", "lower"]:
|
|
200
|
+
raise ValueError(
|
|
201
|
+
'multi_hashin_shtrikman: mode is not one of "average", "upper" or "lower"'
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
k_min = np.min(k_arr, axis=0)
|
|
205
|
+
k_max = np.max(k_arr, axis=0)
|
|
206
|
+
mu_min = np.min(mu_arr, axis=0)
|
|
207
|
+
mu_max = np.max(mu_arr, axis=0)
|
|
208
|
+
|
|
209
|
+
k_hs_upper = np.sum(f / (k_arr + 4 / 3 * mu_max), axis=0) ** -1 - 4 / 3 * mu_max
|
|
210
|
+
k_hs_lower = np.sum(f / (k_arr + 4 / 3 * mu_min), axis=0) ** -1 - 4 / 3 * mu_min
|
|
211
|
+
|
|
212
|
+
zeta_max = mu_max / 6 * (9 * k_max + 8 * mu_max) / (k_max + 2 * mu_max)
|
|
213
|
+
zeta_min = mu_min / 6 * (9 * k_min + 8 * mu_min) / (k_min + 2 * mu_min)
|
|
214
|
+
|
|
215
|
+
mu_hs_upper = np.sum(f / (mu_arr + zeta_max), axis=0) ** -1 - zeta_max
|
|
216
|
+
mu_hs_lower = np.sum(f / (mu_arr + zeta_min), axis=0) ** -1 - zeta_min
|
|
217
|
+
|
|
218
|
+
if mode == "lower":
|
|
219
|
+
return k_hs_lower, mu_hs_lower
|
|
220
|
+
if mode == "upper":
|
|
221
|
+
return k_hs_upper, mu_hs_upper
|
|
222
|
+
k_hs = 0.5 * (k_hs_upper + k_hs_lower)
|
|
223
|
+
mu_hs = 0.5 * (mu_hs_upper + mu_hs_lower)
|
|
224
|
+
return k_hs, mu_hs
|