rock-physics-open 0.0__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.

Potentially problematic release.


This version of rock-physics-open might be problematic. Click here for more details.

Files changed (142) hide show
  1. rock_physics_open/__init__.py +0 -0
  2. rock_physics_open/equinor_utilities/__init__.py +0 -0
  3. rock_physics_open/equinor_utilities/anisotropy.py +162 -0
  4. rock_physics_open/equinor_utilities/classification_functions/__init__.py +17 -0
  5. rock_physics_open/equinor_utilities/classification_functions/class_stats.py +58 -0
  6. rock_physics_open/equinor_utilities/classification_functions/lin_class.py +47 -0
  7. rock_physics_open/equinor_utilities/classification_functions/mahal_class.py +56 -0
  8. rock_physics_open/equinor_utilities/classification_functions/norm_class.py +65 -0
  9. rock_physics_open/equinor_utilities/classification_functions/poly_class.py +40 -0
  10. rock_physics_open/equinor_utilities/classification_functions/post_prob.py +26 -0
  11. rock_physics_open/equinor_utilities/classification_functions/two_step_classification.py +46 -0
  12. rock_physics_open/equinor_utilities/conversions.py +10 -0
  13. rock_physics_open/equinor_utilities/gen_utilities/__init__.py +11 -0
  14. rock_physics_open/equinor_utilities/gen_utilities/dict_to_float.py +33 -0
  15. rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +83 -0
  16. rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +126 -0
  17. rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +78 -0
  18. rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +14 -0
  19. rock_physics_open/equinor_utilities/machine_learning_utilities/dummy_vars.py +42 -0
  20. rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +119 -0
  21. rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +61 -0
  22. rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +151 -0
  23. rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +188 -0
  24. rock_physics_open/equinor_utilities/snapshot_test_utilities/__init__.py +10 -0
  25. rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +145 -0
  26. rock_physics_open/equinor_utilities/snapshot_test_utilities/snapshots.py +54 -0
  27. rock_physics_open/equinor_utilities/std_functions/__init__.py +43 -0
  28. rock_physics_open/equinor_utilities/std_functions/backus_ave.py +53 -0
  29. rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +69 -0
  30. rock_physics_open/equinor_utilities/std_functions/gassmann.py +140 -0
  31. rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +195 -0
  32. rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +43 -0
  33. rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +51 -0
  34. rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +98 -0
  35. rock_physics_open/equinor_utilities/std_functions/rho.py +59 -0
  36. rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +128 -0
  37. rock_physics_open/equinor_utilities/std_functions/walton.py +38 -0
  38. rock_physics_open/equinor_utilities/std_functions/wood_brie.py +77 -0
  39. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.gif +0 -0
  40. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.ico +0 -0
  41. rock_physics_open/equinor_utilities/various_utilities/__init__.py +24 -0
  42. rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +83 -0
  43. rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +37 -0
  44. rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +37 -0
  45. rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +53 -0
  46. rock_physics_open/equinor_utilities/various_utilities/hs_average.py +40 -0
  47. rock_physics_open/equinor_utilities/various_utilities/pressure.py +88 -0
  48. rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +85 -0
  49. rock_physics_open/equinor_utilities/various_utilities/timeshift.py +91 -0
  50. rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +154 -0
  51. rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +61 -0
  52. rock_physics_open/fluid_models/__init__.py +9 -0
  53. rock_physics_open/fluid_models/brine_model/__init__.py +5 -0
  54. rock_physics_open/fluid_models/brine_model/brine_properties.py +143 -0
  55. rock_physics_open/fluid_models/gas_model/__init__.py +5 -0
  56. rock_physics_open/fluid_models/gas_model/gas_properties.py +277 -0
  57. rock_physics_open/fluid_models/oil_model/__init__.py +5 -0
  58. rock_physics_open/fluid_models/oil_model/dead_oil_density.py +60 -0
  59. rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +28 -0
  60. rock_physics_open/fluid_models/oil_model/live_oil_density.py +79 -0
  61. rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +24 -0
  62. rock_physics_open/fluid_models/oil_model/oil_bubble_point.py +69 -0
  63. rock_physics_open/fluid_models/oil_model/oil_properties.py +114 -0
  64. rock_physics_open/sandstone_models/__init__.py +57 -0
  65. rock_physics_open/sandstone_models/cemented_shalysand_sandyshale_models.py +304 -0
  66. rock_physics_open/sandstone_models/constant_cement_models.py +204 -0
  67. rock_physics_open/sandstone_models/constant_cement_optimisation.py +122 -0
  68. rock_physics_open/sandstone_models/contact_cement_model.py +138 -0
  69. rock_physics_open/sandstone_models/curvefit_sandstone_models.py +143 -0
  70. rock_physics_open/sandstone_models/friable_models.py +178 -0
  71. rock_physics_open/sandstone_models/friable_optimisation.py +112 -0
  72. rock_physics_open/sandstone_models/friable_shalysand_sandyshale_models.py +235 -0
  73. rock_physics_open/sandstone_models/patchy_cement_fluid_substitution_model.py +477 -0
  74. rock_physics_open/sandstone_models/patchy_cement_model.py +286 -0
  75. rock_physics_open/sandstone_models/patchy_cement_optimisation.py +251 -0
  76. rock_physics_open/sandstone_models/unresolved_cemented_sandshale_models.py +134 -0
  77. rock_physics_open/sandstone_models/unresolved_friable_sandshale_models.py +126 -0
  78. rock_physics_open/shale_models/__init__.py +19 -0
  79. rock_physics_open/shale_models/dem.py +174 -0
  80. rock_physics_open/shale_models/dem_dual_por.py +61 -0
  81. rock_physics_open/shale_models/kus_tok.py +59 -0
  82. rock_physics_open/shale_models/multi_sca.py +133 -0
  83. rock_physics_open/shale_models/pq.py +102 -0
  84. rock_physics_open/shale_models/sca.py +90 -0
  85. rock_physics_open/shale_models/shale4_mineral.py +147 -0
  86. rock_physics_open/shale_models/shale4_mineral_dem_overlay.py +92 -0
  87. rock_physics_open/span_wagner/__init__.py +5 -0
  88. rock_physics_open/span_wagner/co2_properties.py +438 -0
  89. rock_physics_open/span_wagner/coefficients.py +165 -0
  90. rock_physics_open/span_wagner/equations.py +104 -0
  91. rock_physics_open/span_wagner/tables/__init__.py +0 -0
  92. rock_physics_open/span_wagner/tables/carbon_dioxide_density.npz +0 -0
  93. rock_physics_open/span_wagner/tables/lookup_table.py +33 -0
  94. rock_physics_open/t_matrix_models/Equinor_logo.ico +0 -0
  95. rock_physics_open/t_matrix_models/__init__.py +45 -0
  96. rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +124 -0
  97. rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +124 -0
  98. rock_physics_open/t_matrix_models/curvefit_t_matrix_min.py +86 -0
  99. rock_physics_open/t_matrix_models/opt_subst_utilities.py +415 -0
  100. rock_physics_open/t_matrix_models/parse_t_matrix_inputs.py +297 -0
  101. rock_physics_open/t_matrix_models/run_t_matrix.py +243 -0
  102. rock_physics_open/t_matrix_models/t_matrix_C.py +210 -0
  103. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +137 -0
  104. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +163 -0
  105. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +72 -0
  106. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +86 -0
  107. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +172 -0
  108. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +159 -0
  109. rock_physics_open/t_matrix_models/t_matrix_vector/__init__.py +12 -0
  110. rock_physics_open/t_matrix_models/t_matrix_vector/array_functions.py +75 -0
  111. rock_physics_open/t_matrix_models/t_matrix_vector/calc_c_eff.py +163 -0
  112. rock_physics_open/t_matrix_models/t_matrix_vector/calc_isolated.py +95 -0
  113. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd.py +40 -0
  114. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_eff.py +116 -0
  115. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_uuv.py +18 -0
  116. rock_physics_open/t_matrix_models/t_matrix_vector/calc_pressure.py +140 -0
  117. rock_physics_open/t_matrix_models/t_matrix_vector/calc_t.py +71 -0
  118. rock_physics_open/t_matrix_models/t_matrix_vector/calc_td.py +42 -0
  119. rock_physics_open/t_matrix_models/t_matrix_vector/calc_theta.py +43 -0
  120. rock_physics_open/t_matrix_models/t_matrix_vector/calc_x.py +33 -0
  121. rock_physics_open/t_matrix_models/t_matrix_vector/calc_z.py +50 -0
  122. rock_physics_open/t_matrix_models/t_matrix_vector/check_and_tile.py +43 -0
  123. rock_physics_open/t_matrix_models/t_matrix_vector/g_tensor.py +140 -0
  124. rock_physics_open/t_matrix_models/t_matrix_vector/iso_av.py +60 -0
  125. rock_physics_open/t_matrix_models/t_matrix_vector/iso_ave_all.py +55 -0
  126. rock_physics_open/t_matrix_models/t_matrix_vector/pressure_input.py +44 -0
  127. rock_physics_open/t_matrix_models/t_matrix_vector/t_matrix_vec.py +278 -0
  128. rock_physics_open/t_matrix_models/t_matrix_vector/velocity_vti_angles.py +81 -0
  129. rock_physics_open/t_matrix_models/tmatrix_python.dll +0 -0
  130. rock_physics_open/t_matrix_models/tmatrix_python.so +0 -0
  131. rock_physics_open/ternary_plots/__init__.py +3 -0
  132. rock_physics_open/ternary_plots/gen_ternary_plot.py +73 -0
  133. rock_physics_open/ternary_plots/shale_prop_ternary.py +337 -0
  134. rock_physics_open/ternary_plots/ternary_patches.py +277 -0
  135. rock_physics_open/ternary_plots/ternary_plot_utilities.py +197 -0
  136. rock_physics_open/ternary_plots/unconventionals_ternary.py +75 -0
  137. rock_physics_open/version.py +21 -0
  138. rock_physics_open-0.0.dist-info/METADATA +92 -0
  139. rock_physics_open-0.0.dist-info/RECORD +142 -0
  140. rock_physics_open-0.0.dist-info/WHEEL +5 -0
  141. rock_physics_open-0.0.dist-info/licenses/LICENSE +165 -0
  142. rock_physics_open-0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,126 @@
1
+ from sys import byteorder
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ WRONG_BYTEORDER = ">" if byteorder == "little" else "<"
7
+
8
+
9
+ def filter_input_log(
10
+ args, working_int=None, negative=False, no_zero=False, positive=True
11
+ ):
12
+ """
13
+ Check for valid input values in numpy arrays or pandas data frames. Default behaviour is to
14
+ identify missing values - assumed to be NaN and Inf. Other conditions
15
+ can be stated in the key word arguments. Unknown conditions are ignored and a warning
16
+ is issued. Run dim_check_vector to make sure that all inputs have the same length.
17
+ Erroneous values in a sample in one log will remove the sample from all the logs.
18
+ All inputs must have the same array length (data frames the same number of indices).
19
+
20
+ Parameters
21
+ ----------
22
+ args : list or tuple or np.ndarray or pd.DataFrame
23
+ Inputs to be filtered, single array or dataframe or lists of arrays or data frames.
24
+ working_int : np.ndarray
25
+ Valid positions are shown as values > 0.
26
+ negative : bool
27
+ Positive values are excluded (zero values are retained).
28
+ no_zero : bool
29
+ Zero values are excluded.
30
+ positive : bool
31
+ Negative values are excluded.
32
+
33
+ Returns
34
+ -------
35
+ tuple
36
+ idx, output_args : (np.ndarray, list)
37
+ indices of valid values [bool],
38
+ list of input arrays at valid indices.
39
+ """
40
+ type_error = "filter_input_log: unknown input data type: {}".format(type(args))
41
+ size_error = "filter_input_log: inputs of different length"
42
+
43
+ if not isinstance(args, (list, tuple, np.ndarray, pd.DataFrame)):
44
+ raise ValueError(type_error)
45
+
46
+ # Make sure that 'args' is iterable
47
+ if isinstance(args, (np.ndarray, pd.DataFrame)):
48
+ args = [args]
49
+
50
+ # Input tuple
51
+ if isinstance(args, tuple):
52
+ args = list(args)
53
+
54
+ # Need to preserve original inputs
55
+ input_args = args.copy()
56
+
57
+ # Test that inputs are of the right types and the same length
58
+ if not np.all([isinstance(log, (np.ndarray, pd.DataFrame)) for log in args]):
59
+ raise ValueError(type_error)
60
+ if not np.all([log.shape[0] == args[0].shape[0] for log in args]):
61
+ raise ValueError(size_error)
62
+
63
+ # Generate pandas series from numpy arrays
64
+ args = [pd.Series(log) if isinstance(log, np.ndarray) else log for log in args]
65
+ # Merge into a data frame
66
+ logs = pd.concat(args, axis=1)
67
+
68
+ # If any of the input logs are of type boolean, False means that they should not be included,
69
+ # regardless of filter flags
70
+ # https://github.com/pandas-dev/pandas/issues/32432
71
+ # idx = ~logs.any(bool_only=True, axis=1)
72
+ # Need to do it the cumbersome way for the time being
73
+ bool_col = logs.dtypes.apply(lambda dtype: dtype == "bool")
74
+ if any(bool_col):
75
+ idx = ~logs.loc[:, logs.columns[bool_col]].any(axis=1)
76
+ logs.drop(columns=logs.columns[bool_col], inplace=True)
77
+ else:
78
+ idx = pd.Series(index=logs.index, data=np.zeros_like(logs.index).astype(bool))
79
+
80
+ # Standard checks: NaN and Inf
81
+ idx = np.logical_or(idx, logs.isna().any(axis=1))
82
+ idx = np.logical_or(idx, logs.isin([np.inf, -np.inf]).any(axis=1))
83
+
84
+ # Remove columns with dtype that is not numeric
85
+ obj_col = [dd.kind not in ["i", "u", "f", "c"] for dd in logs.dtypes]
86
+ logs.drop(columns=logs.columns[obj_col], inplace=True)
87
+
88
+ # Checks according to the input options input_dict
89
+ # Only consider working interval if it is included or set to some value
90
+ if working_int is not None and not np.all(working_int == 0):
91
+ idx = np.logical_or(idx, working_int == 0)
92
+ if negative:
93
+ # noinspection PyTypeChecker
94
+ idx = np.logical_or(idx, (logs >= 0.0).all(axis=1))
95
+ # idx = np.logical_or(idx, logs.loc[logs > 0.0]).any(axis=1)
96
+ if no_zero:
97
+ idx = np.logical_or(idx, (logs == 0.0).any(axis=1))
98
+ if positive:
99
+ # noinspection PyTypeChecker
100
+ idx = np.logical_or(idx, (logs < 0.0).any(axis=1))
101
+
102
+ # Negate idx to identify samples to retain
103
+ idx = np.logical_not(idx)
104
+ num_valid_samples = idx.sum()
105
+ if num_valid_samples == 0:
106
+ raise ValueError("No acceptable input values")
107
+ for i in range(len(input_args)):
108
+ if isinstance(input_args[i], np.ndarray):
109
+ input_args[i] = input_args[i][idx]
110
+ else: # data frame
111
+ # https://pandas.pydata.org/pandas-docs/stable/user_guide/gotchas.html#byte-ordering-issues
112
+
113
+ check_type = (
114
+ np.array([col_type.byteorder for col_type in input_args[i].dtypes])
115
+ == WRONG_BYTEORDER
116
+ )
117
+ if np.any(check_type):
118
+ tmp_array = (
119
+ input_args[i].to_numpy().byteswap().newbyteorder().astype(float)
120
+ )
121
+ cols = input_args[i].columns
122
+ for j in range(check_type.shape[0]):
123
+ if check_type[j]:
124
+ input_args[i][cols[j]] = tmp_array[:, j]
125
+ input_args[i] = input_args[i].loc[idx]
126
+ return np.array(idx), input_args
@@ -0,0 +1,78 @@
1
+ from sys import byteorder
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ WRONG_BYTEORDER = ">" if byteorder == "little" else "<"
7
+
8
+
9
+ def filter_output(idx_inp, inp_log):
10
+ """
11
+ Function to restore outputs from a plugin to original length and
12
+ with values at correct positions. The logs are assumed to go through
13
+ matching input filtering done by gen_utilities.filter_input_log earlier.
14
+
15
+ Parameters
16
+ ----------
17
+ idx_inp: np.ndarray
18
+ boolean array which is True at locations to be filled, length idx_inp is returned length of
19
+ arrays or data frames.
20
+ inp_log: tuple or list or np.ndarray or pd.DataFrame
21
+ input numpy array(s) or pandas data frame(s), in list or tuple that are to be expanded to original
22
+ length.
23
+
24
+ Returns
25
+ -------
26
+ return_logs : list
27
+ Expanded inputs.
28
+ """
29
+
30
+ def _expand_array(idx, inp_single_log):
31
+ logs = np.ones(idx.shape, dtype=float) * np.nan
32
+ try:
33
+ logs[idx] = inp_single_log.flatten()
34
+ except ValueError:
35
+ # Assume that the dtype of the input log is not fit for casting to float, set to object and retry
36
+ logs = logs.astype(object)
37
+ logs[idx] = inp_single_log
38
+ return logs.reshape(idx.shape)
39
+
40
+ def _expand_df(idx, inp_df):
41
+ logs = pd.DataFrame(columns=inp_df.columns, index=np.arange(idx.shape[0]))
42
+ logs.loc[idx] = inp_df
43
+ return logs
44
+
45
+ if not isinstance(inp_log, (list, tuple, np.ndarray, pd.DataFrame)):
46
+ raise ValueError(
47
+ "filter_output: unknown input data type: {}".format(type(inp_log))
48
+ )
49
+ if not isinstance(idx_inp, (list, np.ndarray)):
50
+ raise ValueError(
51
+ "filter_output: unknown filter array data type: {}".format(type(idx_inp))
52
+ )
53
+
54
+ # Make iterable in case of single input
55
+ if isinstance(inp_log, (np.ndarray, pd.DataFrame)):
56
+ inp_log = [inp_log]
57
+ if isinstance(idx_inp, np.ndarray):
58
+ idx_inp = [idx_inp]
59
+
60
+ # Possible to simplify?
61
+ if len(idx_inp) != len(inp_log):
62
+ if len(idx_inp) == 1:
63
+ idx_inp = idx_inp * len(inp_log)
64
+ else:
65
+ raise ValueError(
66
+ "filter_output: mismatch between length of filter arrays and inputs: {} and {}".format(
67
+ len(idx_inp), len(inp_log)
68
+ )
69
+ )
70
+
71
+ return_logs = []
72
+ for this_idx, this_log in zip(idx_inp, inp_log):
73
+ if isinstance(this_log, np.ndarray):
74
+ return_logs.append(_expand_array(this_idx, this_log))
75
+ elif isinstance(this_log, pd.DataFrame):
76
+ return_logs.append(_expand_df(this_idx, this_log))
77
+
78
+ return return_logs
@@ -0,0 +1,14 @@
1
+ from .dummy_vars import generate_dummy_vars
2
+ from .exponential_model import CarbonateExponentialPressure
3
+ from .import_ml_models import import_model
4
+ from .run_regression import run_regression
5
+ from .sigmoidal_model import CarbonateSigmoidalPressure, Sigmoid
6
+
7
+ __all__ = [
8
+ "generate_dummy_vars",
9
+ "CarbonateExponentialPressure",
10
+ "import_model",
11
+ "run_regression",
12
+ "CarbonateSigmoidalPressure",
13
+ "Sigmoid",
14
+ ]
@@ -0,0 +1,42 @@
1
+ import numpy as np
2
+ from sklearn.preprocessing import OneHotEncoder
3
+
4
+
5
+ def generate_dummy_vars(inp_frame, class_var, ohe=None):
6
+ """
7
+ From categorical variables generate a one-hot-encoder, i.e. each value in the categorical variable becomes a binary
8
+ variable. See sklearn.preprocessing.OneHotEncoder.
9
+
10
+ Parameters
11
+ ----------
12
+ inp_frame : pd.DataFrame
13
+ Input data containing categorical variables.
14
+ class_var : str
15
+ Name of categorical variable.
16
+ ohe : preprocessing.OneHotEncoder
17
+ One-hot-encoder object.
18
+
19
+ Returns
20
+ -------
21
+ dum_features, no_dummy_cols, dum_var_names : (np.ndarray, int, np.ndarray)
22
+ dum_features: 2D array with transformed dummy variables, no_dummy_cols: number of columns in returned array,
23
+ dum_var_names: automatically generated feature names.
24
+ """
25
+ from pandas.api.types import is_numeric_dtype
26
+
27
+ if is_numeric_dtype(inp_frame[class_var]):
28
+ # Make sure that the chosen indicator variable contains discrete values
29
+ inp_frame = inp_frame.astype({class_var: "int32"})
30
+
31
+ features_in = np.array(inp_frame[class_var]).reshape(-1, 1)
32
+
33
+ if ohe is None:
34
+ classes = features_in
35
+ ohe = OneHotEncoder(categories="auto", sparse_output=False)
36
+ ohe.fit(classes)
37
+
38
+ dum_features = ohe.transform(features_in)
39
+ no_dummy_cols = dum_features.shape[1]
40
+ dum_var_names = ohe.get_feature_names_out()
41
+
42
+ return dum_features, no_dummy_cols, dum_var_names
@@ -0,0 +1,119 @@
1
+ import pickle
2
+ from typing import Union
3
+
4
+ import numpy as np
5
+
6
+
7
+ def _verify_input(inp_arr):
8
+ if isinstance(inp_arr, np.ndarray) and not (
9
+ inp_arr.ndim == 2 and inp_arr.shape[1] == 3
10
+ ):
11
+ raise ValueError(
12
+ "Input to predict method should be an nx3 numpy array with columns velocity, in situ "
13
+ "pressure and depleted pressure"
14
+ )
15
+
16
+
17
+ class CarbonateExponentialPressure:
18
+ def __init__(
19
+ self,
20
+ a_factor: float = None,
21
+ b_factor: float = None,
22
+ model_max_pressure: float = None,
23
+ description: str = "",
24
+ ):
25
+ self._a_factor = a_factor
26
+ self._b_factor = b_factor
27
+ self._model_max_pressure = model_max_pressure
28
+ self._description = description
29
+
30
+ def todict(self):
31
+ return {
32
+ "a_factor": self._a_factor,
33
+ "b_factor": self._b_factor,
34
+ "model_max_pressure": self._model_max_pressure,
35
+ "description": self._description,
36
+ }
37
+
38
+ @property
39
+ def a_factor(self) -> float:
40
+ return self._a_factor
41
+
42
+ @property
43
+ def b_factor(self) -> float:
44
+ return self._b_factor
45
+
46
+ @property
47
+ def max_pressure(self) -> float:
48
+ return self._model_max_pressure
49
+
50
+ @property
51
+ def description(self) -> str:
52
+ return self._description
53
+
54
+ def predict(self, inp_arr: np.ndarray) -> Union[np.ndarray, None]:
55
+ _verify_input(inp_arr)
56
+ if not self._valid():
57
+ return None
58
+ vel = inp_arr[:, 0]
59
+ eff_pres_in_situ = inp_arr[:, 1]
60
+ eff_pres_depl = inp_arr[:, 2]
61
+ # Return differential velocity to match alternative models
62
+ return (
63
+ vel
64
+ * (1.0 - self._a_factor * np.exp(-eff_pres_depl / self._b_factor))
65
+ / (1.0 - self._a_factor * np.exp(-eff_pres_in_situ / self._b_factor))
66
+ - vel
67
+ )
68
+
69
+ def predict_max(self, inp_arr: np.ndarray) -> Union[np.ndarray, None]:
70
+ _verify_input(inp_arr)
71
+ if not self._valid():
72
+ return None
73
+ vel = inp_arr[:, 0]
74
+ eff_pres_in_situ = inp_arr[:, 1]
75
+ return (
76
+ vel
77
+ * (
78
+ 1.0
79
+ - self._a_factor * np.exp(-self._model_max_pressure / self._b_factor)
80
+ )
81
+ / (1.0 - self._a_factor * np.exp(-eff_pres_in_situ / self.b_factor))
82
+ )
83
+
84
+ def predict_abs(self, inp_arr: np.ndarray) -> Union[np.ndarray, None]:
85
+ _verify_input(inp_arr)
86
+ if not self._valid():
87
+ return None
88
+ vel = inp_arr[:, 0]
89
+ eff_pres_in_situ = inp_arr[:, 1]
90
+ eff_pres_depl = inp_arr[:, 2]
91
+ return (
92
+ vel
93
+ * (1.0 - self._a_factor * np.exp(-eff_pres_depl / self._b_factor))
94
+ / (1.0 - self._a_factor * np.exp(-eff_pres_in_situ / self._b_factor))
95
+ )
96
+
97
+ def save(self, file):
98
+ with open(file, "wb") as f_out:
99
+ pickle.dump(self.todict(), f_out)
100
+
101
+ @classmethod
102
+ def load(cls, file):
103
+ with open(file, "rb") as f_in:
104
+ inp_pcl = pickle.load(f_in)
105
+ return cls(
106
+ a_factor=inp_pcl["a_factor"],
107
+ b_factor=inp_pcl["b_factor"],
108
+ model_max_pressure=inp_pcl["model_max_pressure"],
109
+ description=inp_pcl["description"],
110
+ )
111
+
112
+ def _valid(self):
113
+ if self.a_factor is None:
114
+ raise ValueError('object field "a_factor" is not set')
115
+ if self.b_factor is None:
116
+ raise ValueError('object field "b_factor" is not set')
117
+ if self.max_pressure is None:
118
+ raise ValueError('object field "max_pressure" is not set')
119
+ return True
@@ -0,0 +1,61 @@
1
+ from .exponential_model import CarbonateExponentialPressure
2
+ from .sigmoidal_model import CarbonateSigmoidalPressure
3
+
4
+
5
+ def import_model(model_file_name):
6
+ """
7
+ Utility to import a pickled dict containing information needed to run a classification or regression based on
8
+ a calibrated model.
9
+
10
+ Parameters
11
+ ----------
12
+ model_file_name : str
13
+ Full name including path for model file.
14
+
15
+ Returns
16
+ -------
17
+ models, scaler, ohe, label_var, label_units, feature_var, cat_var : Any
18
+ models: various regression or classification models from e.g. sklearn or tensorflow keras, scaler: preprocessing
19
+ Robust Scaler, label_var: name(s) of label variable(s), label_unit: unit(s) of label variable(s), cat_var:
20
+ categorical variables that should be encoded with one-hot-encoder.
21
+ """
22
+
23
+ from pickle import load
24
+
25
+ with open(model_file_name, "rb") as fin:
26
+ # 11.04.2021 HFLE: There is an issue that is not connected to the local function, in that a warning is issued
27
+ # when the model is loaded, claiming that it is of an older version. This is debugged in detail, and the model
28
+ # IS of the correct version, so the error arise elsewhere. To avoid confusion, the warning is suppressed here
29
+ import warnings
30
+
31
+ with warnings.catch_warnings():
32
+ warnings.simplefilter("ignore", category=UserWarning)
33
+ mod_dict = load(fin)
34
+
35
+ if mod_dict["model_type"] == "Sigmoid":
36
+ models = CarbonateSigmoidalPressure.load(mod_dict["nn_mod"])
37
+ elif mod_dict["model_type"] == "Exponential":
38
+ models = CarbonateExponentialPressure.load(mod_dict["nn_mod"])
39
+ else:
40
+ raise ValueError("unknown model type {}".format(mod_dict["model_type"]))
41
+
42
+ ohe = None
43
+ cat_var = []
44
+ try:
45
+ if mod_dict["ohe"]:
46
+ with open(mod_dict["ohe"], "rb") as f:
47
+ ohe_dict = load(f)
48
+ ohe = ohe_dict["ohe"]
49
+ cat_var = ohe_dict["cat_var"]
50
+ except (FileExistsError, FileNotFoundError):
51
+ pass
52
+
53
+ return (
54
+ models,
55
+ mod_dict["scaler"],
56
+ ohe,
57
+ mod_dict["label_var"],
58
+ mod_dict["label_units"],
59
+ mod_dict["feature_var"],
60
+ cat_var,
61
+ )
@@ -0,0 +1,151 @@
1
+ import os
2
+ from re import match
3
+
4
+ import numpy as np
5
+ import pandas as pd
6
+
7
+ from .dummy_vars import generate_dummy_vars
8
+ from .import_ml_models import import_model
9
+
10
+
11
+ def _read_models(*model_files, model_dir=None):
12
+ # Find the directory of the model files, change working directory, return to original directory at end of function
13
+ orig_dir = os.getcwd()
14
+ if model_dir is None:
15
+ model_dir, _ = os.path.split(model_files[0])
16
+ os.chdir(model_dir)
17
+ # Allocate lists and read model
18
+ reg_model, scaler, ohe, label_var, label_unit, feat_var, cat_var = (
19
+ [] for _ in range(7)
20
+ )
21
+ answer_lists = [reg_model, scaler, ohe, label_var, label_unit, feat_var, cat_var]
22
+ for mod_name in model_files:
23
+ answer = import_model(mod_name)
24
+ for ans, lst in zip(answer, answer_lists):
25
+ lst.append(ans)
26
+
27
+ # Need to modify names
28
+ col_names, col_units = ([] for _ in range(2))
29
+ for i in range(len(label_var)):
30
+ col_names.append(label_var[i] + "_" + model_files[i].replace(label_var[i], ""))
31
+ col_units.append(label_unit[i])
32
+
33
+ os.chdir(orig_dir)
34
+
35
+ return (
36
+ reg_model,
37
+ scaler,
38
+ ohe,
39
+ label_var,
40
+ label_unit,
41
+ feat_var,
42
+ cat_var,
43
+ col_names,
44
+ col_units,
45
+ )
46
+
47
+
48
+ def _perform_regression(
49
+ inp_frame, col_names, feat_var, cat_var, ohe, scaler, reg_model
50
+ ):
51
+ depth = inp_frame.index.to_numpy()
52
+
53
+ res_frame = pd.DataFrame(index=depth, columns=col_names)
54
+
55
+ for j, model_name in enumerate(col_names):
56
+ tmp_frame = inp_frame.copy()
57
+
58
+ # Limit to columns used in estimation before dropping NaNs
59
+ num_var = [i for i in feat_var[j] if not bool(match(r"x\d", i))]
60
+ no_num_var = len(num_var)
61
+ if cat_var[j]:
62
+ num_var.append(cat_var[j])
63
+ tmp_frame = tmp_frame[num_var]
64
+ idx_na_n = tmp_frame.isna().any(axis=1)
65
+
66
+ if cat_var[j]:
67
+ dum_features, _, dum_var_names = generate_dummy_vars(
68
+ tmp_frame.loc[~idx_na_n], cat_var[j], ohe=ohe[j]
69
+ )
70
+ # Add dummy features to data frame
71
+ kept_dum_var = []
72
+ for i, name in enumerate(dum_var_names):
73
+ if name in feat_var[j]:
74
+ tmp_frame.loc[~idx_na_n, name] = dum_features[:, i]
75
+ kept_dum_var.append(name)
76
+ tmp_frame.drop(columns=[cat_var[j]], inplace=True)
77
+
78
+ # Need to assure that we have the correct sequence of features
79
+ tmp_frame = tmp_frame.reindex(columns=feat_var[j])
80
+
81
+ new_features = np.zeros((np.sum(~idx_na_n), tmp_frame.shape[1]))
82
+ # Make scaling optional
83
+ if scaler[j] is not None:
84
+ new_features[:, :no_num_var] = scaler[j].transform(
85
+ tmp_frame.to_numpy()[~idx_na_n, :no_num_var]
86
+ )
87
+ else:
88
+ new_features[:, :no_num_var] = tmp_frame.to_numpy()[
89
+ ~idx_na_n, :no_num_var
90
+ ]
91
+ new_features[:, no_num_var:] = tmp_frame.loc[
92
+ ~idx_na_n, kept_dum_var
93
+ ].to_numpy()
94
+ else:
95
+ # Much simpler if there are no dummy variables
96
+ # Need to assure that we have the correct sequence of features
97
+ tmp_frame = tmp_frame.reindex(columns=feat_var[j])
98
+ # Make scaling optional
99
+ if scaler[j] is not None:
100
+ new_features = scaler[j].transform(tmp_frame.to_numpy()[~idx_na_n, :])
101
+ else:
102
+ new_features = tmp_frame.to_numpy()[~idx_na_n, :]
103
+
104
+ new_var = np.ones(depth.shape[0]) * np.nan
105
+ new_var[~idx_na_n] = reg_model[j].predict(new_features).flatten()
106
+ res_frame[col_names[j]] = new_var
107
+
108
+ return res_frame
109
+
110
+
111
+ def run_regression(inp_df, vp_model_file_name, vs_model_file_name, model_dir=None):
112
+ """
113
+ Estimate Vp and Vs by neural network regression with multiple inputs.
114
+
115
+ Parameters
116
+ ----------
117
+ inp_df : pd.DataFrame
118
+ Input logs required for the regression.
119
+ vp_model_file_name : str
120
+ Full file name for vp model.
121
+ vs_model_file_name : str
122
+ Full file name for vs model.
123
+ model_dir : str
124
+ Directory.
125
+
126
+ Returns
127
+ -------
128
+ vp, vs : pd.DataFrame
129
+ Estimated vp and vs as series in Pandas DataFrame.
130
+ """
131
+
132
+ (
133
+ regression_model,
134
+ scaler_obj,
135
+ ohe_obj,
136
+ label_var,
137
+ label_var_unit,
138
+ feature_var,
139
+ category_var,
140
+ column_names,
141
+ column_units,
142
+ ) = _read_models(vp_model_file_name, vs_model_file_name, model_dir=model_dir)
143
+ return _perform_regression(
144
+ inp_df,
145
+ column_names,
146
+ feature_var,
147
+ category_var,
148
+ ohe_obj,
149
+ scaler_obj,
150
+ regression_model,
151
+ )