gebpy 1.1.3__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.
Files changed (254) hide show
  1. gebpy/__init__.py +55 -0
  2. gebpy/__pycache__/__init__.cpython-310.pyc +0 -0
  3. gebpy/adapters/__init__.py +0 -0
  4. gebpy/cli/__init__.py +0 -0
  5. gebpy/core/__init__.py +0 -0
  6. gebpy/core/chemistry/__init__.py +0 -0
  7. gebpy/core/chemistry/common.py +1369 -0
  8. gebpy/core/chemistry/elements.py +317 -0
  9. gebpy/core/chemistry/geochemistry.py +1728 -0
  10. gebpy/core/fluids/__init__.py +0 -0
  11. gebpy/core/io/__init__.py +0 -0
  12. gebpy/core/mathematics/__init__.py +0 -0
  13. gebpy/core/minerals/__init__.py +0 -0
  14. gebpy/core/minerals/carbonates.py +412 -0
  15. gebpy/core/minerals/common.py +555 -0
  16. gebpy/core/minerals/config.py +77 -0
  17. gebpy/core/minerals/cyclosilicates.py +0 -0
  18. gebpy/core/minerals/halides.py +0 -0
  19. gebpy/core/minerals/inosilicates.py +0 -0
  20. gebpy/core/minerals/nesosilicates.py +0 -0
  21. gebpy/core/minerals/organics.py +0 -0
  22. gebpy/core/minerals/oxides.py +589 -0
  23. gebpy/core/minerals/phosphates.py +0 -0
  24. gebpy/core/minerals/phospides.py +0 -0
  25. gebpy/core/minerals/phyllosilicates.py +436 -0
  26. gebpy/core/minerals/sorosilicates.py +0 -0
  27. gebpy/core/minerals/sulfates.py +0 -0
  28. gebpy/core/minerals/sulfides.py +459 -0
  29. gebpy/core/minerals/synthesis.py +201 -0
  30. gebpy/core/minerals/tectosilicates.py +433 -0
  31. gebpy/core/physics/__init__.py +0 -0
  32. gebpy/core/physics/common.py +53 -0
  33. gebpy/core/physics/geophysics.py +351 -0
  34. gebpy/core/rocks/__init__.py +0 -0
  35. gebpy/core/rocks/anisotropic_rocks.py +395 -0
  36. gebpy/core/rocks/common.py +95 -0
  37. gebpy/core/rocks/config.py +77 -0
  38. gebpy/core/rocks/isotropic_rocks.py +395 -0
  39. gebpy/core/rocks/sedimentary.py +385 -0
  40. gebpy/core/subsurface/__init__.py +0 -0
  41. gebpy/data_minerals/__init__.py +0 -0
  42. gebpy/data_minerals/albite.yaml +59 -0
  43. gebpy/data_minerals/anatase.yaml +43 -0
  44. gebpy/data_minerals/ankerite.yaml +47 -0
  45. gebpy/data_minerals/annite.yaml +57 -0
  46. gebpy/data_minerals/anorthite.yaml +59 -0
  47. gebpy/data_minerals/antigorite.yaml +53 -0
  48. gebpy/data_minerals/aragonite.yaml +48 -0
  49. gebpy/data_minerals/argutite.yaml +43 -0
  50. gebpy/data_minerals/arsenolite.yaml +40 -0
  51. gebpy/data_minerals/au3oxide.yaml +46 -0
  52. gebpy/data_minerals/avicennite.yaml +40 -0
  53. gebpy/data_minerals/azurite.yaml +53 -0
  54. gebpy/data_minerals/baddeleyite.yaml +49 -0
  55. gebpy/data_minerals/bismite.yaml +49 -0
  56. gebpy/data_minerals/boehmite.yaml +48 -0
  57. gebpy/data_minerals/brookite.yaml +46 -0
  58. gebpy/data_minerals/brucite.yaml +45 -0
  59. gebpy/data_minerals/bunsenite.yaml +40 -0
  60. gebpy/data_minerals/calcite.yaml +45 -0
  61. gebpy/data_minerals/cassiterite.yaml +43 -0
  62. gebpy/data_minerals/cerussite.yaml +48 -0
  63. gebpy/data_minerals/chamosite.yaml +56 -0
  64. gebpy/data_minerals/chlorite.yaml +75 -0
  65. gebpy/data_minerals/chromite.yaml +42 -0
  66. gebpy/data_minerals/chrysotile.yaml +53 -0
  67. gebpy/data_minerals/claudetite.yaml +49 -0
  68. gebpy/data_minerals/clinochlore.yaml +55 -0
  69. gebpy/data_minerals/cochromite.yaml +42 -0
  70. gebpy/data_minerals/corundum.yaml +43 -0
  71. gebpy/data_minerals/crocoite.yaml +51 -0
  72. gebpy/data_minerals/cuprite.yaml +40 -0
  73. gebpy/data_minerals/cuprospinel.yaml +42 -0
  74. gebpy/data_minerals/diaspore.yaml +48 -0
  75. gebpy/data_minerals/dolomite.yaml +47 -0
  76. gebpy/data_minerals/eastonite.yaml +57 -0
  77. gebpy/data_minerals/eskolaite.yaml +43 -0
  78. gebpy/data_minerals/fechlorite.yaml +61 -0
  79. gebpy/data_minerals/fecolumbite.yaml +48 -0
  80. gebpy/data_minerals/ferberite.yaml +51 -0
  81. gebpy/data_minerals/fetantalite.yaml +48 -0
  82. gebpy/data_minerals/franklinite.yaml +42 -0
  83. gebpy/data_minerals/gahnite.yaml +42 -0
  84. gebpy/data_minerals/galaxite.yaml +42 -0
  85. gebpy/data_minerals/geikielite.yaml +45 -0
  86. gebpy/data_minerals/gibbsite.yaml +51 -0
  87. gebpy/data_minerals/glauconite.yaml +69 -0
  88. gebpy/data_minerals/goethite.yaml +48 -0
  89. gebpy/data_minerals/groutite.yaml +48 -0
  90. gebpy/data_minerals/hematite.yaml +43 -0
  91. gebpy/data_minerals/hercynite.yaml +42 -0
  92. gebpy/data_minerals/huebnerite.yaml +51 -0
  93. gebpy/data_minerals/ikaite.yaml +53 -0
  94. gebpy/data_minerals/illite.yaml +55 -0
  95. gebpy/data_minerals/ilmenite.yaml +45 -0
  96. gebpy/data_minerals/jacobsite.yaml +42 -0
  97. gebpy/data_minerals/kalsilite.yaml +47 -0
  98. gebpy/data_minerals/kaolinite.yaml +59 -0
  99. gebpy/data_minerals/karelianite.yaml +43 -0
  100. gebpy/data_minerals/lime.yaml +40 -0
  101. gebpy/data_minerals/litharge.yaml +43 -0
  102. gebpy/data_minerals/magnesiochromite.yaml +42 -0
  103. gebpy/data_minerals/magnesioferrite.yaml +42 -0
  104. gebpy/data_minerals/magnesite.yaml +45 -0
  105. gebpy/data_minerals/magnetite.yaml +41 -0
  106. gebpy/data_minerals/malachite.yaml +53 -0
  107. gebpy/data_minerals/manganite.yaml +51 -0
  108. gebpy/data_minerals/manganochromite.yaml +42 -0
  109. gebpy/data_minerals/manganosite.yaml +40 -0
  110. gebpy/data_minerals/marialite.yaml +49 -0
  111. gebpy/data_minerals/massicot.yaml +46 -0
  112. gebpy/data_minerals/meionite.yaml +49 -0
  113. gebpy/data_minerals/mgchlorite.yaml +61 -0
  114. gebpy/data_minerals/mgcolumbite.yaml +48 -0
  115. gebpy/data_minerals/mgtantalite.yaml +48 -0
  116. gebpy/data_minerals/microcline.yaml +59 -0
  117. gebpy/data_minerals/minium.yaml +44 -0
  118. gebpy/data_minerals/mnchlorite.yaml +61 -0
  119. gebpy/data_minerals/mncolumbite.yaml +48 -0
  120. gebpy/data_minerals/mntantalite.yaml +48 -0
  121. gebpy/data_minerals/monteponite.yaml +40 -0
  122. gebpy/data_minerals/montmorillonite.yaml +77 -0
  123. gebpy/data_minerals/muscovite.yaml +55 -0
  124. gebpy/data_minerals/nanepheline.yaml +47 -0
  125. gebpy/data_minerals/nichlorite.yaml +61 -0
  126. gebpy/data_minerals/nichromite.yaml +42 -0
  127. gebpy/data_minerals/nimite.yaml +55 -0
  128. gebpy/data_minerals/nontronite.yaml +73 -0
  129. gebpy/data_minerals/orthoclase.yaml +53 -0
  130. gebpy/data_minerals/paratellurite.yaml +43 -0
  131. gebpy/data_minerals/pennantite.yaml +61 -0
  132. gebpy/data_minerals/periclase.yaml +40 -0
  133. gebpy/data_minerals/phlogopite.yaml +57 -0
  134. gebpy/data_minerals/plattnerite.yaml +43 -0
  135. gebpy/data_minerals/powellite.yaml +45 -0
  136. gebpy/data_minerals/pyrite.yaml +40 -0
  137. gebpy/data_minerals/pyrolusite.yaml +43 -0
  138. gebpy/data_minerals/pyrophanite.yaml +45 -0
  139. gebpy/data_minerals/pyrophyllite.yaml +59 -0
  140. gebpy/data_minerals/quartz.yaml +43 -0
  141. gebpy/data_minerals/rhodochrosite.yaml +45 -0
  142. gebpy/data_minerals/rutile.yaml +43 -0
  143. gebpy/data_minerals/saponite.yaml +77 -0
  144. gebpy/data_minerals/scheelite.yaml +45 -0
  145. gebpy/data_minerals/scrutinyite.yaml +46 -0
  146. gebpy/data_minerals/senarmontite.yaml +40 -0
  147. gebpy/data_minerals/siderite.yaml +45 -0
  148. gebpy/data_minerals/siderophyllite.yaml +57 -0
  149. gebpy/data_minerals/smithsonite.yaml +45 -0
  150. gebpy/data_minerals/spinel.yaml +42 -0
  151. gebpy/data_minerals/stishovite.yaml +43 -0
  152. gebpy/data_minerals/stolzite.yaml +45 -0
  153. gebpy/data_minerals/talc.yaml +53 -0
  154. gebpy/data_minerals/tistarite.yaml +43 -0
  155. gebpy/data_minerals/trevorite.yaml +42 -0
  156. gebpy/data_minerals/ulvoespinel.yaml +42 -0
  157. gebpy/data_minerals/uraninite.yaml +40 -0
  158. gebpy/data_minerals/valentinite.yaml +46 -0
  159. gebpy/data_minerals/vermiculite.yaml +69 -0
  160. gebpy/data_minerals/wulfenite.yaml +45 -0
  161. gebpy/data_minerals/wustite.yaml +40 -0
  162. gebpy/data_minerals/zincite.yaml +43 -0
  163. gebpy/data_minerals/zincochromite.yaml +42 -0
  164. gebpy/data_rocks/__init__.py +0 -0
  165. gebpy/data_rocks/dolostone.yaml +40 -0
  166. gebpy/data_rocks/limestone.yaml +40 -0
  167. gebpy/data_rocks/marl.yaml +50 -0
  168. gebpy/data_rocks/sandstone.yaml +39 -0
  169. gebpy/data_rocks/shale.yaml +50 -0
  170. gebpy/gebpy_app.py +8732 -0
  171. gebpy/gui/__init__.py +0 -0
  172. gebpy/lib/images/GebPy_Header.png +0 -0
  173. gebpy/lib/images/GebPy_Icon.png +0 -0
  174. gebpy/lib/images/GebPy_Logo.png +0 -0
  175. gebpy/main.py +29 -0
  176. gebpy/modules/__init__.py +0 -0
  177. gebpy/modules/__pycache__/__init__.cpython-310.pyc +0 -0
  178. gebpy/modules/__pycache__/metamorphics.cpython-310.pyc +0 -0
  179. gebpy/modules/__pycache__/silicates.cpython-310.pyc +0 -0
  180. gebpy/modules/carbonates.py +2658 -0
  181. gebpy/modules/chemistry.py +1369 -0
  182. gebpy/modules/core.py +1805 -0
  183. gebpy/modules/elements.py +317 -0
  184. gebpy/modules/evaporites.py +1299 -0
  185. gebpy/modules/exploration.py +1145 -0
  186. gebpy/modules/fluids.py +339 -0
  187. gebpy/modules/geochemistry.py +1727 -0
  188. gebpy/modules/geophysics.py +351 -0
  189. gebpy/modules/gui.py +9093 -0
  190. gebpy/modules/gui_elements.py +145 -0
  191. gebpy/modules/halides.py +485 -0
  192. gebpy/modules/igneous.py +2241 -0
  193. gebpy/modules/metamorphics.py +3222 -0
  194. gebpy/modules/mineralogy.py +442 -0
  195. gebpy/modules/minerals.py +7954 -0
  196. gebpy/modules/ore.py +1648 -0
  197. gebpy/modules/organics.py +530 -0
  198. gebpy/modules/oxides.py +9057 -0
  199. gebpy/modules/petrophysics.py +98 -0
  200. gebpy/modules/phosphates.py +589 -0
  201. gebpy/modules/phospides.py +194 -0
  202. gebpy/modules/plotting.py +619 -0
  203. gebpy/modules/pyllosilicates.py +380 -0
  204. gebpy/modules/sedimentary_rocks.py +908 -0
  205. gebpy/modules/sequences.py +2166 -0
  206. gebpy/modules/series.py +1625 -0
  207. gebpy/modules/silicates.py +11102 -0
  208. gebpy/modules/siliciclastics.py +1846 -0
  209. gebpy/modules/subsurface_2d.py +179 -0
  210. gebpy/modules/sulfates.py +1629 -0
  211. gebpy/modules/sulfides.py +4786 -0
  212. gebpy/plotting/__init__.py +0 -0
  213. gebpy/ui_nb/__init__.py +0 -0
  214. gebpy/user_data/.gitkeep +0 -0
  215. gebpy-1.1.3.dist-info/LICENSE +165 -0
  216. gebpy-1.1.3.dist-info/METADATA +207 -0
  217. gebpy-1.1.3.dist-info/RECORD +254 -0
  218. gebpy-1.1.3.dist-info/WHEEL +5 -0
  219. gebpy-1.1.3.dist-info/entry_points.txt +2 -0
  220. gebpy-1.1.3.dist-info/top_level.txt +1 -0
  221. modules/__init__.py +0 -0
  222. modules/carbonates.py +2658 -0
  223. modules/chemistry.py +1369 -0
  224. modules/core.py +1805 -0
  225. modules/elements.py +317 -0
  226. modules/evaporites.py +1299 -0
  227. modules/exploration.py +765 -0
  228. modules/fluids.py +339 -0
  229. modules/geochemistry.py +1727 -0
  230. modules/geophysics.py +337 -0
  231. modules/gui.py +9093 -0
  232. modules/gui_elements.py +145 -0
  233. modules/halides.py +485 -0
  234. modules/igneous.py +2196 -0
  235. modules/metamorphics.py +2699 -0
  236. modules/mineralogy.py +442 -0
  237. modules/minerals.py +7954 -0
  238. modules/ore.py +1628 -0
  239. modules/organics.py +530 -0
  240. modules/oxides.py +9057 -0
  241. modules/petrophysics.py +98 -0
  242. modules/phosphates.py +589 -0
  243. modules/phospides.py +194 -0
  244. modules/plotting.py +619 -0
  245. modules/pyllosilicates.py +380 -0
  246. modules/sedimentary_rocks.py +908 -0
  247. modules/sequences.py +2166 -0
  248. modules/series.py +1625 -0
  249. modules/silicates.py +11102 -0
  250. modules/siliciclastics.py +1830 -0
  251. modules/subsurface_2d.py +179 -0
  252. modules/sulfates.py +1629 -0
  253. modules/sulfides.py +4786 -0
  254. notebooks/__init__.py +0 -0
@@ -0,0 +1,395 @@
1
+ #!/usr/bin/env python
2
+ # -*-coding: utf-8 -*-
3
+
4
+ #-----------------------------------------------
5
+
6
+ # Name: isotropic_rocks.py
7
+ # Author: Maximilian A. Beeskow
8
+ # Version: 1.0
9
+ # Date: 17.12.2025
10
+
11
+ #-----------------------------------------------
12
+
13
+ """
14
+ Module: isotropic_rocks.py
15
+ This module controls the generation of synthetic data for isotropic rocks.
16
+ """
17
+
18
+ # PACKAGES
19
+ import yaml
20
+ import numpy as np
21
+ import pandas as pd
22
+ from pathlib import Path
23
+
24
+ # MODULES
25
+ from ..minerals.synthesis import MineralDataGeneration
26
+ from ..rocks.common import RockGeneration
27
+ from ..physics.common import Geophysics
28
+
29
+ # Code
30
+ BASE_PATH = Path(__file__).resolve().parents[2]
31
+ DATA_PATH = BASE_PATH / "data_rocks"
32
+
33
+ class IsotropicRocks:
34
+ _yaml_cache = {}
35
+ _mineralogy_cache = {}
36
+ _mineral_groups_cache = {}
37
+ _rocks = {"Sandstone", "Limestone", "Dolostone", "Marl"}
38
+
39
+ def __init__(self, name, random_seed) -> None:
40
+ self.name = name
41
+ self.random_seed = random_seed
42
+ self.rng = np.random.default_rng(random_seed)
43
+ self.current_seed = int(np.round(self.rng.uniform(0, 1000), 0))
44
+ self.data_path = DATA_PATH
45
+ self.rock_gen = RockGeneration()
46
+ self.geophysics = Geophysics()
47
+ self.conversion_factors = self.rock_gen._determine_oxide_conversion_factors()
48
+ self.cache = {}
49
+
50
+ def _load_yaml(self, rock_name: str) -> dict:
51
+ # 1) Cache-Hit
52
+ if rock_name in IsotropicRocks._yaml_cache:
53
+ return IsotropicRocks._yaml_cache[rock_name]
54
+
55
+ # 2) Laden von Disk
56
+ yaml_file = self.data_path/f"{rock_name}.yaml"
57
+ if not yaml_file.exists():
58
+ raise FileNotFoundError(f"No YAML file found for {rock_name}.")
59
+
60
+ with open(yaml_file, "r") as f:
61
+ data = yaml.safe_load(f)
62
+
63
+ if "mineralogy" in data and rock_name not in IsotropicRocks._mineralogy_cache:
64
+ self._compile_mineralogy(rock_name, data["mineralogy"])
65
+
66
+ if "mineral_groups" in data:
67
+ self._compile_mineral_groups(rock_name, data["mineral_groups"])
68
+
69
+ # 3) Cache schreiben
70
+ IsotropicRocks._yaml_cache[rock_name] = data
71
+
72
+ return data
73
+
74
+ def _compile_mineralogy(self, rock_name: str, mineralogy_dict: dict):
75
+ """
76
+ Extracts and compiles all chemistry formulas from the YAML file.
77
+ Stores the compiled ASTs in the global formula cache.
78
+ """
79
+ if rock_name not in IsotropicRocks._mineralogy_cache:
80
+ IsotropicRocks._mineralogy_cache[rock_name] = {}
81
+
82
+ for element, entry in mineralogy_dict.items():
83
+ mineral = element
84
+ interval = list(entry.values())
85
+ lower_limit = interval[0]
86
+ upper_limit = interval[1]
87
+ compiled = [lower_limit, upper_limit]
88
+ IsotropicRocks._mineralogy_cache[rock_name][mineral] = compiled
89
+
90
+ def _compile_mineral_groups(self, rock_name: str, group_dict: dict):
91
+ if rock_name not in IsotropicRocks._mineral_groups_cache:
92
+ IsotropicRocks._mineral_groups_cache[rock_name] = {}
93
+
94
+ for group, entry in group_dict.items():
95
+ minerals = entry["minerals"]
96
+ min_val = entry["min"]
97
+ max_val = entry["max"]
98
+
99
+ IsotropicRocks._mineral_groups_cache[rock_name][group] = {
100
+ "minerals": minerals,
101
+ "min": min_val,
102
+ "max": max_val
103
+ }
104
+
105
+ def _sample_mineralogy(self, rock_name: str, number: int):
106
+ has_groups = rock_name in IsotropicRocks._mineral_groups_cache
107
+
108
+ if not has_groups:
109
+ # ---- Modus A: flach ----
110
+ mineral_limits = IsotropicRocks._mineralogy_cache[rock_name]
111
+ mins = [v[0] for v in mineral_limits.values()]
112
+ maxs = [v[1] for v in mineral_limits.values()]
113
+ minerals = list(mineral_limits.keys())
114
+
115
+ comp = self._sample_bounded_simplex_batch(mins, maxs, number)
116
+ return minerals, comp
117
+
118
+ # ---- Modus B: gruppiert ----
119
+ groups = IsotropicRocks._mineral_groups_cache[rock_name]
120
+ mineral_limits = IsotropicRocks._mineralogy_cache[rock_name]
121
+
122
+ # 1️⃣ Gruppen + freie Minerale
123
+ group_names = list(groups.keys())
124
+ group_mins = [groups[g]["min"] for g in group_names]
125
+ group_maxs = [groups[g]["max"] for g in group_names]
126
+
127
+ free_minerals = [
128
+ m for m in mineral_limits
129
+ if not any(m in groups[g]["minerals"] for g in groups)
130
+ ]
131
+
132
+ free_mins = [mineral_limits[m][0] for m in free_minerals]
133
+ free_maxs = [mineral_limits[m][1] for m in free_minerals]
134
+
135
+ labels = group_names + free_minerals
136
+ mins = group_mins + free_mins
137
+ maxs = group_maxs + free_maxs
138
+
139
+ # 2️⃣ Top-Level-Sampling
140
+ top_comp = self._sample_bounded_simplex_batch(mins, maxs, number)
141
+
142
+ # 3️⃣ Gruppen intern auflösen
143
+ mineral_list = []
144
+ mineral_comp = []
145
+
146
+ for i, label in enumerate(labels):
147
+ frac = top_comp[:, i]
148
+
149
+ if label in groups:
150
+ minerals = groups[label]["minerals"]
151
+ n = len(minerals)
152
+ split = self.rng.dirichlet(np.ones(n), size=number)
153
+
154
+ for j, m in enumerate(minerals):
155
+ mineral_list.append(m)
156
+ mineral_comp.append(frac * split[:, j])
157
+ else:
158
+ mineral_list.append(label)
159
+ mineral_comp.append(frac)
160
+
161
+ comp = np.vstack(mineral_comp).T
162
+ return mineral_list, comp
163
+
164
+ def _sample_bounded_simplex_batch(self, min_vals, max_vals, number):
165
+ min_vals = np.asarray(min_vals, dtype=float)
166
+ max_vals = np.asarray(max_vals, dtype=float)
167
+ n = len(min_vals)
168
+
169
+ # --- Consistency ---
170
+ if min_vals.sum() > 1:
171
+ raise ValueError("Sum of minimum fractions > 1")
172
+
173
+ if max_vals.sum() < 1:
174
+ raise ValueError("Sum of maximum fractions < 1")
175
+
176
+ span = max_vals - min_vals
177
+ samples = np.zeros((number, n))
178
+
179
+ for i in range(number):
180
+ remaining = 1.0 - min_vals.sum()
181
+ order = np.arange(n)
182
+
183
+ self.rng.shuffle(order)
184
+ x = np.zeros(n)
185
+
186
+ for j in order[:-1]:
187
+ upper = min(span[j], remaining)
188
+ val = self.rng.uniform(0, upper)
189
+ x[j] = val
190
+ remaining -= val
191
+
192
+ x[order[-1]] = remaining
193
+ samples[i] = min_vals + x
194
+
195
+ return samples
196
+
197
+ def _collect_mineral_data(self, list_minerals, number):
198
+ _mineral_data = []
199
+ for index, mineral in enumerate(list_minerals):
200
+ data_init = MineralDataGeneration(mineral, number)
201
+ data_mineral = data_init.generate_data()
202
+ is_fixed = data_mineral.shape[0] == 1
203
+ if is_fixed and number > 1:
204
+ data_mineral = pd.concat([data_mineral]*number, ignore_index=True)
205
+ elif not is_fixed and data_mineral.shape[0] != number:
206
+ raise ValueError(
207
+ f"Mineral '{mineral}' returned {data_mineral.shape[0]} rows, "
208
+ f"but expected {number}.")
209
+ _mineral_data.append(data_mineral)
210
+
211
+ return _mineral_data
212
+
213
+ def _extract_mineral_property_data(self, list_minerals, data_mineral, property):
214
+ arrays = [data_mineral[i][property].to_numpy() for i in range(len(list_minerals))]
215
+ return np.vstack(arrays)
216
+
217
+ def _extract_element_data(self, data_minerals, list_elements):
218
+ seen = set(list_elements)
219
+ ordered = list(list_elements)
220
+
221
+ for dataset in data_minerals:
222
+ for key in dataset.keys():
223
+ if key.startswith("chemistry."):
224
+ element = key[len("chemistry."):]
225
+ if element not in seen:
226
+ seen.add(element)
227
+ ordered.append(element)
228
+
229
+ return ordered
230
+
231
+ def _extract_oxide_data(self, data_minerals, list_oxides):
232
+ seen = set(list_oxides)
233
+ ordered = list(list_oxides)
234
+
235
+ for dataset in data_minerals:
236
+ for key in dataset.keys():
237
+ if key.startswith("compounds."):
238
+ oxide = key[len("compounds."):]
239
+ if oxide not in seen:
240
+ seen.add(oxide)
241
+ ordered.append(oxide)
242
+
243
+ # Spezialfall Pyrit
244
+ if dataset["mineral"][0] == "Py":
245
+ for oxide in ("Fe2O3", "SO3"):
246
+ if oxide not in seen:
247
+ seen.add(oxide)
248
+ ordered.append(oxide)
249
+ if "FeS2" in seen:
250
+ seen.remove("FeS2")
251
+ ordered = [o for o in ordered if o != "FeS2"]
252
+
253
+ return ordered
254
+
255
+ def _update_chemistry_data(self, _bulk_data, data_minerals, data_composition, element, number):
256
+ n_minerals = len(data_minerals)
257
+ helper = np.zeros((n_minerals, number))
258
+ key_element = "chemistry." + element
259
+
260
+ for i, dataset in enumerate(data_minerals):
261
+ if key_element in dataset:
262
+ helper[i, :] = dataset[key_element].to_numpy()
263
+
264
+ bulk_values = np.sum(data_composition * helper.T, axis=1)
265
+ _bulk_data["w." + element] = bulk_values
266
+
267
+ return _bulk_data
268
+
269
+ def _update_oxide_data(self, bulk_data, list_oxides):
270
+ for oxide in list_oxides:
271
+ cation, anion = self.rock_gen._get_elements_of_compound(compound=oxide)
272
+ if anion == "O":
273
+ key_cation = "w." + cation
274
+ values = self.conversion_factors[oxide]["factor"]*bulk_data[key_cation]
275
+ key_oxide = "w." + oxide
276
+ bulk_data[key_oxide] = values
277
+ else:
278
+ print("There is a non-oxide compound part of the list.")
279
+
280
+ return bulk_data
281
+
282
+ def _assign_mineral_amounts(self, bulk_data, data_amounts):
283
+ for mineral, values in data_amounts.items():
284
+ key_mineral = "phi." + mineral
285
+ bulk_data[key_mineral] = values
286
+
287
+ return bulk_data
288
+
289
+ def collect_geophysical_properties(self, _helper_bulk_data, rho_f, n):
290
+ # Update bulk density data
291
+ (_helper_bulk_data["rho"], _helper_bulk_data["rho_s"],
292
+ _helper_bulk_data["rho_f"]) = self.geophysics.calculate_bulk_density_data(
293
+ v_phi=_helper_bulk_data["porosity"], val_rho=_helper_bulk_data["rho"], val_rho_f=rho_f,
294
+ val_n=n)
295
+ # Update bulk seismic velocity data
296
+ (_helper_bulk_data["vP"], _helper_bulk_data["vS"],
297
+ _helper_bulk_data["vP/vS"]) = self.geophysics.calculate_seismic_velocities(
298
+ val_K=_helper_bulk_data["K"], val_G=_helper_bulk_data["G"], val_rho=_helper_bulk_data["rho"])
299
+ # Update elastic parameter data
300
+ (_helper_bulk_data["E"], _helper_bulk_data["poisson"],
301
+ _helper_bulk_data["lame"]) = self.geophysics.calculate_elastic_parameter_data(
302
+ val_K=_helper_bulk_data["K"], val_G=_helper_bulk_data["G"])
303
+
304
+ return _helper_bulk_data
305
+
306
+ def collect_initial_compositional_data(self, list_minerals, n):
307
+ _helper_elements = []
308
+ _helper_oxides = []
309
+ _mineral_data = self._collect_mineral_data(list_minerals=list_minerals, number=n)
310
+ _helper_elements = self._extract_element_data(data_minerals=_mineral_data, list_elements=_helper_elements)
311
+ _helper_oxides = self._extract_oxide_data(data_minerals=_mineral_data, list_oxides=_helper_oxides)
312
+
313
+ return _mineral_data, _helper_elements, _helper_oxides
314
+
315
+ def collect_initial_bulk_data(self, list_minerals, _mineral_data, _helper_composition):
316
+ _helper_bulk_data = {}
317
+ for property in ["rho", "K", "G", "GR", "PE"]:
318
+ _helper_property = self._extract_mineral_property_data(
319
+ list_minerals=list_minerals, data_mineral=_mineral_data, property=property)
320
+ _helper_bulk_data[property] = np.sum(_helper_composition*_helper_property.T, axis=1)
321
+
322
+ return _helper_bulk_data
323
+
324
+ def update_compositional_bulk_data(
325
+ self, _helper_elements, _helper_bulk_data, _mineral_data, _helper_composition, _helper_oxides,
326
+ _helper_mineral_amounts, n):
327
+ for element in _helper_elements:
328
+ _helper_bulk_data = self._update_chemistry_data(
329
+ _bulk_data=_helper_bulk_data, data_minerals=_mineral_data, data_composition=_helper_composition,
330
+ element=element, number=n)
331
+ # Update oxide data
332
+ _helper_bulk_data = self._update_oxide_data(bulk_data=_helper_bulk_data, list_oxides=_helper_oxides)
333
+ # Update rock composition data
334
+ _helper_bulk_data = self._assign_mineral_amounts(
335
+ bulk_data=_helper_bulk_data, data_amounts=_helper_mineral_amounts)
336
+
337
+ return _helper_bulk_data
338
+
339
+ def generate_dataset(self, number: int = 1, fluid: str = "water", density_fluid=None) -> None:
340
+ if density_fluid is None:
341
+ if fluid == "water":
342
+ density_fluid = 1000
343
+ elif fluid == "oil":
344
+ density_fluid = 800
345
+ elif fluid == "natural gas":
346
+ density_fluid = 750
347
+
348
+ siliciclastics = {"Sandstone"}
349
+ data_yaml = self._load_yaml(rock_name=self.name)
350
+ min_porosity = data_yaml["physical_properties"]["porosity"]["min"]
351
+ max_porosity = data_yaml["physical_properties"]["porosity"]["max"]
352
+ porosity = self.rng.uniform(min_porosity, max_porosity, number)
353
+ mineral_limits = IsotropicRocks._mineralogy_cache[self.name]
354
+ _limits = {"lower": [], "upper": []}
355
+
356
+ for mineral, values in mineral_limits.items():
357
+ _limits["lower"].append(values[0])
358
+ _limits["upper"].append(values[1])
359
+
360
+ list_minerals = list(IsotropicRocks._mineralogy_cache[self.name].keys())
361
+ _properties = ["rho", "vP", "vS", "K", "G", "GR", "PE"]
362
+ _bulk_data = {}
363
+ # Collect mineralogical composition data
364
+ n_minerals = len(list_minerals)
365
+ _helper_composition = np.zeros((number, n_minerals))
366
+ _helper_mineral_amounts = {mineral: np.zeros(number) for mineral in list_minerals}
367
+
368
+ _helper_composition = self._sample_bounded_simplex_batch(
369
+ min_vals=_limits["lower"], max_vals=_limits["upper"], number=number)
370
+ _helper_mineral_amounts = {mineral: _helper_composition[:, j] for j, mineral in enumerate(list_minerals)}
371
+
372
+ # Collect mineral data
373
+ _mineral_data, _helper_elements, _helper_oxides = self.collect_initial_compositional_data(
374
+ list_minerals=list_minerals, n=number)
375
+ # Collect bulk data
376
+ _helper_bulk_data = self.collect_initial_bulk_data(
377
+ list_minerals=list_minerals, _mineral_data=_mineral_data, _helper_composition=_helper_composition)
378
+ # Assign porosity data
379
+ _helper_bulk_data["porosity"] = porosity
380
+ # Collect geophysical data
381
+ _helper_bulk_data = self.collect_geophysical_properties(
382
+ _helper_bulk_data=_helper_bulk_data, rho_f=density_fluid, n=number)
383
+ # Update chemistry data
384
+ _helper_bulk_data = self.update_compositional_bulk_data(
385
+ _helper_elements=_helper_elements, _helper_bulk_data=_helper_bulk_data, _mineral_data=_mineral_data,
386
+ _helper_composition=_helper_composition, _helper_oxides=_helper_oxides,
387
+ _helper_mineral_amounts=_helper_mineral_amounts, n=number)
388
+ # Conversion to a pandas dataframe object
389
+ _bulk_data = pd.DataFrame(_helper_bulk_data)
390
+
391
+ return _bulk_data
392
+
393
+ # TEST
394
+ if __name__ == "__main__":
395
+ DEFAULT_DATA = IsotropicRocks(name="Sandstone", random_seed=42).generate_dataset(number=10)