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.
- gebpy/__init__.py +55 -0
- gebpy/__pycache__/__init__.cpython-310.pyc +0 -0
- gebpy/adapters/__init__.py +0 -0
- gebpy/cli/__init__.py +0 -0
- gebpy/core/__init__.py +0 -0
- gebpy/core/chemistry/__init__.py +0 -0
- gebpy/core/chemistry/common.py +1369 -0
- gebpy/core/chemistry/elements.py +317 -0
- gebpy/core/chemistry/geochemistry.py +1728 -0
- gebpy/core/fluids/__init__.py +0 -0
- gebpy/core/io/__init__.py +0 -0
- gebpy/core/mathematics/__init__.py +0 -0
- gebpy/core/minerals/__init__.py +0 -0
- gebpy/core/minerals/carbonates.py +412 -0
- gebpy/core/minerals/common.py +555 -0
- gebpy/core/minerals/config.py +77 -0
- gebpy/core/minerals/cyclosilicates.py +0 -0
- gebpy/core/minerals/halides.py +0 -0
- gebpy/core/minerals/inosilicates.py +0 -0
- gebpy/core/minerals/nesosilicates.py +0 -0
- gebpy/core/minerals/organics.py +0 -0
- gebpy/core/minerals/oxides.py +589 -0
- gebpy/core/minerals/phosphates.py +0 -0
- gebpy/core/minerals/phospides.py +0 -0
- gebpy/core/minerals/phyllosilicates.py +436 -0
- gebpy/core/minerals/sorosilicates.py +0 -0
- gebpy/core/minerals/sulfates.py +0 -0
- gebpy/core/minerals/sulfides.py +459 -0
- gebpy/core/minerals/synthesis.py +201 -0
- gebpy/core/minerals/tectosilicates.py +433 -0
- gebpy/core/physics/__init__.py +0 -0
- gebpy/core/physics/common.py +53 -0
- gebpy/core/physics/geophysics.py +351 -0
- gebpy/core/rocks/__init__.py +0 -0
- gebpy/core/rocks/anisotropic_rocks.py +395 -0
- gebpy/core/rocks/common.py +95 -0
- gebpy/core/rocks/config.py +77 -0
- gebpy/core/rocks/isotropic_rocks.py +395 -0
- gebpy/core/rocks/sedimentary.py +385 -0
- gebpy/core/subsurface/__init__.py +0 -0
- gebpy/data_minerals/__init__.py +0 -0
- gebpy/data_minerals/albite.yaml +59 -0
- gebpy/data_minerals/anatase.yaml +43 -0
- gebpy/data_minerals/ankerite.yaml +47 -0
- gebpy/data_minerals/annite.yaml +57 -0
- gebpy/data_minerals/anorthite.yaml +59 -0
- gebpy/data_minerals/antigorite.yaml +53 -0
- gebpy/data_minerals/aragonite.yaml +48 -0
- gebpy/data_minerals/argutite.yaml +43 -0
- gebpy/data_minerals/arsenolite.yaml +40 -0
- gebpy/data_minerals/au3oxide.yaml +46 -0
- gebpy/data_minerals/avicennite.yaml +40 -0
- gebpy/data_minerals/azurite.yaml +53 -0
- gebpy/data_minerals/baddeleyite.yaml +49 -0
- gebpy/data_minerals/bismite.yaml +49 -0
- gebpy/data_minerals/boehmite.yaml +48 -0
- gebpy/data_minerals/brookite.yaml +46 -0
- gebpy/data_minerals/brucite.yaml +45 -0
- gebpy/data_minerals/bunsenite.yaml +40 -0
- gebpy/data_minerals/calcite.yaml +45 -0
- gebpy/data_minerals/cassiterite.yaml +43 -0
- gebpy/data_minerals/cerussite.yaml +48 -0
- gebpy/data_minerals/chamosite.yaml +56 -0
- gebpy/data_minerals/chlorite.yaml +75 -0
- gebpy/data_minerals/chromite.yaml +42 -0
- gebpy/data_minerals/chrysotile.yaml +53 -0
- gebpy/data_minerals/claudetite.yaml +49 -0
- gebpy/data_minerals/clinochlore.yaml +55 -0
- gebpy/data_minerals/cochromite.yaml +42 -0
- gebpy/data_minerals/corundum.yaml +43 -0
- gebpy/data_minerals/crocoite.yaml +51 -0
- gebpy/data_minerals/cuprite.yaml +40 -0
- gebpy/data_minerals/cuprospinel.yaml +42 -0
- gebpy/data_minerals/diaspore.yaml +48 -0
- gebpy/data_minerals/dolomite.yaml +47 -0
- gebpy/data_minerals/eastonite.yaml +57 -0
- gebpy/data_minerals/eskolaite.yaml +43 -0
- gebpy/data_minerals/fechlorite.yaml +61 -0
- gebpy/data_minerals/fecolumbite.yaml +48 -0
- gebpy/data_minerals/ferberite.yaml +51 -0
- gebpy/data_minerals/fetantalite.yaml +48 -0
- gebpy/data_minerals/franklinite.yaml +42 -0
- gebpy/data_minerals/gahnite.yaml +42 -0
- gebpy/data_minerals/galaxite.yaml +42 -0
- gebpy/data_minerals/geikielite.yaml +45 -0
- gebpy/data_minerals/gibbsite.yaml +51 -0
- gebpy/data_minerals/glauconite.yaml +69 -0
- gebpy/data_minerals/goethite.yaml +48 -0
- gebpy/data_minerals/groutite.yaml +48 -0
- gebpy/data_minerals/hematite.yaml +43 -0
- gebpy/data_minerals/hercynite.yaml +42 -0
- gebpy/data_minerals/huebnerite.yaml +51 -0
- gebpy/data_minerals/ikaite.yaml +53 -0
- gebpy/data_minerals/illite.yaml +55 -0
- gebpy/data_minerals/ilmenite.yaml +45 -0
- gebpy/data_minerals/jacobsite.yaml +42 -0
- gebpy/data_minerals/kalsilite.yaml +47 -0
- gebpy/data_minerals/kaolinite.yaml +59 -0
- gebpy/data_minerals/karelianite.yaml +43 -0
- gebpy/data_minerals/lime.yaml +40 -0
- gebpy/data_minerals/litharge.yaml +43 -0
- gebpy/data_minerals/magnesiochromite.yaml +42 -0
- gebpy/data_minerals/magnesioferrite.yaml +42 -0
- gebpy/data_minerals/magnesite.yaml +45 -0
- gebpy/data_minerals/magnetite.yaml +41 -0
- gebpy/data_minerals/malachite.yaml +53 -0
- gebpy/data_minerals/manganite.yaml +51 -0
- gebpy/data_minerals/manganochromite.yaml +42 -0
- gebpy/data_minerals/manganosite.yaml +40 -0
- gebpy/data_minerals/marialite.yaml +49 -0
- gebpy/data_minerals/massicot.yaml +46 -0
- gebpy/data_minerals/meionite.yaml +49 -0
- gebpy/data_minerals/mgchlorite.yaml +61 -0
- gebpy/data_minerals/mgcolumbite.yaml +48 -0
- gebpy/data_minerals/mgtantalite.yaml +48 -0
- gebpy/data_minerals/microcline.yaml +59 -0
- gebpy/data_minerals/minium.yaml +44 -0
- gebpy/data_minerals/mnchlorite.yaml +61 -0
- gebpy/data_minerals/mncolumbite.yaml +48 -0
- gebpy/data_minerals/mntantalite.yaml +48 -0
- gebpy/data_minerals/monteponite.yaml +40 -0
- gebpy/data_minerals/montmorillonite.yaml +77 -0
- gebpy/data_minerals/muscovite.yaml +55 -0
- gebpy/data_minerals/nanepheline.yaml +47 -0
- gebpy/data_minerals/nichlorite.yaml +61 -0
- gebpy/data_minerals/nichromite.yaml +42 -0
- gebpy/data_minerals/nimite.yaml +55 -0
- gebpy/data_minerals/nontronite.yaml +73 -0
- gebpy/data_minerals/orthoclase.yaml +53 -0
- gebpy/data_minerals/paratellurite.yaml +43 -0
- gebpy/data_minerals/pennantite.yaml +61 -0
- gebpy/data_minerals/periclase.yaml +40 -0
- gebpy/data_minerals/phlogopite.yaml +57 -0
- gebpy/data_minerals/plattnerite.yaml +43 -0
- gebpy/data_minerals/powellite.yaml +45 -0
- gebpy/data_minerals/pyrite.yaml +40 -0
- gebpy/data_minerals/pyrolusite.yaml +43 -0
- gebpy/data_minerals/pyrophanite.yaml +45 -0
- gebpy/data_minerals/pyrophyllite.yaml +59 -0
- gebpy/data_minerals/quartz.yaml +43 -0
- gebpy/data_minerals/rhodochrosite.yaml +45 -0
- gebpy/data_minerals/rutile.yaml +43 -0
- gebpy/data_minerals/saponite.yaml +77 -0
- gebpy/data_minerals/scheelite.yaml +45 -0
- gebpy/data_minerals/scrutinyite.yaml +46 -0
- gebpy/data_minerals/senarmontite.yaml +40 -0
- gebpy/data_minerals/siderite.yaml +45 -0
- gebpy/data_minerals/siderophyllite.yaml +57 -0
- gebpy/data_minerals/smithsonite.yaml +45 -0
- gebpy/data_minerals/spinel.yaml +42 -0
- gebpy/data_minerals/stishovite.yaml +43 -0
- gebpy/data_minerals/stolzite.yaml +45 -0
- gebpy/data_minerals/talc.yaml +53 -0
- gebpy/data_minerals/tistarite.yaml +43 -0
- gebpy/data_minerals/trevorite.yaml +42 -0
- gebpy/data_minerals/ulvoespinel.yaml +42 -0
- gebpy/data_minerals/uraninite.yaml +40 -0
- gebpy/data_minerals/valentinite.yaml +46 -0
- gebpy/data_minerals/vermiculite.yaml +69 -0
- gebpy/data_minerals/wulfenite.yaml +45 -0
- gebpy/data_minerals/wustite.yaml +40 -0
- gebpy/data_minerals/zincite.yaml +43 -0
- gebpy/data_minerals/zincochromite.yaml +42 -0
- gebpy/data_rocks/__init__.py +0 -0
- gebpy/data_rocks/dolostone.yaml +40 -0
- gebpy/data_rocks/limestone.yaml +40 -0
- gebpy/data_rocks/marl.yaml +50 -0
- gebpy/data_rocks/sandstone.yaml +39 -0
- gebpy/data_rocks/shale.yaml +50 -0
- gebpy/gebpy_app.py +8732 -0
- gebpy/gui/__init__.py +0 -0
- gebpy/lib/images/GebPy_Header.png +0 -0
- gebpy/lib/images/GebPy_Icon.png +0 -0
- gebpy/lib/images/GebPy_Logo.png +0 -0
- gebpy/main.py +29 -0
- gebpy/modules/__init__.py +0 -0
- gebpy/modules/__pycache__/__init__.cpython-310.pyc +0 -0
- gebpy/modules/__pycache__/metamorphics.cpython-310.pyc +0 -0
- gebpy/modules/__pycache__/silicates.cpython-310.pyc +0 -0
- gebpy/modules/carbonates.py +2658 -0
- gebpy/modules/chemistry.py +1369 -0
- gebpy/modules/core.py +1805 -0
- gebpy/modules/elements.py +317 -0
- gebpy/modules/evaporites.py +1299 -0
- gebpy/modules/exploration.py +1145 -0
- gebpy/modules/fluids.py +339 -0
- gebpy/modules/geochemistry.py +1727 -0
- gebpy/modules/geophysics.py +351 -0
- gebpy/modules/gui.py +9093 -0
- gebpy/modules/gui_elements.py +145 -0
- gebpy/modules/halides.py +485 -0
- gebpy/modules/igneous.py +2241 -0
- gebpy/modules/metamorphics.py +3222 -0
- gebpy/modules/mineralogy.py +442 -0
- gebpy/modules/minerals.py +7954 -0
- gebpy/modules/ore.py +1648 -0
- gebpy/modules/organics.py +530 -0
- gebpy/modules/oxides.py +9057 -0
- gebpy/modules/petrophysics.py +98 -0
- gebpy/modules/phosphates.py +589 -0
- gebpy/modules/phospides.py +194 -0
- gebpy/modules/plotting.py +619 -0
- gebpy/modules/pyllosilicates.py +380 -0
- gebpy/modules/sedimentary_rocks.py +908 -0
- gebpy/modules/sequences.py +2166 -0
- gebpy/modules/series.py +1625 -0
- gebpy/modules/silicates.py +11102 -0
- gebpy/modules/siliciclastics.py +1846 -0
- gebpy/modules/subsurface_2d.py +179 -0
- gebpy/modules/sulfates.py +1629 -0
- gebpy/modules/sulfides.py +4786 -0
- gebpy/plotting/__init__.py +0 -0
- gebpy/ui_nb/__init__.py +0 -0
- gebpy/user_data/.gitkeep +0 -0
- gebpy-1.1.3.dist-info/LICENSE +165 -0
- gebpy-1.1.3.dist-info/METADATA +207 -0
- gebpy-1.1.3.dist-info/RECORD +254 -0
- gebpy-1.1.3.dist-info/WHEEL +5 -0
- gebpy-1.1.3.dist-info/entry_points.txt +2 -0
- gebpy-1.1.3.dist-info/top_level.txt +1 -0
- modules/__init__.py +0 -0
- modules/carbonates.py +2658 -0
- modules/chemistry.py +1369 -0
- modules/core.py +1805 -0
- modules/elements.py +317 -0
- modules/evaporites.py +1299 -0
- modules/exploration.py +765 -0
- modules/fluids.py +339 -0
- modules/geochemistry.py +1727 -0
- modules/geophysics.py +337 -0
- modules/gui.py +9093 -0
- modules/gui_elements.py +145 -0
- modules/halides.py +485 -0
- modules/igneous.py +2196 -0
- modules/metamorphics.py +2699 -0
- modules/mineralogy.py +442 -0
- modules/minerals.py +7954 -0
- modules/ore.py +1628 -0
- modules/organics.py +530 -0
- modules/oxides.py +9057 -0
- modules/petrophysics.py +98 -0
- modules/phosphates.py +589 -0
- modules/phospides.py +194 -0
- modules/plotting.py +619 -0
- modules/pyllosilicates.py +380 -0
- modules/sedimentary_rocks.py +908 -0
- modules/sequences.py +2166 -0
- modules/series.py +1625 -0
- modules/silicates.py +11102 -0
- modules/siliciclastics.py +1830 -0
- modules/subsurface_2d.py +179 -0
- modules/sulfates.py +1629 -0
- modules/sulfides.py +4786 -0
- notebooks/__init__.py +0 -0
|
@@ -0,0 +1,555 @@
|
|
|
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: 15.12.2025
|
|
10
|
+
|
|
11
|
+
#-----------------------------------------------
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
Module: common.py
|
|
15
|
+
This module contains several routines that are commonly used by the different mineral-related modules.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# PACKAGES
|
|
19
|
+
import numpy as np
|
|
20
|
+
import scipy, re
|
|
21
|
+
|
|
22
|
+
# MODULES
|
|
23
|
+
from ..chemistry.geochemistry import MineralChemistry
|
|
24
|
+
from ..physics.geophysics import WellLog as wg
|
|
25
|
+
|
|
26
|
+
# CODE
|
|
27
|
+
class GeophysicalProperties:
|
|
28
|
+
def __init__(self):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
def calculate_elastic_properties(self, bulk_mod, shear_mod):
|
|
32
|
+
E = (9*bulk_mod*shear_mod)/(3*bulk_mod + shear_mod) # Young's modulus
|
|
33
|
+
nu = (3*bulk_mod - 2*shear_mod)/(2*(3*bulk_mod + shear_mod)) # Poisson's ratio
|
|
34
|
+
return E, nu
|
|
35
|
+
|
|
36
|
+
def calculate_seismic_velocities(self, bulk_mod, shear_mod, rho):
|
|
37
|
+
vPvS = ((bulk_mod + 4/3*shear_mod)/shear_mod)**0.5 # vP/vS
|
|
38
|
+
vP = ((bulk_mod + 4/3*shear_mod)/rho)**0.5 # P-wave velocity vP
|
|
39
|
+
vS = (shear_mod/rho)**0.5 # S-wave velocity vS
|
|
40
|
+
return vPvS, vP, vS
|
|
41
|
+
|
|
42
|
+
def calculate_radiation_properties(self, constr_radiation, rho_electron):
|
|
43
|
+
gamma_ray = constr_radiation.calculate_gr() # Gamma ray
|
|
44
|
+
pe = constr_radiation.calculate_pe() # Photoelectricity Pe
|
|
45
|
+
U = pe*rho_electron*10**(-3) # Photoelectricity U
|
|
46
|
+
return gamma_ray, pe, U
|
|
47
|
+
|
|
48
|
+
class CrystallographicProperties:
|
|
49
|
+
def __init__(self):
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def calculate_molar_volume(self, constr_volume, constr_molar_volume, cell_z):
|
|
53
|
+
dataV = constr_volume
|
|
54
|
+
V = dataV.calculate_volume() # Cell volume
|
|
55
|
+
V_m = constr_molar_volume.calculate_molar_volume(volume_cell=V, z=cell_z) # Molar volume
|
|
56
|
+
return V, V_m
|
|
57
|
+
|
|
58
|
+
def calculate_mineral_density(self, constr_density):
|
|
59
|
+
rho = constr_density.calculate_bulk_density() # Density
|
|
60
|
+
return rho
|
|
61
|
+
|
|
62
|
+
def calculate_electron_density(self, constr_electron_density):
|
|
63
|
+
rho_e = constr_electron_density.calculate_electron_density() # Electron density
|
|
64
|
+
return rho_e
|
|
65
|
+
|
|
66
|
+
class CrystalPhysics:
|
|
67
|
+
def __init__(self, properties):
|
|
68
|
+
self.properties = properties
|
|
69
|
+
self.avogadro = scipy.constants.Avogadro
|
|
70
|
+
|
|
71
|
+
def calculate_bulk_density(self):
|
|
72
|
+
# properties = [ molar mass, formula unit, unit cell volume ]
|
|
73
|
+
M = self.properties[0] # in g/mol
|
|
74
|
+
Z = self.properties[1]
|
|
75
|
+
V = self.properties[2] # in cm^3
|
|
76
|
+
|
|
77
|
+
# density rho in kg/m^3
|
|
78
|
+
rho = (Z*M)/(V*self.avogadro)*1000
|
|
79
|
+
|
|
80
|
+
return rho
|
|
81
|
+
|
|
82
|
+
def calculate_electron_density(self):
|
|
83
|
+
# properties = [ elements, amounts, bulk density ]
|
|
84
|
+
Z = np.sum([self.properties[1][i]*self.properties[0][i][1] for i in range(len(self.properties[0]))])/np.sum(
|
|
85
|
+
self.properties[1])
|
|
86
|
+
A = np.sum([self.properties[1][i]*self.properties[0][i][2] for i in range(len(self.properties[0]))])/np.sum(
|
|
87
|
+
self.properties[1])
|
|
88
|
+
|
|
89
|
+
rho_b = self.properties[2]
|
|
90
|
+
rho_e = 2*Z/A * rho_b
|
|
91
|
+
|
|
92
|
+
return rho_e
|
|
93
|
+
|
|
94
|
+
def calculate_volume(self):
|
|
95
|
+
# properties = [ list of lattice lengths, list of lattice angles, crystal system ]
|
|
96
|
+
lenghts = self.properties[0] # in angstrom
|
|
97
|
+
angles = self.properties[1] # in degree
|
|
98
|
+
crystalsystem = self.properties[2]
|
|
99
|
+
|
|
100
|
+
if crystalsystem == "cubic":
|
|
101
|
+
a = lenghts[0]*10**(-8)
|
|
102
|
+
V = a**3
|
|
103
|
+
return V
|
|
104
|
+
elif crystalsystem == "tetragonal":
|
|
105
|
+
a = lenghts[0]*10**(-8)
|
|
106
|
+
c = lenghts[1]*10**(-8)
|
|
107
|
+
V = a**2 * c
|
|
108
|
+
return V
|
|
109
|
+
elif crystalsystem in ["hexagonal", "trigonal"]:
|
|
110
|
+
a = lenghts[0]*10**(-8)
|
|
111
|
+
c = lenghts[1]*10**(-8)
|
|
112
|
+
angle = 60
|
|
113
|
+
V = (a**2 * c)*np.sin(angle*np.pi/180)
|
|
114
|
+
return V
|
|
115
|
+
elif crystalsystem == "orthorhombic":
|
|
116
|
+
a = lenghts[0]*10**(-8)
|
|
117
|
+
b = lenghts[1]*10**(-8)
|
|
118
|
+
c = lenghts[2]*10**(-8)
|
|
119
|
+
V = a * b * c
|
|
120
|
+
return V
|
|
121
|
+
elif crystalsystem == "monoclinic":
|
|
122
|
+
a = lenghts[0]*10**(-8)
|
|
123
|
+
b = lenghts[1]*10**(-8)
|
|
124
|
+
c = lenghts[2]*10**(-8)
|
|
125
|
+
beta = angles[0]
|
|
126
|
+
V = (a * b * c)*np.sin(beta*np.pi/180)
|
|
127
|
+
return V
|
|
128
|
+
elif crystalsystem == "triclinic":
|
|
129
|
+
a = lenghts[0]*10**(-8)
|
|
130
|
+
b = lenghts[1]*10**(-8)
|
|
131
|
+
c = lenghts[2]*10**(-8)
|
|
132
|
+
alpha = angles[0]
|
|
133
|
+
beta = angles[1]
|
|
134
|
+
gamma = angles[2]
|
|
135
|
+
V = (a * b * c)*(1 - np.cos(alpha*np.pi/180)**2 - np.cos(beta*np.pi/180)**2 - np.cos(gamma*np.pi/180)**2 +
|
|
136
|
+
2*(abs(np.cos(alpha*np.pi/180)*np.cos(beta*np.pi/180)*np.cos(gamma*np.pi/180))))**(0.5)
|
|
137
|
+
return V
|
|
138
|
+
|
|
139
|
+
class OxideComposition:
|
|
140
|
+
"""
|
|
141
|
+
This class calculates the oxide composition of a certain mineral.
|
|
142
|
+
"""
|
|
143
|
+
def __init__(self):
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
def _get_cation_element(self, oxide: str) -> str:
|
|
147
|
+
first = oxide[0]
|
|
148
|
+
if len(oxide) > 1 and oxide[1].islower():
|
|
149
|
+
return oxide[:2]
|
|
150
|
+
|
|
151
|
+
return first
|
|
152
|
+
|
|
153
|
+
def _parse_formula(self, formula: str):
|
|
154
|
+
pattern = r"([A-Z][a-z]?)(\d*)"
|
|
155
|
+
matches = re.findall(pattern, formula)
|
|
156
|
+
|
|
157
|
+
composition = {}
|
|
158
|
+
for elem, amount in matches:
|
|
159
|
+
amount = int(amount) if amount else 1
|
|
160
|
+
composition[elem] = composition.get(elem, 0) + amount
|
|
161
|
+
|
|
162
|
+
return composition
|
|
163
|
+
|
|
164
|
+
def _determine_oxide_conversion_factors(self, elements):
|
|
165
|
+
list_oxides = [
|
|
166
|
+
"H2O", "CO", "CO2", "Na2O", "MgO", "Al2O3", "SiO2", "Cl2O", "K2O", "CaO", "MnO", "Mn2O3", "MnO2", "MnO3",
|
|
167
|
+
"Mn2O7", "FeO", "Fe2O3", "FeO3", "NiO", "Ni2O3", "TiO2", "Ti2O3", "VO", "V2O3", "VO2", "V2O10", "CrO",
|
|
168
|
+
"Cr2O3", "CrO3", "CoO", "Co2O3", "Cu2O", "CuO", "ZnO", "GeO2", "As2O3", "As2O10", "ZrO2", "Nb2O3", "Nb2O10",
|
|
169
|
+
"MoO", "Mo2O3", "MoO2", "Mo2O10", "MoO3", "CdO", "SnO", "SnO2", "Sb2O3", "Sb2O10", "TeO2", "TeO3", "Ta2O10",
|
|
170
|
+
"WO", "W2O3", "WO2", "W2O10", "WO3", "Au2O", "Au2O3", "Tl2O", "Tl2O3", "PbO", "PbO2", "Bi2O3", "Bi2O10",
|
|
171
|
+
"U2O3", "UO2", "U2O10", "UO3"]
|
|
172
|
+
mass_oxygen = elements["O"][2]
|
|
173
|
+
_conversion_factors = {}
|
|
174
|
+
for oxide in list_oxides:
|
|
175
|
+
_conversion_factors[oxide] = self._parse_formula(formula=oxide)
|
|
176
|
+
cation = self._get_cation_element(oxide=oxide)
|
|
177
|
+
if cation in elements:
|
|
178
|
+
mass_cation = elements[cation][2]
|
|
179
|
+
_conversion_factors[oxide]["factor"] = (_conversion_factors[oxide][cation]*mass_cation +
|
|
180
|
+
_conversion_factors[oxide]["O"]*mass_oxygen)/(
|
|
181
|
+
_conversion_factors[oxide][cation]*mass_cation)
|
|
182
|
+
else:
|
|
183
|
+
pass
|
|
184
|
+
#print(self.name, ": cation", cation, "not found in chemical container.")
|
|
185
|
+
|
|
186
|
+
return _conversion_factors
|
|
187
|
+
|
|
188
|
+
def _element_amounts_as_dict(self, amounts):
|
|
189
|
+
helper_dict = {}
|
|
190
|
+
for item in amounts:
|
|
191
|
+
helper_dict[item[0]] = item[2]
|
|
192
|
+
|
|
193
|
+
return helper_dict
|
|
194
|
+
|
|
195
|
+
class MineralGeneration:
|
|
196
|
+
"""
|
|
197
|
+
This class controls the mineral data generation for minerals with fixed composition.
|
|
198
|
+
"""
|
|
199
|
+
def __init__(self, name, yaml_data, elements, cache, geophysical_properties, rounding):
|
|
200
|
+
self.name = name
|
|
201
|
+
self.yaml_data = yaml_data
|
|
202
|
+
self.elements = elements
|
|
203
|
+
self.cache = cache
|
|
204
|
+
self.geophysical_properties = geophysical_properties
|
|
205
|
+
self.rounding = rounding
|
|
206
|
+
self.conversion_factors = self._determine_oxide_conversion_factors()
|
|
207
|
+
|
|
208
|
+
def _get_value(self, data: dict, path: list[str], default=None):
|
|
209
|
+
"""Safely extract a float or string value from nested YAML data."""
|
|
210
|
+
try:
|
|
211
|
+
for key in path:
|
|
212
|
+
data = data[key]
|
|
213
|
+
if isinstance(data, dict) and "value" in data:
|
|
214
|
+
return float(data["value"])
|
|
215
|
+
else:
|
|
216
|
+
return data # kann z.B. ein String oder eine Zahl sein
|
|
217
|
+
except (KeyError, TypeError):
|
|
218
|
+
return default
|
|
219
|
+
|
|
220
|
+
def _determine_volume_constructor(self, vals):
|
|
221
|
+
val_a = vals["a"]
|
|
222
|
+
val_system = vals["crystal_system"]
|
|
223
|
+
if val_system in ["isometric", "cubic"]:
|
|
224
|
+
constr_vol = CrystalPhysics([[val_a], [], val_system])
|
|
225
|
+
elif val_system in ["tetragonal", "hexagonal", "trigonal"]:
|
|
226
|
+
val_c = vals["c"]
|
|
227
|
+
constr_vol = CrystalPhysics([[val_a, val_c], [], val_system])
|
|
228
|
+
elif val_system in ["orthorhombic"]:
|
|
229
|
+
val_b = vals["b"]
|
|
230
|
+
val_c = vals["c"]
|
|
231
|
+
constr_vol = CrystalPhysics([[val_a, val_b, val_c], [], val_system])
|
|
232
|
+
elif val_system in ["monoclinic"]:
|
|
233
|
+
val_b = vals["b"]
|
|
234
|
+
val_c = vals["c"]
|
|
235
|
+
val_beta = vals["beta"]
|
|
236
|
+
constr_vol = CrystalPhysics([[val_a, val_b, val_c], [val_beta], val_system])
|
|
237
|
+
elif val_system in ["triclinic"]:
|
|
238
|
+
val_b = vals["b"]
|
|
239
|
+
val_c = vals["c"]
|
|
240
|
+
val_alpha = vals["alpha"]
|
|
241
|
+
val_beta = vals["beta"]
|
|
242
|
+
val_gamma = vals["gamma"]
|
|
243
|
+
constr_vol = CrystalPhysics([[val_a, val_b, val_c], [val_alpha, val_beta, val_gamma], val_system])
|
|
244
|
+
return constr_vol
|
|
245
|
+
|
|
246
|
+
def _parse_formula(self, formula: str):
|
|
247
|
+
pattern = r"([A-Z][a-z]?)(\d*)"
|
|
248
|
+
matches = re.findall(pattern, formula)
|
|
249
|
+
|
|
250
|
+
composition = {}
|
|
251
|
+
for elem, amount in matches:
|
|
252
|
+
amount = int(amount) if amount else 1
|
|
253
|
+
composition[elem] = composition.get(elem, 0) + amount
|
|
254
|
+
|
|
255
|
+
return composition
|
|
256
|
+
|
|
257
|
+
def _get_cation_element(self, oxide: str) -> str:
|
|
258
|
+
first = oxide[0]
|
|
259
|
+
if len(oxide) > 1 and oxide[1].islower():
|
|
260
|
+
return oxide[:2]
|
|
261
|
+
|
|
262
|
+
return first
|
|
263
|
+
|
|
264
|
+
def _determine_sulfide_conversion_factors(self):
|
|
265
|
+
list_sulfides = ["FeS", "FeS2"]
|
|
266
|
+
mass_sulfur = self.elements["S"][2]
|
|
267
|
+
_conversion_factors = {}
|
|
268
|
+
for sulfide in list_sulfides:
|
|
269
|
+
_conversion_factors[sulfide] = self._parse_formula(formula=sulfide)
|
|
270
|
+
cation = self._get_cation_element(oxide=sulfide)
|
|
271
|
+
if cation in self.elements:
|
|
272
|
+
mass_cation = self.elements[cation][2]
|
|
273
|
+
_conversion_factors[sulfide]["factor"] = (_conversion_factors[sulfide][cation]*mass_cation +
|
|
274
|
+
_conversion_factors[sulfide]["S"]*mass_sulfur)/(
|
|
275
|
+
_conversion_factors[sulfide][cation]*mass_cation)
|
|
276
|
+
else:
|
|
277
|
+
pass
|
|
278
|
+
#print(self.name, ": cation", cation, "not found in chemical container.")
|
|
279
|
+
|
|
280
|
+
return _conversion_factors
|
|
281
|
+
|
|
282
|
+
def _determine_oxide_conversion_factors(self):
|
|
283
|
+
list_oxides = [
|
|
284
|
+
"H2O", "CO", "CO2", "Na2O", "MgO", "Al2O3", "SiO2", "Cl2O", "K2O", "CaO", "MnO", "Mn2O3", "MnO2", "MnO3",
|
|
285
|
+
"Mn2O7", "FeO", "Fe2O3", "FeO3", "NiO", "Ni2O3", "TiO2", "Ti2O3", "VO", "V2O3", "VO2", "V2O10", "CrO",
|
|
286
|
+
"Cr2O3", "CrO3", "CoO", "Co2O3", "Cu2O", "CuO", "ZnO", "GeO2", "As2O3", "As2O10", "ZrO2", "Nb2O3", "Nb2O10",
|
|
287
|
+
"MoO", "Mo2O3", "MoO2", "Mo2O10", "MoO3", "CdO", "SnO", "SnO2", "Sb2O3", "Sb2O10", "TeO2", "TeO3", "Ta2O10",
|
|
288
|
+
"WO", "W2O3", "WO2", "W2O10", "WO3", "Au2O", "Au2O3", "Tl2O", "Tl2O3", "PbO", "PbO2", "Bi2O3", "Bi2O10",
|
|
289
|
+
"U2O3", "UO2", "U2O10", "UO3", "Nb2O5", "Ta2O5"]
|
|
290
|
+
mass_oxygen = self.elements["O"][2]
|
|
291
|
+
_conversion_factors = {}
|
|
292
|
+
for oxide in list_oxides:
|
|
293
|
+
_conversion_factors[oxide] = self._parse_formula(formula=oxide)
|
|
294
|
+
cation = self._get_cation_element(oxide=oxide)
|
|
295
|
+
if cation in self.elements:
|
|
296
|
+
mass_cation = self.elements[cation][2]
|
|
297
|
+
_conversion_factors[oxide]["factor"] = (_conversion_factors[oxide][cation]*mass_cation +
|
|
298
|
+
_conversion_factors[oxide]["O"]*mass_oxygen)/(
|
|
299
|
+
_conversion_factors[oxide][cation]*mass_cation)
|
|
300
|
+
else:
|
|
301
|
+
pass
|
|
302
|
+
#print(self.name, ": cation", cation, "not found in chemical container.")
|
|
303
|
+
|
|
304
|
+
return _conversion_factors
|
|
305
|
+
|
|
306
|
+
def _element_amounts_as_dict(self, amounts):
|
|
307
|
+
helper_dict = {}
|
|
308
|
+
for item in amounts:
|
|
309
|
+
helper_dict[item[0]] = item[2]
|
|
310
|
+
|
|
311
|
+
return helper_dict
|
|
312
|
+
|
|
313
|
+
def _determine_majors_data(self):
|
|
314
|
+
majors_data = []
|
|
315
|
+
molar_mass_pure = 0
|
|
316
|
+
for element, amount in self.yaml_data["chemistry"].items():
|
|
317
|
+
n_order = int(self.elements[element][1])
|
|
318
|
+
val_amount = float(amount)
|
|
319
|
+
molar_mass = float(self.elements[element][2])
|
|
320
|
+
majors_data.append([element, n_order, val_amount, molar_mass])
|
|
321
|
+
molar_mass_pure += val_amount*molar_mass
|
|
322
|
+
majors_data.sort(key=lambda x: x[1])
|
|
323
|
+
return majors_data, molar_mass_pure
|
|
324
|
+
|
|
325
|
+
def _extract_values_from_yaml(self):
|
|
326
|
+
vals = {}
|
|
327
|
+
# Physical parameters
|
|
328
|
+
for key in ["K", "G", "a_K", "b_K", "a_G", "b_G"]:
|
|
329
|
+
if key in self.yaml_data.get("physical_properties", {}):
|
|
330
|
+
vals[key] = float(self.yaml_data["physical_properties"][key]["value"])
|
|
331
|
+
# Cell parameters
|
|
332
|
+
for key in ["a", "b", "c", "alpha", "beta", "gamma", "Z"]:
|
|
333
|
+
if key in self.yaml_data.get("cell_data", {}):
|
|
334
|
+
vals[key] = float(self.yaml_data["cell_data"][key]["value"])
|
|
335
|
+
# Meta data
|
|
336
|
+
vals["key"] = self.yaml_data["metadata"]["key"]
|
|
337
|
+
vals["crystal_system"] = self.yaml_data["metadata"]["crystal_system"]
|
|
338
|
+
|
|
339
|
+
return vals
|
|
340
|
+
|
|
341
|
+
def create_mineral_data_fixed_composition(self):
|
|
342
|
+
"""
|
|
343
|
+
Synthetic mineral data generation for an user-selected mineral.
|
|
344
|
+
All mechanical properties (K, G, E) are stored in Pascals internally.
|
|
345
|
+
For output, they are converted to GPa.
|
|
346
|
+
"""
|
|
347
|
+
name_lower = self.name.lower()
|
|
348
|
+
# Chemistry
|
|
349
|
+
val_state = "fixed"
|
|
350
|
+
traces_data = []
|
|
351
|
+
# Molar mass, elemental amounts
|
|
352
|
+
majors_data, molar_mass_pure = self._determine_majors_data()
|
|
353
|
+
if "oxides" in self.yaml_data:
|
|
354
|
+
oxides_data = {}
|
|
355
|
+
for oxide, amount in self.yaml_data["oxides"].items():
|
|
356
|
+
cation = self._get_cation_element(oxide=oxide)
|
|
357
|
+
oxides_data[oxide] = [cation, None, amount]
|
|
358
|
+
elif "sulfides" in self.yaml_data:
|
|
359
|
+
self.conversion_factors = self._determine_sulfide_conversion_factors()
|
|
360
|
+
oxides_data = {}
|
|
361
|
+
for oxide, amount in self.yaml_data["sulfides"].items():
|
|
362
|
+
cation = self._get_cation_element(oxide=oxide)
|
|
363
|
+
oxides_data[oxide] = [cation, None, amount]
|
|
364
|
+
|
|
365
|
+
if name_lower not in self.cache:
|
|
366
|
+
vals = self._extract_values_from_yaml()
|
|
367
|
+
constr_minchem = MineralChemistry(w_traces=traces_data, molar_mass_pure=molar_mass_pure, majors=majors_data)
|
|
368
|
+
self.cache[name_lower] = {
|
|
369
|
+
"majors_data": majors_data,
|
|
370
|
+
"molar_mass_pure": molar_mass_pure,
|
|
371
|
+
"constants": vals,
|
|
372
|
+
"MineralChemistry": constr_minchem
|
|
373
|
+
}
|
|
374
|
+
else:
|
|
375
|
+
vals = self.cache[name_lower]["constants"]
|
|
376
|
+
constr_minchem = self.cache[name_lower]["MineralChemistry"]
|
|
377
|
+
constr_electr_density = self.cache[name_lower]["const_electron_density"]
|
|
378
|
+
constr_vol = self.cache[name_lower]["constr_volume"]
|
|
379
|
+
constr_density = self.cache[name_lower]["constr_density"]
|
|
380
|
+
constr_radiation = self.cache[name_lower]["constr_radiation"]
|
|
381
|
+
|
|
382
|
+
# Reading and assigning the mineral-specific information from the YAML file
|
|
383
|
+
val_key = vals["key"]
|
|
384
|
+
val_Z = vals["Z"]
|
|
385
|
+
if "K" in vals:
|
|
386
|
+
val_K = vals["K"]
|
|
387
|
+
val_G = vals["G"]
|
|
388
|
+
else:
|
|
389
|
+
val_a_K = float(vals["a_K"])
|
|
390
|
+
val_b_K = float(vals["b_K"])
|
|
391
|
+
val_a_G = float(vals["a_G"])
|
|
392
|
+
val_b_G = float(vals["b_G"])
|
|
393
|
+
|
|
394
|
+
molar_mass, amounts = constr_minchem.calculate_molar_mass()
|
|
395
|
+
amounts_dict = self._element_amounts_as_dict(amounts=amounts)
|
|
396
|
+
element = [self.elements[name] for name, *_ in amounts]
|
|
397
|
+
for oxide in oxides_data.keys():
|
|
398
|
+
cation = self._get_cation_element(oxide=oxide)
|
|
399
|
+
weight = oxides_data[oxide][2]
|
|
400
|
+
if weight != 1:
|
|
401
|
+
value = weight
|
|
402
|
+
else:
|
|
403
|
+
try:
|
|
404
|
+
value = amounts_dict[cation]*self.conversion_factors[oxide]["factor"]
|
|
405
|
+
except:
|
|
406
|
+
value = 0
|
|
407
|
+
oxides_data[oxide][1] = value
|
|
408
|
+
# (Molar) Volume
|
|
409
|
+
if "constr_volume" not in self.cache[name_lower]:
|
|
410
|
+
constr_vol = self._determine_volume_constructor(vals=vals)
|
|
411
|
+
self.cache[name_lower]["constr_volume"] = constr_vol
|
|
412
|
+
|
|
413
|
+
V, V_m = CrystallographicProperties().calculate_molar_volume(
|
|
414
|
+
constr_volume=constr_vol, constr_molar_volume=constr_minchem, cell_z=val_Z)
|
|
415
|
+
# Density
|
|
416
|
+
if "constr_density" not in self.cache[name_lower]:
|
|
417
|
+
constr_density = CrystalPhysics([molar_mass, val_Z, V])
|
|
418
|
+
self.cache[name_lower]["constr_density"] = constr_density
|
|
419
|
+
|
|
420
|
+
rho = CrystallographicProperties().calculate_mineral_density(constr_density=constr_density)
|
|
421
|
+
|
|
422
|
+
if "const_electron_density" not in self.cache[name_lower]:
|
|
423
|
+
constr_electr_density = wg(amounts=amounts, elements=element, rho_b=rho)
|
|
424
|
+
self.cache[name_lower]["const_electron_density"] = constr_electr_density
|
|
425
|
+
|
|
426
|
+
rho_e = CrystallographicProperties().calculate_electron_density(constr_electron_density=constr_electr_density)
|
|
427
|
+
# Elastic properties
|
|
428
|
+
if "K" not in vals:
|
|
429
|
+
val_K = (val_a_K*rho + val_b_K)*10**9
|
|
430
|
+
val_G = (val_a_G*rho + val_b_G)*10**9
|
|
431
|
+
E, nu = self.geophysical_properties.calculate_elastic_properties(bulk_mod=val_K, shear_mod=val_G)
|
|
432
|
+
# Seismic properties
|
|
433
|
+
vPvS, vP, vS = self.geophysical_properties.calculate_seismic_velocities(
|
|
434
|
+
bulk_mod=val_K, shear_mod=val_G, rho=rho)
|
|
435
|
+
# Radiation properties
|
|
436
|
+
if "constr_radiation" not in self.cache[name_lower]:
|
|
437
|
+
constr_radiation = wg(amounts=amounts, elements=element)
|
|
438
|
+
self.cache[name_lower]["constr_radiation"] = constr_radiation
|
|
439
|
+
|
|
440
|
+
gamma_ray, pe, U = self.geophysical_properties.calculate_radiation_properties(
|
|
441
|
+
constr_radiation=constr_radiation, rho_electron=rho_e)
|
|
442
|
+
# Electrical resistivity
|
|
443
|
+
p = None
|
|
444
|
+
# Results
|
|
445
|
+
results = {
|
|
446
|
+
"mineral": val_key, "state": val_state, "M": round(molar_mass, self.rounding),
|
|
447
|
+
"chemistry": {name: round(val[1], 6) for name, *val in amounts}, "rho": round(rho, self.rounding),
|
|
448
|
+
"rho_e": round(rho_e, self.rounding), "V": round(V_m, self.rounding), "vP": round(vP, self.rounding),
|
|
449
|
+
"vS": round(vS, self.rounding), "vP/vS": round(vPvS, self.rounding),
|
|
450
|
+
"K": round(val_K*10**(-9), self.rounding), "G": round(val_G*10**(-9), self.rounding),
|
|
451
|
+
"E": round(E*10**(-9), self.rounding), "nu": round(nu, 6), "GR": round(gamma_ray, self.rounding),
|
|
452
|
+
"PE": round(pe, self.rounding), "U": round(U, self.rounding), "p": p}
|
|
453
|
+
if "oxides" in self.yaml_data:
|
|
454
|
+
results["compounds"] = {name: round(val[1], 6) for name, val in oxides_data.items()}
|
|
455
|
+
elif "sulfides" in self.yaml_data:
|
|
456
|
+
results["compounds"] = {name: round(val[1], 6) for name, val in oxides_data.items()}
|
|
457
|
+
|
|
458
|
+
return results
|
|
459
|
+
|
|
460
|
+
def create_mineral_data_endmember_series(self, endmember_series, var_class, current_seed, rng):
|
|
461
|
+
"""
|
|
462
|
+
Synthetic mineral data generation for an user-selected mineral.
|
|
463
|
+
All mechanical properties (K, G, E) are stored in Pascals internally.
|
|
464
|
+
For output, they are converted to GPa.
|
|
465
|
+
"""
|
|
466
|
+
val_state = "variable"
|
|
467
|
+
|
|
468
|
+
if not hasattr(self, "cache"):
|
|
469
|
+
self.cache = {}
|
|
470
|
+
|
|
471
|
+
name_lower = endmember_series[self.name]["name_lower"]
|
|
472
|
+
val_key = endmember_series[self.name]["key"]
|
|
473
|
+
endmember = endmember_series[self.name]["endmembers"]
|
|
474
|
+
oxides_data = {}
|
|
475
|
+
for oxide in endmember_series[self.name]["oxides"]:
|
|
476
|
+
cation = self._get_cation_element(oxide=oxide)
|
|
477
|
+
oxides_data[oxide] = [cation, None]
|
|
478
|
+
|
|
479
|
+
if "endmembers" not in self.cache:
|
|
480
|
+
self.cache["endmembers"] = {}
|
|
481
|
+
|
|
482
|
+
if name_lower not in self.cache:
|
|
483
|
+
endmember_data = {}
|
|
484
|
+
list_elements = []
|
|
485
|
+
for mineral in endmember:
|
|
486
|
+
if mineral not in self.cache["endmembers"]:
|
|
487
|
+
mineral_data = var_class(name=mineral, random_seed=current_seed).generate_dataset(
|
|
488
|
+
number=1)
|
|
489
|
+
self.cache["endmembers"][mineral] = mineral_data
|
|
490
|
+
endmember_data[mineral] = self.cache["endmembers"][mineral]
|
|
491
|
+
mineral_data = endmember_data[mineral]
|
|
492
|
+
for element in mineral_data["chemistry"]:
|
|
493
|
+
if element not in list_elements:
|
|
494
|
+
list_elements.append(element)
|
|
495
|
+
constr_OxComp = OxideComposition()
|
|
496
|
+
|
|
497
|
+
self.cache[name_lower] = {
|
|
498
|
+
"endmember_data": endmember_data, "list_elements": list_elements, "OxComp": constr_OxComp}
|
|
499
|
+
else:
|
|
500
|
+
endmember_data = self.cache[name_lower]["endmember_data"]
|
|
501
|
+
list_elements = self.cache[name_lower]["list_elements"]
|
|
502
|
+
constr_OxComp = self.cache[name_lower]["OxComp"]
|
|
503
|
+
weights = rng.dirichlet(np.ones(len(endmember)))
|
|
504
|
+
fraction_endmember = dict(zip(endmember, weights))
|
|
505
|
+
|
|
506
|
+
properties = ["M", "rho", "rho_e", "V", "K", "G"]
|
|
507
|
+
helper_results = {
|
|
508
|
+
prop: sum(fraction_endmember[m]*endmember_data[m][prop][0] for m in endmember)
|
|
509
|
+
for prop in properties
|
|
510
|
+
}
|
|
511
|
+
# Amounts
|
|
512
|
+
amounts = []
|
|
513
|
+
for element in list_elements:
|
|
514
|
+
amount = sum(fraction_endmember[mineral]*endmember_data[mineral]["chemistry"].get(element, [0])[0]
|
|
515
|
+
for mineral in endmember)
|
|
516
|
+
amounts.append([element, self.elements[element][1], amount])
|
|
517
|
+
element = [self.elements[name] for name, *_ in amounts]
|
|
518
|
+
# Oxide amounts
|
|
519
|
+
amounts_dict = constr_OxComp._element_amounts_as_dict(amounts=amounts)
|
|
520
|
+
try:
|
|
521
|
+
for oxide in oxides_data.keys():
|
|
522
|
+
cation = constr_OxComp._get_cation_element(oxide=oxide)
|
|
523
|
+
value = amounts_dict[cation]*self.conversion_factors[oxide]["factor"]
|
|
524
|
+
oxides_data[oxide][1] = value
|
|
525
|
+
except:
|
|
526
|
+
print("No oxide data available!")
|
|
527
|
+
# Elastic properties
|
|
528
|
+
val_K = helper_results["K"]*10**9
|
|
529
|
+
val_G = helper_results["G"]*10**9
|
|
530
|
+
rho = helper_results["rho"]
|
|
531
|
+
rho_e = helper_results["rho_e"]
|
|
532
|
+
E, nu = self.geophysical_properties.calculate_elastic_properties(bulk_mod=val_K, shear_mod=val_G)
|
|
533
|
+
# Seismic properties
|
|
534
|
+
vPvS, vP, vS = self.geophysical_properties.calculate_seismic_velocities(
|
|
535
|
+
bulk_mod=val_K, shear_mod=val_G, rho=rho)
|
|
536
|
+
# Radiation properties
|
|
537
|
+
constr_radiation = wg(amounts=amounts, elements=element)
|
|
538
|
+
gamma_ray, pe, U = self.geophysical_properties.calculate_radiation_properties(
|
|
539
|
+
constr_radiation=constr_radiation, rho_electron=rho_e)
|
|
540
|
+
# Electrical resistivity
|
|
541
|
+
p = None
|
|
542
|
+
# Results
|
|
543
|
+
results = {
|
|
544
|
+
"mineral": val_key, "state": val_state, "M": round(helper_results["M"], self.rounding),
|
|
545
|
+
"chemistry": {name: round(val[1], 6) for name, *val in amounts}, "rho": round(rho, self.rounding),
|
|
546
|
+
"rho_e": round(rho_e, self.rounding), "V": round(helper_results["V"], self.rounding),
|
|
547
|
+
"vP": round(vP, self.rounding), "vS": round(vS, self.rounding),
|
|
548
|
+
"vP/vS": round(vPvS, self.rounding), "K": round(val_K*10**(-9), self.rounding),
|
|
549
|
+
"G": round(val_G*10**(-9), self.rounding), "E": round(E*10**(-9), self.rounding), "nu": round(nu, 6),
|
|
550
|
+
"GR": round(gamma_ray, self.rounding), "PE": round(pe, self.rounding), "U": round(U, self.rounding), "p": p}
|
|
551
|
+
try:
|
|
552
|
+
results["compounds"] = {name: round(val[1], 6) for name, val in oxides_data.items()}
|
|
553
|
+
except:
|
|
554
|
+
print("No oxide/sulfide data available!")
|
|
555
|
+
return results
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*-coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
#-----------------------------------------------
|
|
5
|
+
|
|
6
|
+
# Name: config.py
|
|
7
|
+
# Author: Maximilian A. Beeskow
|
|
8
|
+
# Version: 1.0
|
|
9
|
+
# Date: 16.10.2025
|
|
10
|
+
|
|
11
|
+
#-----------------------------------------------
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
Module: config.py
|
|
15
|
+
Defines configuration parameters for synthetic mineral data generation.
|
|
16
|
+
Used by analysis and synthesis modules within gebpy.core.minerals.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
# PACKAGES
|
|
20
|
+
from typing import Optional
|
|
21
|
+
|
|
22
|
+
# CODE
|
|
23
|
+
class MineralConfiguration:
|
|
24
|
+
"""
|
|
25
|
+
Configuration of the mineral data generation.
|
|
26
|
+
- name: mineral name (e.g., 'Olivine')
|
|
27
|
+
- n_datapoints: Number of generated data points (> 0)
|
|
28
|
+
- random_seed: integer seed; if None, defaults to 42
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
name: str,
|
|
34
|
+
n_datapoints: int,
|
|
35
|
+
random_seed: Optional[int] = None
|
|
36
|
+
) -> None:
|
|
37
|
+
self.name = name
|
|
38
|
+
self.n_datapoints = n_datapoints
|
|
39
|
+
self.random_seed = 42 if random_seed is None else random_seed
|
|
40
|
+
self._validate()
|
|
41
|
+
|
|
42
|
+
def __repr__(self) -> str:
|
|
43
|
+
return (
|
|
44
|
+
f"<MineralConfiguration name={self.name!r}, "
|
|
45
|
+
f"n_datapoints={self.n_datapoints}, "
|
|
46
|
+
f"random_seed={self.random_seed}>"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def set_name(self, new_name: str) -> None:
|
|
50
|
+
if not new_name:
|
|
51
|
+
raise ValueError("Mineral name must not be empty. Please assign a valid mineral name.")
|
|
52
|
+
self.name = new_name
|
|
53
|
+
|
|
54
|
+
def set_number_of_datapoints(self, new_n_datapoints: int) -> None:
|
|
55
|
+
if not isinstance(new_n_datapoints, int):
|
|
56
|
+
raise TypeError("n_datapoints must be an integer.")
|
|
57
|
+
if new_n_datapoints <= 0:
|
|
58
|
+
raise ValueError("The number of data points must be positive.")
|
|
59
|
+
self.n_datapoints = new_n_datapoints
|
|
60
|
+
|
|
61
|
+
def set_random_seed(self, new_random_seed: Optional[int]) -> None:
|
|
62
|
+
self.random_seed = 42 if new_random_seed is None else new_random_seed
|
|
63
|
+
if self.random_seed < 0:
|
|
64
|
+
raise ValueError("The random number seed must be >= 0 or None.")
|
|
65
|
+
|
|
66
|
+
def _validate(self) -> None:
|
|
67
|
+
if not self.name:
|
|
68
|
+
raise ValueError("Mineral name must not be empty. Please assign a valid mineral name.")
|
|
69
|
+
if not isinstance(self.n_datapoints, int):
|
|
70
|
+
raise TypeError("n_datapoints must be an integer.")
|
|
71
|
+
if self.n_datapoints <= 0:
|
|
72
|
+
raise ValueError("The number of data points must be positive.")
|
|
73
|
+
if self.random_seed < 0:
|
|
74
|
+
raise ValueError("The random number seed must be >= 0 or None.")
|
|
75
|
+
|
|
76
|
+
# DEFAULT EXAMPLE
|
|
77
|
+
DEFAULT_CONFIG = MineralConfiguration(name="Olivine", n_datapoints=10)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|