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