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,436 @@
1
+ #!/usr/bin/env python
2
+ # -*-coding: utf-8 -*-
3
+
4
+ #-----------------------------------------------
5
+
6
+ # Name: phyllosilicates.py
7
+ # Author: Maximilian A. Beeskow
8
+ # Version: 1.0
9
+ # Date: 15.12.2025
10
+
11
+ #-----------------------------------------------
12
+
13
+ """
14
+ Module: phyllosilicates.py
15
+ This module controls the generation of the synthetic data of the phyllosilicate minerals.
16
+ """
17
+
18
+ # PACKAGES
19
+ import yaml
20
+ import numpy as np
21
+ from pathlib import Path
22
+
23
+ from asteval import Interpreter
24
+
25
+ # MODULES
26
+ from ..chemistry.common import PeriodicSystem
27
+ from ..chemistry.geochemistry import MineralChemistry
28
+ from ..physics.geophysics import WellLog as wg
29
+
30
+ from .common import (
31
+ GeophysicalProperties,
32
+ CrystallographicProperties,
33
+ CrystalPhysics,
34
+ MineralGeneration as MinGen
35
+ )
36
+
37
+ # CODE
38
+ BASE_PATH = Path(__file__).resolve().parents[2]
39
+ DATA_PATH = BASE_PATH / "data_minerals"
40
+
41
+ class Phyllosilicates:
42
+ _yaml_cache = {}
43
+ _formula_cache = {}
44
+ _minerals = {
45
+ "Annite", "Eastonite", "Illite", "Kaolinite", "Phlogopite", "Siderophyllite", "Chamosite", "Clinochlore",
46
+ "Pennantite", "Nimite", "Muscovite", "Talc", "Chrysotile", "Antigorite", "Pyrophyllite", "Montmorillonite",
47
+ "Nontronite", "Saponite", "Glauconite", "Vermiculite", "Chlorite", "Biotite", "FeChlorite", "MgChlorite",
48
+ "MnChlorite", "NiChlorite"}
49
+
50
+ def __init__(self, name, random_seed, rounding=3) -> None:
51
+ self.name = name
52
+ self.random_seed = random_seed
53
+ self.rng = np.random.default_rng(random_seed)
54
+ self.current_seed = int(np.round(self.rng.uniform(0, 1000), 0))
55
+ self.data_path = DATA_PATH
56
+ self.rounding = rounding
57
+ self.ae = Interpreter()
58
+ self.cache = {}
59
+
60
+ # Chemistry
61
+ self.elements = {
62
+ "H": PeriodicSystem(name="H").get_data(),
63
+ "O": PeriodicSystem(name="O").get_data(),
64
+ "Na": PeriodicSystem(name="Na").get_data(),
65
+ "Mg": PeriodicSystem(name="Mg").get_data(),
66
+ "Al": PeriodicSystem(name="Al").get_data(),
67
+ "Si": PeriodicSystem(name="Si").get_data(),
68
+ "K": PeriodicSystem(name="K").get_data(),
69
+ "Ca": PeriodicSystem(name="Ca").get_data(),
70
+ "Mn": PeriodicSystem(name="Mn").get_data(),
71
+ "Fe": PeriodicSystem(name="Fe").get_data(),
72
+ "Ni": PeriodicSystem(name="Ni").get_data(),
73
+ }
74
+
75
+ # Geophysics
76
+ self.geophysical_properties = GeophysicalProperties()
77
+ # Crystallography
78
+ self.crystallographic_properties = CrystallographicProperties()
79
+
80
+ # Mineral-specific data
81
+ if self.name in [
82
+ "Annite", "Eastonite", "Illite", "Kaolinite", "Phlogopite", "Siderophyllite", "Chamosite", "Clinochlore",
83
+ "Pennantite", "Nimite", "Muscovite", "Talc", "Chrysotile", "Antigorite", "Pyrophyllite", "Montmorillonite",
84
+ "Nontronite", "Saponite", "Glauconite", "Vermiculite", "Chlorite", "FeChlorite", "MgChlorite", "MnChlorite",
85
+ "NiChlorite"]:
86
+ self.yaml_data = self._load_yaml(self.name.lower())
87
+ if self.name == "Biotite":
88
+ self.yaml_data = {
89
+ mineral.lower(): self._load_yaml(mineral.lower())
90
+ for mineral in ["Annite", "Phlogopite", "Siderophyllite", "Eastonite"]}
91
+ elif self.name == "Chlorite":
92
+ self.yaml_data = {
93
+ mineral.lower(): self._load_yaml(mineral.lower())
94
+ for mineral in ["FeChlorite", "MgChlorite", "MnChlorite", "NiChlorite"]}
95
+
96
+ def _load_yaml(self, mineral_name: str) -> dict:
97
+ # 1) Cache-Hit
98
+ if mineral_name in Phyllosilicates._yaml_cache:
99
+ return Phyllosilicates._yaml_cache[mineral_name]
100
+
101
+ # 2) Laden von Disk
102
+ yaml_file = self.data_path/f"{mineral_name}.yaml"
103
+ if not yaml_file.exists():
104
+ raise FileNotFoundError(f"No YAML file found for {mineral_name}.")
105
+
106
+ with open(yaml_file, "r") as f:
107
+ data = yaml.safe_load(f)
108
+
109
+ if "chemistry" in data and mineral_name not in Phyllosilicates._formula_cache:
110
+ self._compile_chemistry_formulas(mineral_name, data["chemistry"])
111
+
112
+ # 3) Cache schreiben
113
+ Phyllosilicates._yaml_cache[mineral_name] = data
114
+
115
+ return data
116
+
117
+ def _get_value(self, data: dict, path: list[str], default=None):
118
+ """Safely extract a float or string value from nested YAML data."""
119
+ try:
120
+ for key in path:
121
+ data = data[key]
122
+ if isinstance(data, dict) and "value" in data:
123
+ return float(data["value"])
124
+ else:
125
+ return data # kann z.B. ein String oder eine Zahl sein
126
+ except (KeyError, TypeError):
127
+ return default
128
+
129
+ def _get_variables(self):
130
+ if self.name == "Glauconite":
131
+ x = round(self.rng.uniform(0, 1), 2)
132
+ y1 = round(self.rng.uniform(0, 1), 2)
133
+ y2 = round(self.rng.uniform(0, 1 - y1), 2)
134
+ z = round(self.rng.uniform(0, 1), 2)
135
+ return {"x": x, "y1": y1, "y2": y2, "z": z}
136
+ elif self.name == "Vermiculite":
137
+ x = round(self.rng.uniform(0, 1), 2)
138
+ y = round(self.rng.uniform(0, (1 - x)), 2)
139
+ z = round(self.rng.uniform(0, 1), 2)
140
+ return {"x": x, "y": y, "z": z}
141
+ elif self.name == "Chlorite":
142
+ x = round(self.rng.uniform(0, 1), 2)
143
+ y = round(self.rng.uniform(0, (1 - x)), 2)
144
+ upper = max(0, (1 - x - y))
145
+ z = round(self.rng.uniform(0, upper), 2)
146
+ return {"x": x, "y": y, "z": z}
147
+ else:
148
+ if "variables" not in self.yaml_data:
149
+ return {}
150
+ vars = {}
151
+ for k, v in self.yaml_data["variables"].items():
152
+ if isinstance(v[0], int):
153
+ vars[k] = self.rng.integers(v[0], v[1])
154
+ else:
155
+ vars[k] = round(self.rng.uniform(v[0], v[1]), 2)
156
+ return vars
157
+
158
+ def generate_dataset(self, number: int = 1, as_dataframe=False) -> None:
159
+ fixed = {
160
+ "Annite", "Eastonite", "Illite", "Kaolinite", "Phlogopite", "Siderophyllite",
161
+ "Chamosite", "Clinochlore", "Pennantite", "Nimite", "Muscovite",
162
+ "Talc", "Chrysotile", "Antigorite", "Pyrophyllite", "FeChlorite", "MgChlorite", "MnChlorite", "NiChlorite"}
163
+ variable = {"Montmorillonite", "Nontronite", "Saponite", "Glauconite", "Vermiculite"}
164
+ endmember = {"Biotite", "Chlorite"}
165
+ generators = {
166
+ **{m: MinGen(
167
+ name=self.name, yaml_data=self.yaml_data, elements=self.elements, cache=self.cache,
168
+ geophysical_properties=self.geophysical_properties, rounding=self.rounding
169
+ ).create_mineral_data_fixed_composition for m in fixed},
170
+ **{m: self.create_mineral_data_variable_composition for m in variable},
171
+ **{m: self.create_mineral_data_endmember_series for m in endmember},
172
+ }
173
+
174
+ if self.name not in generators:
175
+ raise ValueError(f"Mineral '{self.name}' not recognized.")
176
+
177
+ dataset = {}
178
+ if self.name in fixed:
179
+ dataset = self._evaluate_mineral(index=1, generators=generators, dataset=dataset)
180
+ else:
181
+ for index in range(number):
182
+ dataset = self._evaluate_mineral(index=index, generators=generators, dataset=dataset)
183
+
184
+ if as_dataframe:
185
+ import pandas as pd
186
+ return pd.DataFrame(dataset)
187
+ else:
188
+ return dataset
189
+
190
+ def _evaluate_mineral(self, index, generators, dataset):
191
+ self.current_seed = np.uint32(self.random_seed + index)
192
+ data_mineral = generators[self.name]()
193
+
194
+ for key, value in data_mineral.items():
195
+ if key in ["M", "rho", "rho_e", "V", "vP", "vS", "vP/vS", "K", "G", "E", "nu", "GR", "PE", "U",
196
+ "p"]:
197
+ if key not in dataset:
198
+ dataset[key] = [value]
199
+ else:
200
+ dataset[key].append(value)
201
+ elif key in ["mineral", "state", "trace elements"] and key not in dataset:
202
+ dataset[key] = value
203
+ elif key in ["chemistry", "compounds"]:
204
+ if key not in dataset:
205
+ dataset[key] = {}
206
+ for key_2, value_2 in value.items():
207
+ dataset[key][key_2] = [value_2]
208
+ else:
209
+ for key_2, value_2 in value.items():
210
+ dataset[key][key_2].append(value_2)
211
+ return dataset
212
+
213
+ def _compile_chemistry_formulas(self, mineral_name: str, chemistry_dict: dict):
214
+ """
215
+ Extracts and compiles all chemistry formulas from the YAML file.
216
+ Stores the compiled ASTs in the global formula cache.
217
+ """
218
+
219
+ compiled = {}
220
+
221
+ for element, entry in chemistry_dict.items():
222
+
223
+ # Fall A: Einfache Zahl (z.B. 2, 3.5)
224
+ if isinstance(entry, (int, float)):
225
+ expr = str(entry)
226
+ # Fall B: dict mit 'formula'
227
+ elif isinstance(entry, dict) and "formula" in entry:
228
+ expr = str(entry["formula"])
229
+ # Fall C: Alles andere ist invalid
230
+ else:
231
+ raise ValueError(
232
+ f"Invalid chemistry entry for element '{element}' in {mineral_name}.yaml: {entry}")
233
+ # AST kompilieren
234
+ compiled[element] = self.ae.parse(expr)
235
+ # Cache schreiben
236
+ Phyllosilicates._formula_cache[mineral_name] = compiled
237
+
238
+ def _evaluate_chemistry(self, chemistry_dict, **variables):
239
+ """
240
+ Evaluates algebraic expressions of element amounts defined in the YAML file.
241
+
242
+ Parameters:
243
+ chemistry_dict (dict): Dictionary from YAML containing element formulas as strings.
244
+ **variables: Variable assignments (e.g. x=0.5, y=1, n=8)
245
+
246
+ Returns:
247
+ dict: {element: calculated_amount}
248
+ """
249
+ self.ae.symtable.clear()
250
+
251
+ # Variablen setzen
252
+ for k, v in variables.items():
253
+ self.ae.symtable[k] = v
254
+
255
+ results = {}
256
+ compiled = Phyllosilicates._formula_cache[self.name.lower()]
257
+
258
+ for el in chemistry_dict:
259
+ results[el] = self.ae.run(compiled[el])
260
+
261
+ return results
262
+
263
+ def _extract_values_from_yaml(self):
264
+ vals = {}
265
+ # Physical parameters
266
+ for key in ["K", "G", "a_K", "b_K", "a_G", "b_G"]:
267
+ if key in self.yaml_data.get("physical_properties", {}):
268
+ vals[key] = float(self.yaml_data["physical_properties"][key]["value"])
269
+ # Cell parameters
270
+ for key in ["a", "b", "c", "alpha", "beta", "gamma", "Z"]:
271
+ if key in self.yaml_data.get("cell_data", {}):
272
+ vals[key] = float(self.yaml_data["cell_data"][key]["value"])
273
+ # Meta data
274
+ vals["key"] = self.yaml_data["metadata"]["key"]
275
+ vals["crystal_system"] = self.yaml_data["metadata"]["crystal_system"]
276
+
277
+ return vals
278
+
279
+ def _determine_majors_data(self):
280
+ majors_data = []
281
+ molar_mass_pure = 0
282
+ vars = self._get_variables()
283
+ amounts_elements = self._evaluate_chemistry(self.yaml_data["chemistry"], **vars)
284
+ for element, amount in amounts_elements.items():
285
+ n_order = int(self.elements[element][1])
286
+ val_amount = float(amount)
287
+ molar_mass = float(self.elements[element][2])
288
+ majors_data.append([element, n_order, val_amount, molar_mass])
289
+ molar_mass_pure += val_amount*molar_mass
290
+ majors_data.sort(key=lambda x: x[1])
291
+ return majors_data, amounts_elements, molar_mass_pure, vars
292
+
293
+ def _calculate_molar_mass_amounts(self, amounts_elements):
294
+ molar_mass = 0
295
+ for element, amount in amounts_elements.items():
296
+ molar_mass += amount*float(self.elements[element][2])
297
+
298
+ amounts = []
299
+ for element, amount in amounts_elements.items():
300
+ value = amount*float(self.elements[element][2])/molar_mass
301
+ amounts.append([element, self.elements[element][1], value])
302
+ element = [self.elements[name] for name, *_ in amounts]
303
+ return molar_mass, amounts, element
304
+
305
+ def _determine_volume_constructor(self, vals):
306
+ val_a = vals["a"]
307
+ val_system = vals["crystal_system"]
308
+ if val_system in ["isometric", "cubic"]:
309
+ constr_vol = CrystalPhysics([[val_a], [], val_system])
310
+ elif val_system in ["tetragonal", "hexagonal", "trigonal"]:
311
+ val_c = vals["c"]
312
+ constr_vol = CrystalPhysics([[val_a, val_c], [], val_system])
313
+ elif val_system in ["orthorhombic"]:
314
+ val_b = vals["b"]
315
+ val_c = vals["c"]
316
+ constr_vol = CrystalPhysics([[val_a, val_b, val_c], [], val_system])
317
+ elif val_system in ["monoclinic"]:
318
+ val_b = vals["b"]
319
+ val_c = vals["c"]
320
+ val_beta = vals["beta"]
321
+ constr_vol = CrystalPhysics([[val_a, val_b, val_c], [val_beta], val_system])
322
+ elif val_system in ["triclinic"]:
323
+ val_b = vals["b"]
324
+ val_c = vals["c"]
325
+ val_alpha = vals["alpha"]
326
+ val_beta = vals["beta"]
327
+ val_gamma = vals["gamma"]
328
+ constr_vol = CrystalPhysics([[val_a, val_b, val_c], [val_alpha, val_beta, val_gamma], val_system])
329
+ return constr_vol
330
+
331
+ def create_mineral_data_variable_composition(self):
332
+ """
333
+ Synthetic mineral data generation for an user-selected mineral.
334
+ All mechanical properties (K, G, E) are stored in Pascals internally.
335
+ For output, they are converted to GPa.
336
+ """
337
+ name_lower = self.name.lower()
338
+ # Chemistry
339
+ val_state = "variable"
340
+ traces_data = []
341
+ # Molar mass, elemental amounts
342
+ majors_data, amounts_elements, molar_mass_pure, vars = self._determine_majors_data()
343
+
344
+ if name_lower not in self.cache:
345
+ vals = self._extract_values_from_yaml()
346
+ self.cache[name_lower] = {"constants": vals}
347
+ else:
348
+ vals = self.cache[name_lower]["constants"]
349
+ constr_vol = self.cache[name_lower]["constr_vol"]
350
+
351
+ # Molar mass, element amounts
352
+ molar_mass, amounts, element = self._calculate_molar_mass_amounts(amounts_elements=amounts_elements)
353
+
354
+ # Reading and assigning the mineral-specific information from the YAML file
355
+ val_key = vals["key"]
356
+ val_Z = vals["Z"]
357
+ if "K" in vals:
358
+ val_K = vals["K"]
359
+ val_G = vals["G"]
360
+ else:
361
+ val_a_K = float(vals["a_K"])
362
+ val_b_K = float(vals["b_K"])
363
+ val_a_G = float(vals["a_G"])
364
+ val_b_G = float(vals["b_G"])
365
+
366
+ # (Molar) Volume
367
+ if "constr_vol" not in self.cache[name_lower]:
368
+ constr_vol = self._determine_volume_constructor(vals=vals)
369
+ self.cache[name_lower]["constr_vol"] = constr_vol
370
+
371
+ constr_minchem = MineralChemistry(w_traces=traces_data, molar_mass_pure=molar_mass_pure, majors=majors_data)
372
+ V, V_m = self.crystallographic_properties.calculate_molar_volume(
373
+ constr_volume=constr_vol, constr_molar_volume=constr_minchem, cell_z=val_Z)
374
+ # Density
375
+ constr_density = CrystalPhysics([molar_mass, val_Z, V])
376
+ rho = self.crystallographic_properties.calculate_mineral_density(constr_density=constr_density)
377
+ constr_electr_density = wg(amounts=amounts, elements=element, rho_b=rho)
378
+ rho_e = self.crystallographic_properties.calculate_electron_density(
379
+ constr_electron_density=constr_electr_density)
380
+
381
+ # Elastic properties
382
+ if "K" not in vals:
383
+ val_K = (val_a_K*rho + val_b_K)*10**9
384
+ val_G = (val_a_G*rho + val_b_G)*10**9
385
+ E, nu = self.geophysical_properties.calculate_elastic_properties(bulk_mod=val_K, shear_mod=val_G)
386
+ # Seismic properties
387
+ vPvS, vP, vS = self.geophysical_properties.calculate_seismic_velocities(
388
+ bulk_mod=val_K, shear_mod=val_G, rho=rho)
389
+ # Radiation properties
390
+ constr_radiation = wg(amounts=amounts, elements=element)
391
+ gamma_ray, pe, U = self.geophysical_properties.calculate_radiation_properties(
392
+ constr_radiation=constr_radiation, rho_electron=rho_e)
393
+ # Electrical resistivity
394
+ p = None
395
+ # Results
396
+ results = {
397
+ "mineral": val_key, "state": val_state, "M": round(molar_mass, self.rounding),
398
+ "chemistry": {name: round(val[1], 6) for name, *val in amounts}, "rho": round(rho, self.rounding),
399
+ "rho_e": round(rho_e, self.rounding), "V": round(V_m, self.rounding), "vP": round(vP, self.rounding),
400
+ "vS": round(vS, self.rounding), "vP/vS": round(vPvS, self.rounding),
401
+ "K": round(val_K*10**(-9), self.rounding), "G": round(val_G*10**(-9), self.rounding),
402
+ "E": round(E*10**(-9), self.rounding), "nu": round(nu, 6), "GR": round(gamma_ray, self.rounding),
403
+ "PE": round(pe, self.rounding), "U": round(U, self.rounding), "p": p}
404
+ return results
405
+
406
+ def create_mineral_data_endmember_series(self):
407
+ """
408
+ Synthetic mineral data generation for an user-selected mineral.
409
+ All mechanical properties (K, G, E) are stored in Pascals internally.
410
+ For output, they are converted to GPa.
411
+ """
412
+ endmember_series = {
413
+ "Biotite": {
414
+ "name_lower": "biotite",
415
+ "key": "Bt",
416
+ "endmembers": ["Annite", "Phlogopite", "Siderophyllite", "Eastonite"],
417
+ "oxides": ["K2O", "FeO", "MgO", "Al2O3", "SiO2", "H2O"]
418
+ },
419
+ "Chlorite": {
420
+ "name_lower": "chlorite",
421
+ "key": "Bt",
422
+ "endmembers": ["FeChlorite", "MgChlorite", "MnChlorite", "NiChlorite"],
423
+ "oxides": ["FeO", "MgO", "MnO", "NiO", "Al2O3", "SiO2", "H2O"]
424
+ }
425
+ }
426
+ results = MinGen(
427
+ name=self.name, yaml_data=self.yaml_data, elements=self.elements, cache=self.cache,
428
+ geophysical_properties=self.geophysical_properties,
429
+ rounding=self.rounding).create_mineral_data_endmember_series(
430
+ endmember_series=endmember_series, var_class=Phyllosilicates, current_seed=self.current_seed, rng=self.rng)
431
+
432
+ return results
433
+
434
+ # TEST
435
+ if __name__ == "__main__":
436
+ DEFAULT_DATA = Phyllosilicates(name="Annite", random_seed=42).generate_dataset(number=10)
File without changes
File without changes