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,589 @@
1
+ #!/usr/bin/env python
2
+ # -*-coding: utf-8 -*-
3
+
4
+ #-----------------------------------------------
5
+
6
+ # Name: oxides.py
7
+ # Author: Maximilian A. Beeskow
8
+ # Version: 1.0
9
+ # Date: 15.12.2025
10
+
11
+ #-----------------------------------------------
12
+
13
+ """
14
+ Module: oxides.py
15
+ This module controls the generation of the synthetic data of the oxides minerals.
16
+ """
17
+
18
+ # PACKAGES
19
+ import yaml
20
+ import numpy as np
21
+ import pandas as pd
22
+ from pathlib import Path
23
+
24
+ from soupsieve.util import lower
25
+ from asteval import Interpreter
26
+
27
+ # MODULES
28
+ from ..chemistry.common import PeriodicSystem
29
+ from ..chemistry.geochemistry import MineralChemistry
30
+ from ..physics.geophysics import WellLog as wg
31
+
32
+ from .common import (
33
+ GeophysicalProperties,
34
+ CrystallographicProperties,
35
+ CrystalPhysics,
36
+ MineralGeneration as MinGen
37
+ )
38
+
39
+ # CODE
40
+ BASE_PATH = Path(__file__).resolve().parents[2]
41
+ DATA_PATH = BASE_PATH / "data_minerals"
42
+
43
+ class Oxides:
44
+ _yaml_cache = {}
45
+ _formula_cache = {}
46
+ _minerals = {
47
+ "Anatase", "Arsenolite", "Au3Oxide", "Bismite", "Boehmite", "Brookite", "Brucite", "Cassiterite", "Chromite",
48
+ "Claudetite", "Cochromite", "Corundum", "Crocoite", "Cuprite", "Cuprospinel", "Diaspore", "Ferberite",
49
+ "Franklinite", "Geikielite", "Gibbsite", "Goethite", "Groutite", "Hematite", "Huebnerite", "Ilmenite",
50
+ "Jacobsite", "Litharge", "Magnesiochromite", "Magnesioferrite", "Magnetite", "Manganite", "Manganochromite",
51
+ "Massicot", "Minium", "Nichromite", "Plattnerite", "Pyrolusite", "Pyrophanite", "Quartz", "Rutile",
52
+ "Scrutinyite", "Senarmontite", "Spinel", "Trevorite", "Ulvospinel", "Uraninite", "Valentinite", "Wulfenite",
53
+ "Zincite", "Zincochromite", "Eskolaite", "Karelianite", "Galaxite", "Gahnite", "Hercynite", "Tistarite",
54
+ "FeColumbite", "MgColumbite", "MnColumbite", "FeTantalite", "MgTantalite", "MnTantalite", "Argutite",
55
+ "Paratellurite", "Stishovite", "Baddeleyite", "Bunsenite", "Periclase", "Manganosite", "Monteponite", "Lime",
56
+ "Wustite", "Avicennite", "Stolzite", "Scheelite", "Powellite", "Al-Spinel", "Cr-Spinel", "Fe-Spinel", "Coltan",
57
+ "Columbite", "Wolframite", "Tantalite", "Corundum-Group", "Chromite-Group", "Ilmenite-Group", "Rutile-Group",
58
+ "Periclase-Group", "Wulfenite-Group", "Scheelite-Group", "Diaspore-Group"}
59
+
60
+ def __init__(self, name, random_seed, rounding: int = 3) -> None:
61
+ self.name = name
62
+ self.random_seed = random_seed
63
+ self.rng = np.random.default_rng(random_seed)
64
+ self.current_seed = int(np.round(self.rng.uniform(0, 1000), 0))
65
+ self.data_path = DATA_PATH
66
+ self.rounding = rounding
67
+ self.ae = Interpreter()
68
+ self.cache = {}
69
+
70
+ # Chemistry
71
+ self.elements = {
72
+ "H": PeriodicSystem(name="H").get_data(),
73
+ "O": PeriodicSystem(name="O").get_data(),
74
+ "Mg": PeriodicSystem(name="Mg").get_data(),
75
+ "Al": PeriodicSystem(name="Al").get_data(),
76
+ "Si": PeriodicSystem(name="Si").get_data(),
77
+ "K": PeriodicSystem(name="K").get_data(),
78
+ "Ca": PeriodicSystem(name="Ca").get_data(),
79
+ "Ti": PeriodicSystem(name="Ti").get_data(),
80
+ "V": PeriodicSystem(name="V").get_data(),
81
+ "Mn": PeriodicSystem(name="Mn").get_data(),
82
+ "Cr": PeriodicSystem(name="Cr").get_data(),
83
+ "Fe": PeriodicSystem(name="Fe").get_data(),
84
+ "Co": PeriodicSystem(name="Co").get_data(),
85
+ "Ni": PeriodicSystem(name="Ni").get_data(),
86
+ "Cu": PeriodicSystem(name="Cu").get_data(),
87
+ "Zn": PeriodicSystem(name="Zn").get_data(),
88
+ "Ge": PeriodicSystem(name="Ge").get_data(),
89
+ "As": PeriodicSystem(name="As").get_data(),
90
+ "Zr": PeriodicSystem(name="Zr").get_data(),
91
+ "Nb": PeriodicSystem(name="Nb").get_data(),
92
+ "Mo": PeriodicSystem(name="Mo").get_data(),
93
+ "Cd": PeriodicSystem(name="Cd").get_data(),
94
+ "Sn": PeriodicSystem(name="Sn").get_data(),
95
+ "Sb": PeriodicSystem(name="Sb").get_data(),
96
+ "Te": PeriodicSystem(name="Te").get_data(),
97
+ "Ta": PeriodicSystem(name="Ta").get_data(),
98
+ "W": PeriodicSystem(name="W").get_data(),
99
+ "Au": PeriodicSystem(name="Au").get_data(),
100
+ "Tl": PeriodicSystem(name="Tl").get_data(),
101
+ "Pb": PeriodicSystem(name="Pb").get_data(),
102
+ "Bi": PeriodicSystem(name="Bi").get_data(),
103
+ "U": PeriodicSystem(name="U").get_data(),
104
+ }
105
+
106
+ # Geophysics
107
+ self.geophysical_properties = GeophysicalProperties()
108
+ # Crystallography
109
+ self.crystallographic_properties = CrystallographicProperties()
110
+
111
+ # Mineral-specific data
112
+ if self.name in [
113
+ "Anatase", "Arsenolite", "Au3Oxide", "Bismite", "Boehmite", "Brookite", "Brucite",
114
+ "Cassiterite", "Chromite", "Claudetite", "Cochromite", "Corundum", "Crocoite", "Cuprite",
115
+ "Cuprospinel", "Diaspore", "Ferberite", "Franklinite", "Geikielite", "Gibbsite", "Goethite", "Groutite",
116
+ "Hematite", "Huebnerite", "Ilmenite", "Jacobsite", "Litharge", "Magnesiochromite",
117
+ "Magnesioferrite", "Magnetite", "Manganite", "Manganochromite", "Massicot", "Minium", "Nichromite",
118
+ "Plattnerite", "Pyrolusite", "Pyrophanite", "Quartz", "Rutile", "Scrutinyite", "Senarmontite",
119
+ "Spinel", "Trevorite", "Ulvospinel", "Uraninite", "Valentinite", "Wulfenite", "Zincite",
120
+ "Zincochromite", "Eskolaite", "Karelianite", "Galaxite", "Gahnite", "Hercynite", "Tistarite",
121
+ "FeColumbite", "MgColumbite", "MnColumbite", "FeTantalite", "MgTantalite", "MnTantalite", "Argutite",
122
+ "Paratellurite", "Stishovite", "Baddeleyite", "Bunsenite", "Periclase", "Manganosite", "Monteponite",
123
+ "Lime", "Wustite", "Avicennite", "Stolzite", "Scheelite", "Powellite"]:
124
+ self.yaml_data = self._load_yaml(lower(self.name))
125
+ if self.name == "Al-Spinel":
126
+ self.yaml_data = {
127
+ mineral.lower(): self._load_yaml(mineral.lower())
128
+ for mineral in ["Spinel", "Hercynite", "Gahnite", "Galaxite"]}
129
+ if self.name == "Cr-Spinel":
130
+ self.yaml_data = {
131
+ mineral.lower(): self._load_yaml(mineral.lower())
132
+ for mineral in ["Chromite", "Zincochromite", "Magnesiochromite"]}
133
+ if self.name == "Fe-Spinel":
134
+ self.yaml_data = {
135
+ mineral.lower(): self._load_yaml(mineral.lower())
136
+ for mineral in [
137
+ "Magnetite", "Cuprospinel", "Jacobsite", "Magnesioferrite", "Trevorite", "Franklinite"]}
138
+ if self.name == "Wolframite":
139
+ self.yaml_data = {
140
+ mineral.lower(): self._load_yaml(mineral.lower())
141
+ for mineral in ["Huebnerite", "Ferberite"]}
142
+ if self.name == "Corundum-Group":
143
+ self.yaml_data = {
144
+ mineral.lower(): self._load_yaml(mineral.lower())
145
+ for mineral in ["Corundum", "Hematite", "Eskolaite", "Karelianite", "Tistarite"]}
146
+ if self.name == "Chromite-Group":
147
+ self.yaml_data = {
148
+ mineral.lower(): self._load_yaml(mineral.lower())
149
+ for mineral in ["Chromite", "Manganochromite", "Nichromite", "Cochromite", "Zincochromite"]}
150
+ if self.name == "Ilmenite-Group":
151
+ self.yaml_data = {
152
+ mineral.lower(): self._load_yaml(mineral.lower())
153
+ for mineral in ["Ilmenite", "Geikielite", "Pyrophanite"]}
154
+ if self.name == "Rutile-Group":
155
+ self.yaml_data = {
156
+ mineral.lower(): self._load_yaml(mineral.lower())
157
+ for mineral in ["Rutile", "Pyrolusite", "Cassiterite", "Plattnerite", "Argutite", "Stishovite"]}
158
+ if self.name == "Columbite":
159
+ self.yaml_data = {
160
+ mineral.lower(): self._load_yaml(mineral.lower())
161
+ for mineral in ["FeColumbite", "MgColumbite", "MnColumbite"]}
162
+ if self.name == "Tantalite":
163
+ self.yaml_data = {
164
+ mineral.lower(): self._load_yaml(mineral.lower())
165
+ for mineral in ["FeTantalite", "MgTantalite", "MnTantalite"]}
166
+ if self.name == "Coltan":
167
+ self.yaml_data = {
168
+ mineral.lower(): self._load_yaml(mineral.lower())
169
+ for mineral in ["FeColumbite", "MgColumbite", "MnColumbite", "FeTantalite", "MgTantalite",
170
+ "MnTantalite"]}
171
+ if self.name == "Periclase-Group":
172
+ self.yaml_data = {
173
+ mineral.lower(): self._load_yaml(mineral.lower())
174
+ for mineral in ["Periclase", "Bunsenite", "Manganosite", "Monteponite", "Lime", "Wustite"]}
175
+ if self.name == "Wulfenite-Group":
176
+ self.yaml_data = {
177
+ mineral.lower(): self._load_yaml(mineral.lower())
178
+ for mineral in ["Wulfenite", "Stolzite"]}
179
+ if self.name == "Scheelite-Group":
180
+ self.yaml_data = {
181
+ mineral.lower(): self._load_yaml(mineral.lower())
182
+ for mineral in ["Scheelite", "Powellite"]}
183
+ if self.name == "Diaspore-Group":
184
+ self.yaml_data = {
185
+ mineral.lower(): self._load_yaml(mineral.lower())
186
+ for mineral in ["Diaspore", "Goethite", "Groutite"]}
187
+
188
+ def _load_yaml(self, mineral_name: str) -> dict:
189
+ # 1) Cache-Hit
190
+ if mineral_name in Oxides._yaml_cache:
191
+ return Oxides._yaml_cache[mineral_name]
192
+
193
+ # 2) Laden von Disk
194
+ yaml_file = self.data_path/f"{mineral_name}.yaml"
195
+ if not yaml_file.exists():
196
+ raise FileNotFoundError(f"No YAML file found for {mineral_name}.")
197
+
198
+ with open(yaml_file, "r") as f:
199
+ data = yaml.safe_load(f)
200
+
201
+ if "chemistry" in data and mineral_name not in Oxides._formula_cache:
202
+ self._compile_chemistry_formulas(mineral_name, data["chemistry"])
203
+
204
+ # 3) Cache schreiben
205
+ Oxides._yaml_cache[mineral_name] = data
206
+
207
+ return data
208
+
209
+ def _get_value(self, data: dict, path: list[str], default=None):
210
+ """Safely extract a float or string value from nested YAML data."""
211
+ try:
212
+ for key in path:
213
+ data = data[key]
214
+ if isinstance(data, dict) and "value" in data:
215
+ return float(data["value"])
216
+ else:
217
+ return data # kann z.B. ein String oder eine Zahl sein
218
+ except (KeyError, TypeError):
219
+ return default
220
+
221
+ def generate_dataset(self, number: int = 1, as_dataframe=False) -> None:
222
+ fixed = {
223
+ "Anatase", "Arsenolite", "Au3Oxide", "Bismite", "Boehmite", "Brookite", "Brucite", "Cassiterite",
224
+ "Chromite", "Claudetite", "Cochromite", "Corundum", "Crocoite", "Cuprite", "Cuprospinel", "Diaspore",
225
+ "Ferberite", "Franklinite", "Geikielite", "Gibbsite", "Goethite", "Groutite", "Hematite", "Huebnerite",
226
+ "Ilmenite", "Jacobsite", "Litharge", "Magnesiochromite", "Magnesioferrite", "Magnetite", "Manganite",
227
+ "Manganochromite", "Massicot", "Minium", "Nichromite", "Plattnerite", "Pyrolusite", "Pyrophanite",
228
+ "Quartz", "Rutile", "Scrutinyite", "Senarmontite", "Sphaerobismite", "Spinel", "Trevorite", "Ulvospinel",
229
+ "Uraninite", "Valentinite", "Wulfenite", "Zincite", "Zincochromite", "Eskolaite",
230
+ "Karelianite", "Galaxite", "Gahnite", "Hercynite", "Tistarite", "FeColumbite", "MgColumbite", "MnColumbite",
231
+ "FeTantalite", "MgTantalite", "MnTantalite", "Argutite", "Paratellurite", "Stishovite", "Baddeleyite",
232
+ "Bunsenite", "Periclase", "Manganosite", "Monteponite", "Lime", "Wustite", "Avicennite", "Stolzite",
233
+ "Scheelite", "Powellite"}
234
+ variable = {}
235
+ endmember = {
236
+ "Al-Spinel", "Cr-Spinel", "Fe-Spinel", "Coltan", "Columbite", "Wolframite", "Tantalite", "Corundum-Group",
237
+ "Chromite-Group", "Ilmenite-Group", "Rutile-Group", "Periclase-Group", "Wulfenite-Group", "Scheelite-Group",
238
+ "Diaspore-Group"}
239
+
240
+ generators = {
241
+ **{m: MinGen(
242
+ name=self.name, yaml_data=self.yaml_data, elements=self.elements, cache=self.cache,
243
+ geophysical_properties=self.geophysical_properties, rounding=self.rounding
244
+ ).create_mineral_data_fixed_composition for m in fixed},
245
+ **{m: self.create_mineral_data_variable_composition for m in variable},
246
+ **{m: self.create_mineral_data_endmember_series for m in endmember},
247
+ }
248
+
249
+ if self.name not in generators:
250
+ raise ValueError(f"Mineral '{self.name}' not recognized.")
251
+
252
+ dataset = {}
253
+ if self.name in fixed:
254
+ dataset = self._evaluate_mineral(index=1, generators=generators, dataset=dataset)
255
+ else:
256
+ for index in range(number):
257
+ dataset = self._evaluate_mineral(index=index, generators=generators, dataset=dataset)
258
+
259
+ if as_dataframe:
260
+ return pd.DataFrame(dataset)
261
+ else:
262
+ return dataset
263
+
264
+ def _evaluate_mineral(self, index, generators, dataset):
265
+ self.current_seed = np.uint32(self.random_seed + index)
266
+ data_mineral = generators[self.name]()
267
+
268
+ for key, value in data_mineral.items():
269
+ if key in ["M", "rho", "rho_e", "V", "vP", "vS", "vP/vS", "K", "G", "E", "nu", "GR", "PE", "U",
270
+ "p"]:
271
+ if key not in dataset:
272
+ dataset[key] = [value]
273
+ else:
274
+ dataset[key].append(value)
275
+ elif key in ["mineral", "state", "trace elements"] and key not in dataset:
276
+ dataset[key] = value
277
+ elif key in ["chemistry", "compounds"]:
278
+ if key not in dataset:
279
+ dataset[key] = {}
280
+ for key_2, value_2 in value.items():
281
+ dataset[key][key_2] = [value_2]
282
+ else:
283
+ for key_2, value_2 in value.items():
284
+ dataset[key][key_2].append(value_2)
285
+ return dataset
286
+
287
+ def _compile_chemistry_formulas(self, mineral_name: str, chemistry_dict: dict):
288
+ """
289
+ Extracts and compiles all chemistry formulas from the YAML file.
290
+ Stores the compiled ASTs in the global formula cache.
291
+ """
292
+
293
+ compiled = {}
294
+
295
+ for element, entry in chemistry_dict.items():
296
+
297
+ # Fall A: Einfache Zahl (z.B. 2, 3.5)
298
+ if isinstance(entry, (int, float)):
299
+ expr = str(entry)
300
+ # Fall B: dict mit 'formula'
301
+ elif isinstance(entry, dict) and "formula" in entry:
302
+ expr = str(entry["formula"])
303
+ # Fall C: Alles andere ist invalid
304
+ else:
305
+ raise ValueError(
306
+ f"Invalid chemistry entry for element '{element}' in {mineral_name}.yaml: {entry}")
307
+ # AST kompilieren
308
+ compiled[element] = self.ae.parse(expr)
309
+ # Cache schreiben
310
+ Oxides._formula_cache[mineral_name] = compiled
311
+
312
+ def _evaluate_chemistry(self, chemistry_dict, **variables):
313
+ """
314
+ Evaluates algebraic expressions of element amounts defined in the YAML file.
315
+
316
+ Parameters:
317
+ chemistry_dict (dict): Dictionary from YAML containing element formulas as strings.
318
+ **variables: Variable assignments (e.g. x=0.5, y=1, n=8)
319
+
320
+ Returns:
321
+ dict: {element: calculated_amount}
322
+ """
323
+ self.ae.symtable.clear()
324
+
325
+ # Variablen setzen
326
+ for k, v in variables.items():
327
+ self.ae.symtable[k] = v
328
+
329
+ results = {}
330
+ compiled = Oxides._formula_cache[self.name.lower()]
331
+
332
+ for el in chemistry_dict:
333
+ results[el] = self.ae.run(compiled[el])
334
+
335
+ return results
336
+
337
+ def _extract_values_from_yaml(self):
338
+ vals = {}
339
+ # Physical parameters
340
+ for key in ["K", "G", "a_K", "b_K", "a_G", "b_G"]:
341
+ if key in self.yaml_data.get("physical_properties", {}):
342
+ vals[key] = float(self.yaml_data["physical_properties"][key]["value"])
343
+ # Cell parameters
344
+ for key in ["a", "b", "c", "alpha", "beta", "gamma", "Z"]:
345
+ if key in self.yaml_data.get("cell_data", {}):
346
+ vals[key] = float(self.yaml_data["cell_data"][key]["value"])
347
+ # Meta data
348
+ vals["key"] = self.yaml_data["metadata"]["key"]
349
+ vals["crystal_system"] = self.yaml_data["metadata"]["crystal_system"]
350
+
351
+ return vals
352
+
353
+ def _determine_majors_data(self):
354
+ majors_data = []
355
+ molar_mass_pure = 0
356
+ vars = self._get_variables()
357
+ amounts_elements = self._evaluate_chemistry(self.yaml_data["chemistry"], **vars)
358
+ for element, amount in amounts_elements.items():
359
+ n_order = int(self.elements[element][1])
360
+ val_amount = float(amount)
361
+ molar_mass = float(self.elements[element][2])
362
+ majors_data.append([element, n_order, val_amount, molar_mass])
363
+ molar_mass_pure += val_amount*molar_mass
364
+ majors_data.sort(key=lambda x: x[1])
365
+ return majors_data, amounts_elements, molar_mass_pure, vars
366
+
367
+ def _calculate_molar_mass_amounts(self, amounts_elements):
368
+ molar_mass = 0
369
+ for element, amount in amounts_elements.items():
370
+ molar_mass += amount*float(self.elements[element][2])
371
+
372
+ amounts = []
373
+ for element, amount in amounts_elements.items():
374
+ value = amount*float(self.elements[element][2])/molar_mass
375
+ amounts.append([element, self.elements[element][1], value])
376
+ element = [self.elements[name] for name, *_ in amounts]
377
+ return molar_mass, amounts, element
378
+
379
+ def _determine_volume_constructor(self, vals):
380
+ val_a = vals["a"]
381
+ val_system = vals["crystal_system"]
382
+ if val_system in ["isometric", "cubic"]:
383
+ constr_vol = CrystalPhysics([[val_a], [], val_system])
384
+ elif val_system in ["tetragonal", "hexagonal", "trigonal"]:
385
+ val_c = vals["c"]
386
+ constr_vol = CrystalPhysics([[val_a, val_c], [], val_system])
387
+ elif val_system in ["orthorhombic"]:
388
+ val_b = vals["b"]
389
+ val_c = vals["c"]
390
+ constr_vol = CrystalPhysics([[val_a, val_b, val_c], [], val_system])
391
+ elif val_system in ["monoclinic"]:
392
+ val_b = vals["b"]
393
+ val_c = vals["c"]
394
+ val_beta = vals["beta"]
395
+ constr_vol = CrystalPhysics([[val_a, val_b, val_c], [val_beta], val_system])
396
+ elif val_system in ["triclinic"]:
397
+ val_b = vals["b"]
398
+ val_c = vals["c"]
399
+ val_alpha = vals["alpha"]
400
+ val_beta = vals["beta"]
401
+ val_gamma = vals["gamma"]
402
+ constr_vol = CrystalPhysics([[val_a, val_b, val_c], [val_alpha, val_beta, val_gamma], val_system])
403
+ return constr_vol
404
+
405
+ def create_mineral_data_variable_composition(self):
406
+ """
407
+ Synthetic mineral data generation for an user-selected mineral.
408
+ All mechanical properties (K, G, E) are stored in Pascals internally.
409
+ For output, they are converted to GPa.
410
+ """
411
+ name_lower = self.name.lower()
412
+ # Chemistry
413
+ val_state = "variable"
414
+ traces_data = []
415
+ # Molar mass, elemental amounts
416
+ majors_data, amounts_elements, molar_mass_pure, vars = self._determine_majors_data()
417
+
418
+ if name_lower not in self.cache:
419
+ vals = self._extract_values_from_yaml()
420
+ self.cache[name_lower] = {"constants": vals}
421
+ else:
422
+ vals = self.cache[name_lower]["constants"]
423
+ constr_vol = self.cache[name_lower]["constr_vol"]
424
+
425
+ # Molar mass, element amounts
426
+ molar_mass, amounts, element = self._calculate_molar_mass_amounts(amounts_elements=amounts_elements)
427
+
428
+ # Reading and assigning the mineral-specific information from the YAML file
429
+ val_key = vals["key"]
430
+ val_Z = vals["Z"]
431
+ if "K" in vals:
432
+ val_K = vals["K"]
433
+ val_G = vals["G"]
434
+ else:
435
+ val_a_K = float(vals["a_K"])
436
+ val_b_K = float(vals["b_K"])
437
+ val_a_G = float(vals["a_G"])
438
+ val_b_G = float(vals["b_G"])
439
+
440
+ # (Molar) Volume
441
+ if "constr_vol" not in self.cache[name_lower]:
442
+ constr_vol = self._determine_volume_constructor(vals=vals)
443
+ self.cache[name_lower]["constr_vol"] = constr_vol
444
+
445
+ constr_minchem = MineralChemistry(w_traces=traces_data, molar_mass_pure=molar_mass_pure,
446
+ majors=majors_data)
447
+ V, V_m = self.crystallographic_properties.calculate_molar_volume(
448
+ constr_volume=constr_vol, constr_molar_volume=constr_minchem, cell_z=val_Z)
449
+ # Density
450
+ constr_density = CrystalPhysics([molar_mass, val_Z, V])
451
+ rho = self.crystallographic_properties.calculate_mineral_density(constr_density=constr_density)
452
+ constr_electr_density = wg(amounts=amounts, elements=element, rho_b=rho)
453
+ rho_e = self.crystallographic_properties.calculate_electron_density(
454
+ constr_electron_density=constr_electr_density)
455
+
456
+ # Elastic properties
457
+ if "K" not in vals:
458
+ val_K = (val_a_K*rho + val_b_K)*10**9
459
+ val_G = (val_a_G*rho + val_b_G)*10**9
460
+ E, nu = self.geophysical_properties.calculate_elastic_properties(bulk_mod=val_K, shear_mod=val_G)
461
+ # Seismic properties
462
+ vPvS, vP, vS = self.geophysical_properties.calculate_seismic_velocities(
463
+ bulk_mod=val_K, shear_mod=val_G, rho=rho)
464
+ # Radiation properties
465
+ constr_radiation = wg(amounts=amounts, elements=element)
466
+ gamma_ray, pe, U = self.geophysical_properties.calculate_radiation_properties(
467
+ constr_radiation=constr_radiation, rho_electron=rho_e)
468
+ # Electrical resistivity
469
+ p = None
470
+ # Results
471
+ results = {
472
+ "mineral": val_key, "state": val_state, "M": round(molar_mass, 3),
473
+ "chemistry": {name: round(val[1], 6) for name, *val in amounts}, "rho": round(rho, 3),
474
+ "rho_e": round(rho_e, 3), "V": round(V_m, 3), "vP": round(vP, 3), "vS": round(vS, 3),
475
+ "vP/vS": round(vPvS, 3), "K": round(val_K*10**(-9), 3), "G": round(val_G*10**(-9), 3),
476
+ "E": round(E*10**(-9), 3), "nu": round(nu, 6), "GR": round(gamma_ray, 3), "PE": round(pe, 3),
477
+ "U": round(U, 3), "p": p}
478
+ return results
479
+
480
+ def create_mineral_data_endmember_series(self):
481
+ """
482
+ Synthetic mineral data generation for an user-selected mineral.
483
+ All mechanical properties (K, G, E) are stored in Pascals internally.
484
+ For output, they are converted to GPa.
485
+ """
486
+ endmember_series = {
487
+ "Al-Spinel": {
488
+ "name_lower": "al-spinel",
489
+ "key": "Al-Spi",
490
+ "endmembers": ["Spinel", "Hercynite", "Gahnite", "Galaxite"],
491
+ "oxides": ["MgO", "Al2O3", "FeO", "ZnO", "MnO"]
492
+ },
493
+ "Cr-Spinel": {
494
+ "name_lower": "cr-spinel",
495
+ "key": "Cr-Spi",
496
+ "endmembers": ["Chromite", "Zincochromite", "Magnesiochromite"],
497
+ "oxides": ["Cr2O3", "FeO", "ZnO", "MgO"]
498
+ },
499
+ "Fe-Spinel": {
500
+ "name_lower": "fespinel",
501
+ "key": "Fe-Spi",
502
+ "endmembers": ["Magnetite", "Cuprospinel", "Jacobsite", "Magnesioferrite", "Trevorite", "Franklinite"],
503
+ "oxides": ["FeO", "Fe2O3", "Cu2O", "MnO", "Mn2O3", "MgO", "NiO", "ZnO"]
504
+ },
505
+ "Wolframite": {
506
+ "name_lower": "wolframite",
507
+ "key": "Wf",
508
+ "endmembers": ["Huebnerite", "Ferberite"],
509
+ "oxides": ["MnO", "WO3", "FeO"]
510
+ },
511
+ "Corundum-Group": {
512
+ "name_lower": "corundum-group",
513
+ "key": "Crn-group",
514
+ "endmembers": ["Corundum", "Hematite", "Eskolaite", "Karelianite", "Tistarite"],
515
+ "oxides": ["Al2O3", "Fe2O3", "Cr2O3", "V2O3", "Ti2O3"]
516
+ },
517
+ "Chromite-Group": {
518
+ "name_lower": "chromite-group",
519
+ "key": "Chr-group",
520
+ "endmembers": ["Chromite", "Manganochromite", "Nichromite", "Cochromite", "Zincochromite"],
521
+ "oxides": ["Cr2O3", "MnO", "NiO", "CoO", "ZnO"]
522
+ },
523
+ "Ilmenite-Group": {
524
+ "name_lower": "ilmenite-group",
525
+ "key": "Ilm-group",
526
+ "endmembers": ["Ilmenite", "Geikielite", "Pyrophanite"],
527
+ "oxides": ["FeO", "TiO2", "MgO", "MnO"]
528
+ },
529
+ "Rutile-Group": {
530
+ "name_lower": "rutile-group",
531
+ "key": "Rt-group",
532
+ "endmembers": ["Rutile", "Pyrolusite", "Cassiterite", "Plattnerite", "Argutite", "Stishovite"],
533
+ "oxides": ["TiO2", "MnO2", "SnO2", "PbO2", "GeO2", "SiO2"]
534
+ },
535
+ "Columbite": {
536
+ "name_lower": "columbite",
537
+ "key": "Clb",
538
+ "endmembers": ["FeColumbite", "MgColumbite", "MnColumbite"],
539
+ "oxides": ["FeO", "MgO", "MnO", "Nb2O5"]
540
+ },
541
+ "Tantalite": {
542
+ "name_lower": "tantalite",
543
+ "key": "Tnt",
544
+ "endmembers": ["FeTantalite", "MgTantalite", "MnTantalite"],
545
+ "oxides": ["FeO", "MgO", "MnO", "Ta2O5"]
546
+ },
547
+ "Coltan": {
548
+ "name_lower": "coltan",
549
+ "key": "Clt",
550
+ "endmembers": ["FeColumbite", "MgColumbite", "MnColumbite", "FeTantalite", "MgTantalite",
551
+ "MnTantalite"],
552
+ "oxides": ["FeO", "MgO", "MnO", "Nb2O5", "Ta2O5"]
553
+ },
554
+ "Periclase-Group": {
555
+ "name_lower": "periclase-Group",
556
+ "key": "Per-group",
557
+ "endmembers": ["Periclase", "Bunsenite", "Manganosite", "Monteponite", "Lime", "Wustite"],
558
+ "oxides": ["MgO", "NiO", "MnO", "CdO", "FeO"]
559
+ },
560
+ "Wulfenite-Group": {
561
+ "name_lower": "wulfenite-Group",
562
+ "key": "Wul-group",
563
+ "endmembers": ["Wulfenite", "Stolzite"],
564
+ "oxides": ["PbO", "MoO3", "WO3"]
565
+ },
566
+ "Scheelite-Group": {
567
+ "name_lower": "scheelite-Group",
568
+ "key": "Sch-group",
569
+ "endmembers": ["Scheelite", "Powellite"],
570
+ "oxides": ["CaO", "MoO3", "WO3"]
571
+ },
572
+ "Diaspore-Group": {
573
+ "name_lower": "diaspore-Group",
574
+ "key": "Dsp-group",
575
+ "endmembers": ["Diaspore", "Goethite", "Groutite"],
576
+ "oxides": ["Al2O3", "Fe2O3", "Mn2O3", "H2O"]
577
+ }
578
+ }
579
+ results = MinGen(
580
+ name=self.name, yaml_data=self.yaml_data, elements=self.elements, cache=self.cache,
581
+ geophysical_properties=self.geophysical_properties,
582
+ rounding=self.rounding).create_mineral_data_endmember_series(
583
+ endmember_series=endmember_series, var_class=Oxides, current_seed=self.current_seed, rng=self.rng)
584
+
585
+ return results
586
+
587
+ # TEST
588
+ if __name__ == "__main__":
589
+ DEFAULT_DATA = Oxides(name="Quartz", random_seed=42).generate_dataset(number=10)
File without changes
File without changes