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,395 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*-coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
#-----------------------------------------------
|
|
5
|
+
|
|
6
|
+
# Name: isotropic_rocks.py
|
|
7
|
+
# Author: Maximilian A. Beeskow
|
|
8
|
+
# Version: 1.0
|
|
9
|
+
# Date: 17.12.2025
|
|
10
|
+
|
|
11
|
+
#-----------------------------------------------
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
Module: isotropic_rocks.py
|
|
15
|
+
This module controls the generation of synthetic data for isotropic rocks.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# PACKAGES
|
|
19
|
+
import yaml
|
|
20
|
+
import numpy as np
|
|
21
|
+
import pandas as pd
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
# MODULES
|
|
25
|
+
from ..minerals.synthesis import MineralDataGeneration
|
|
26
|
+
from ..rocks.common import RockGeneration
|
|
27
|
+
from ..physics.common import Geophysics
|
|
28
|
+
|
|
29
|
+
# Code
|
|
30
|
+
BASE_PATH = Path(__file__).resolve().parents[2]
|
|
31
|
+
DATA_PATH = BASE_PATH / "data_rocks"
|
|
32
|
+
|
|
33
|
+
class IsotropicRocks:
|
|
34
|
+
_yaml_cache = {}
|
|
35
|
+
_mineralogy_cache = {}
|
|
36
|
+
_mineral_groups_cache = {}
|
|
37
|
+
_rocks = {"Sandstone", "Limestone", "Dolostone", "Marl"}
|
|
38
|
+
|
|
39
|
+
def __init__(self, name, random_seed) -> None:
|
|
40
|
+
self.name = name
|
|
41
|
+
self.random_seed = random_seed
|
|
42
|
+
self.rng = np.random.default_rng(random_seed)
|
|
43
|
+
self.current_seed = int(np.round(self.rng.uniform(0, 1000), 0))
|
|
44
|
+
self.data_path = DATA_PATH
|
|
45
|
+
self.rock_gen = RockGeneration()
|
|
46
|
+
self.geophysics = Geophysics()
|
|
47
|
+
self.conversion_factors = self.rock_gen._determine_oxide_conversion_factors()
|
|
48
|
+
self.cache = {}
|
|
49
|
+
|
|
50
|
+
def _load_yaml(self, rock_name: str) -> dict:
|
|
51
|
+
# 1) Cache-Hit
|
|
52
|
+
if rock_name in IsotropicRocks._yaml_cache:
|
|
53
|
+
return IsotropicRocks._yaml_cache[rock_name]
|
|
54
|
+
|
|
55
|
+
# 2) Laden von Disk
|
|
56
|
+
yaml_file = self.data_path/f"{rock_name}.yaml"
|
|
57
|
+
if not yaml_file.exists():
|
|
58
|
+
raise FileNotFoundError(f"No YAML file found for {rock_name}.")
|
|
59
|
+
|
|
60
|
+
with open(yaml_file, "r") as f:
|
|
61
|
+
data = yaml.safe_load(f)
|
|
62
|
+
|
|
63
|
+
if "mineralogy" in data and rock_name not in IsotropicRocks._mineralogy_cache:
|
|
64
|
+
self._compile_mineralogy(rock_name, data["mineralogy"])
|
|
65
|
+
|
|
66
|
+
if "mineral_groups" in data:
|
|
67
|
+
self._compile_mineral_groups(rock_name, data["mineral_groups"])
|
|
68
|
+
|
|
69
|
+
# 3) Cache schreiben
|
|
70
|
+
IsotropicRocks._yaml_cache[rock_name] = data
|
|
71
|
+
|
|
72
|
+
return data
|
|
73
|
+
|
|
74
|
+
def _compile_mineralogy(self, rock_name: str, mineralogy_dict: dict):
|
|
75
|
+
"""
|
|
76
|
+
Extracts and compiles all chemistry formulas from the YAML file.
|
|
77
|
+
Stores the compiled ASTs in the global formula cache.
|
|
78
|
+
"""
|
|
79
|
+
if rock_name not in IsotropicRocks._mineralogy_cache:
|
|
80
|
+
IsotropicRocks._mineralogy_cache[rock_name] = {}
|
|
81
|
+
|
|
82
|
+
for element, entry in mineralogy_dict.items():
|
|
83
|
+
mineral = element
|
|
84
|
+
interval = list(entry.values())
|
|
85
|
+
lower_limit = interval[0]
|
|
86
|
+
upper_limit = interval[1]
|
|
87
|
+
compiled = [lower_limit, upper_limit]
|
|
88
|
+
IsotropicRocks._mineralogy_cache[rock_name][mineral] = compiled
|
|
89
|
+
|
|
90
|
+
def _compile_mineral_groups(self, rock_name: str, group_dict: dict):
|
|
91
|
+
if rock_name not in IsotropicRocks._mineral_groups_cache:
|
|
92
|
+
IsotropicRocks._mineral_groups_cache[rock_name] = {}
|
|
93
|
+
|
|
94
|
+
for group, entry in group_dict.items():
|
|
95
|
+
minerals = entry["minerals"]
|
|
96
|
+
min_val = entry["min"]
|
|
97
|
+
max_val = entry["max"]
|
|
98
|
+
|
|
99
|
+
IsotropicRocks._mineral_groups_cache[rock_name][group] = {
|
|
100
|
+
"minerals": minerals,
|
|
101
|
+
"min": min_val,
|
|
102
|
+
"max": max_val
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
def _sample_mineralogy(self, rock_name: str, number: int):
|
|
106
|
+
has_groups = rock_name in IsotropicRocks._mineral_groups_cache
|
|
107
|
+
|
|
108
|
+
if not has_groups:
|
|
109
|
+
# ---- Modus A: flach ----
|
|
110
|
+
mineral_limits = IsotropicRocks._mineralogy_cache[rock_name]
|
|
111
|
+
mins = [v[0] for v in mineral_limits.values()]
|
|
112
|
+
maxs = [v[1] for v in mineral_limits.values()]
|
|
113
|
+
minerals = list(mineral_limits.keys())
|
|
114
|
+
|
|
115
|
+
comp = self._sample_bounded_simplex_batch(mins, maxs, number)
|
|
116
|
+
return minerals, comp
|
|
117
|
+
|
|
118
|
+
# ---- Modus B: gruppiert ----
|
|
119
|
+
groups = IsotropicRocks._mineral_groups_cache[rock_name]
|
|
120
|
+
mineral_limits = IsotropicRocks._mineralogy_cache[rock_name]
|
|
121
|
+
|
|
122
|
+
# 1️⃣ Gruppen + freie Minerale
|
|
123
|
+
group_names = list(groups.keys())
|
|
124
|
+
group_mins = [groups[g]["min"] for g in group_names]
|
|
125
|
+
group_maxs = [groups[g]["max"] for g in group_names]
|
|
126
|
+
|
|
127
|
+
free_minerals = [
|
|
128
|
+
m for m in mineral_limits
|
|
129
|
+
if not any(m in groups[g]["minerals"] for g in groups)
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
free_mins = [mineral_limits[m][0] for m in free_minerals]
|
|
133
|
+
free_maxs = [mineral_limits[m][1] for m in free_minerals]
|
|
134
|
+
|
|
135
|
+
labels = group_names + free_minerals
|
|
136
|
+
mins = group_mins + free_mins
|
|
137
|
+
maxs = group_maxs + free_maxs
|
|
138
|
+
|
|
139
|
+
# 2️⃣ Top-Level-Sampling
|
|
140
|
+
top_comp = self._sample_bounded_simplex_batch(mins, maxs, number)
|
|
141
|
+
|
|
142
|
+
# 3️⃣ Gruppen intern auflösen
|
|
143
|
+
mineral_list = []
|
|
144
|
+
mineral_comp = []
|
|
145
|
+
|
|
146
|
+
for i, label in enumerate(labels):
|
|
147
|
+
frac = top_comp[:, i]
|
|
148
|
+
|
|
149
|
+
if label in groups:
|
|
150
|
+
minerals = groups[label]["minerals"]
|
|
151
|
+
n = len(minerals)
|
|
152
|
+
split = self.rng.dirichlet(np.ones(n), size=number)
|
|
153
|
+
|
|
154
|
+
for j, m in enumerate(minerals):
|
|
155
|
+
mineral_list.append(m)
|
|
156
|
+
mineral_comp.append(frac * split[:, j])
|
|
157
|
+
else:
|
|
158
|
+
mineral_list.append(label)
|
|
159
|
+
mineral_comp.append(frac)
|
|
160
|
+
|
|
161
|
+
comp = np.vstack(mineral_comp).T
|
|
162
|
+
return mineral_list, comp
|
|
163
|
+
|
|
164
|
+
def _sample_bounded_simplex_batch(self, min_vals, max_vals, number):
|
|
165
|
+
min_vals = np.asarray(min_vals, dtype=float)
|
|
166
|
+
max_vals = np.asarray(max_vals, dtype=float)
|
|
167
|
+
n = len(min_vals)
|
|
168
|
+
|
|
169
|
+
# --- Consistency ---
|
|
170
|
+
if min_vals.sum() > 1:
|
|
171
|
+
raise ValueError("Sum of minimum fractions > 1")
|
|
172
|
+
|
|
173
|
+
if max_vals.sum() < 1:
|
|
174
|
+
raise ValueError("Sum of maximum fractions < 1")
|
|
175
|
+
|
|
176
|
+
span = max_vals - min_vals
|
|
177
|
+
samples = np.zeros((number, n))
|
|
178
|
+
|
|
179
|
+
for i in range(number):
|
|
180
|
+
remaining = 1.0 - min_vals.sum()
|
|
181
|
+
order = np.arange(n)
|
|
182
|
+
|
|
183
|
+
self.rng.shuffle(order)
|
|
184
|
+
x = np.zeros(n)
|
|
185
|
+
|
|
186
|
+
for j in order[:-1]:
|
|
187
|
+
upper = min(span[j], remaining)
|
|
188
|
+
val = self.rng.uniform(0, upper)
|
|
189
|
+
x[j] = val
|
|
190
|
+
remaining -= val
|
|
191
|
+
|
|
192
|
+
x[order[-1]] = remaining
|
|
193
|
+
samples[i] = min_vals + x
|
|
194
|
+
|
|
195
|
+
return samples
|
|
196
|
+
|
|
197
|
+
def _collect_mineral_data(self, list_minerals, number):
|
|
198
|
+
_mineral_data = []
|
|
199
|
+
for index, mineral in enumerate(list_minerals):
|
|
200
|
+
data_init = MineralDataGeneration(mineral, number)
|
|
201
|
+
data_mineral = data_init.generate_data()
|
|
202
|
+
is_fixed = data_mineral.shape[0] == 1
|
|
203
|
+
if is_fixed and number > 1:
|
|
204
|
+
data_mineral = pd.concat([data_mineral]*number, ignore_index=True)
|
|
205
|
+
elif not is_fixed and data_mineral.shape[0] != number:
|
|
206
|
+
raise ValueError(
|
|
207
|
+
f"Mineral '{mineral}' returned {data_mineral.shape[0]} rows, "
|
|
208
|
+
f"but expected {number}.")
|
|
209
|
+
_mineral_data.append(data_mineral)
|
|
210
|
+
|
|
211
|
+
return _mineral_data
|
|
212
|
+
|
|
213
|
+
def _extract_mineral_property_data(self, list_minerals, data_mineral, property):
|
|
214
|
+
arrays = [data_mineral[i][property].to_numpy() for i in range(len(list_minerals))]
|
|
215
|
+
return np.vstack(arrays)
|
|
216
|
+
|
|
217
|
+
def _extract_element_data(self, data_minerals, list_elements):
|
|
218
|
+
seen = set(list_elements)
|
|
219
|
+
ordered = list(list_elements)
|
|
220
|
+
|
|
221
|
+
for dataset in data_minerals:
|
|
222
|
+
for key in dataset.keys():
|
|
223
|
+
if key.startswith("chemistry."):
|
|
224
|
+
element = key[len("chemistry."):]
|
|
225
|
+
if element not in seen:
|
|
226
|
+
seen.add(element)
|
|
227
|
+
ordered.append(element)
|
|
228
|
+
|
|
229
|
+
return ordered
|
|
230
|
+
|
|
231
|
+
def _extract_oxide_data(self, data_minerals, list_oxides):
|
|
232
|
+
seen = set(list_oxides)
|
|
233
|
+
ordered = list(list_oxides)
|
|
234
|
+
|
|
235
|
+
for dataset in data_minerals:
|
|
236
|
+
for key in dataset.keys():
|
|
237
|
+
if key.startswith("compounds."):
|
|
238
|
+
oxide = key[len("compounds."):]
|
|
239
|
+
if oxide not in seen:
|
|
240
|
+
seen.add(oxide)
|
|
241
|
+
ordered.append(oxide)
|
|
242
|
+
|
|
243
|
+
# Spezialfall Pyrit
|
|
244
|
+
if dataset["mineral"][0] == "Py":
|
|
245
|
+
for oxide in ("Fe2O3", "SO3"):
|
|
246
|
+
if oxide not in seen:
|
|
247
|
+
seen.add(oxide)
|
|
248
|
+
ordered.append(oxide)
|
|
249
|
+
if "FeS2" in seen:
|
|
250
|
+
seen.remove("FeS2")
|
|
251
|
+
ordered = [o for o in ordered if o != "FeS2"]
|
|
252
|
+
|
|
253
|
+
return ordered
|
|
254
|
+
|
|
255
|
+
def _update_chemistry_data(self, _bulk_data, data_minerals, data_composition, element, number):
|
|
256
|
+
n_minerals = len(data_minerals)
|
|
257
|
+
helper = np.zeros((n_minerals, number))
|
|
258
|
+
key_element = "chemistry." + element
|
|
259
|
+
|
|
260
|
+
for i, dataset in enumerate(data_minerals):
|
|
261
|
+
if key_element in dataset:
|
|
262
|
+
helper[i, :] = dataset[key_element].to_numpy()
|
|
263
|
+
|
|
264
|
+
bulk_values = np.sum(data_composition * helper.T, axis=1)
|
|
265
|
+
_bulk_data["w." + element] = bulk_values
|
|
266
|
+
|
|
267
|
+
return _bulk_data
|
|
268
|
+
|
|
269
|
+
def _update_oxide_data(self, bulk_data, list_oxides):
|
|
270
|
+
for oxide in list_oxides:
|
|
271
|
+
cation, anion = self.rock_gen._get_elements_of_compound(compound=oxide)
|
|
272
|
+
if anion == "O":
|
|
273
|
+
key_cation = "w." + cation
|
|
274
|
+
values = self.conversion_factors[oxide]["factor"]*bulk_data[key_cation]
|
|
275
|
+
key_oxide = "w." + oxide
|
|
276
|
+
bulk_data[key_oxide] = values
|
|
277
|
+
else:
|
|
278
|
+
print("There is a non-oxide compound part of the list.")
|
|
279
|
+
|
|
280
|
+
return bulk_data
|
|
281
|
+
|
|
282
|
+
def _assign_mineral_amounts(self, bulk_data, data_amounts):
|
|
283
|
+
for mineral, values in data_amounts.items():
|
|
284
|
+
key_mineral = "phi." + mineral
|
|
285
|
+
bulk_data[key_mineral] = values
|
|
286
|
+
|
|
287
|
+
return bulk_data
|
|
288
|
+
|
|
289
|
+
def collect_geophysical_properties(self, _helper_bulk_data, rho_f, n):
|
|
290
|
+
# Update bulk density data
|
|
291
|
+
(_helper_bulk_data["rho"], _helper_bulk_data["rho_s"],
|
|
292
|
+
_helper_bulk_data["rho_f"]) = self.geophysics.calculate_bulk_density_data(
|
|
293
|
+
v_phi=_helper_bulk_data["porosity"], val_rho=_helper_bulk_data["rho"], val_rho_f=rho_f,
|
|
294
|
+
val_n=n)
|
|
295
|
+
# Update bulk seismic velocity data
|
|
296
|
+
(_helper_bulk_data["vP"], _helper_bulk_data["vS"],
|
|
297
|
+
_helper_bulk_data["vP/vS"]) = self.geophysics.calculate_seismic_velocities(
|
|
298
|
+
val_K=_helper_bulk_data["K"], val_G=_helper_bulk_data["G"], val_rho=_helper_bulk_data["rho"])
|
|
299
|
+
# Update elastic parameter data
|
|
300
|
+
(_helper_bulk_data["E"], _helper_bulk_data["poisson"],
|
|
301
|
+
_helper_bulk_data["lame"]) = self.geophysics.calculate_elastic_parameter_data(
|
|
302
|
+
val_K=_helper_bulk_data["K"], val_G=_helper_bulk_data["G"])
|
|
303
|
+
|
|
304
|
+
return _helper_bulk_data
|
|
305
|
+
|
|
306
|
+
def collect_initial_compositional_data(self, list_minerals, n):
|
|
307
|
+
_helper_elements = []
|
|
308
|
+
_helper_oxides = []
|
|
309
|
+
_mineral_data = self._collect_mineral_data(list_minerals=list_minerals, number=n)
|
|
310
|
+
_helper_elements = self._extract_element_data(data_minerals=_mineral_data, list_elements=_helper_elements)
|
|
311
|
+
_helper_oxides = self._extract_oxide_data(data_minerals=_mineral_data, list_oxides=_helper_oxides)
|
|
312
|
+
|
|
313
|
+
return _mineral_data, _helper_elements, _helper_oxides
|
|
314
|
+
|
|
315
|
+
def collect_initial_bulk_data(self, list_minerals, _mineral_data, _helper_composition):
|
|
316
|
+
_helper_bulk_data = {}
|
|
317
|
+
for property in ["rho", "K", "G", "GR", "PE"]:
|
|
318
|
+
_helper_property = self._extract_mineral_property_data(
|
|
319
|
+
list_minerals=list_minerals, data_mineral=_mineral_data, property=property)
|
|
320
|
+
_helper_bulk_data[property] = np.sum(_helper_composition*_helper_property.T, axis=1)
|
|
321
|
+
|
|
322
|
+
return _helper_bulk_data
|
|
323
|
+
|
|
324
|
+
def update_compositional_bulk_data(
|
|
325
|
+
self, _helper_elements, _helper_bulk_data, _mineral_data, _helper_composition, _helper_oxides,
|
|
326
|
+
_helper_mineral_amounts, n):
|
|
327
|
+
for element in _helper_elements:
|
|
328
|
+
_helper_bulk_data = self._update_chemistry_data(
|
|
329
|
+
_bulk_data=_helper_bulk_data, data_minerals=_mineral_data, data_composition=_helper_composition,
|
|
330
|
+
element=element, number=n)
|
|
331
|
+
# Update oxide data
|
|
332
|
+
_helper_bulk_data = self._update_oxide_data(bulk_data=_helper_bulk_data, list_oxides=_helper_oxides)
|
|
333
|
+
# Update rock composition data
|
|
334
|
+
_helper_bulk_data = self._assign_mineral_amounts(
|
|
335
|
+
bulk_data=_helper_bulk_data, data_amounts=_helper_mineral_amounts)
|
|
336
|
+
|
|
337
|
+
return _helper_bulk_data
|
|
338
|
+
|
|
339
|
+
def generate_dataset(self, number: int = 1, fluid: str = "water", density_fluid=None) -> None:
|
|
340
|
+
if density_fluid is None:
|
|
341
|
+
if fluid == "water":
|
|
342
|
+
density_fluid = 1000
|
|
343
|
+
elif fluid == "oil":
|
|
344
|
+
density_fluid = 800
|
|
345
|
+
elif fluid == "natural gas":
|
|
346
|
+
density_fluid = 750
|
|
347
|
+
|
|
348
|
+
siliciclastics = {"Sandstone"}
|
|
349
|
+
data_yaml = self._load_yaml(rock_name=self.name)
|
|
350
|
+
min_porosity = data_yaml["physical_properties"]["porosity"]["min"]
|
|
351
|
+
max_porosity = data_yaml["physical_properties"]["porosity"]["max"]
|
|
352
|
+
porosity = self.rng.uniform(min_porosity, max_porosity, number)
|
|
353
|
+
mineral_limits = IsotropicRocks._mineralogy_cache[self.name]
|
|
354
|
+
_limits = {"lower": [], "upper": []}
|
|
355
|
+
|
|
356
|
+
for mineral, values in mineral_limits.items():
|
|
357
|
+
_limits["lower"].append(values[0])
|
|
358
|
+
_limits["upper"].append(values[1])
|
|
359
|
+
|
|
360
|
+
list_minerals = list(IsotropicRocks._mineralogy_cache[self.name].keys())
|
|
361
|
+
_properties = ["rho", "vP", "vS", "K", "G", "GR", "PE"]
|
|
362
|
+
_bulk_data = {}
|
|
363
|
+
# Collect mineralogical composition data
|
|
364
|
+
n_minerals = len(list_minerals)
|
|
365
|
+
_helper_composition = np.zeros((number, n_minerals))
|
|
366
|
+
_helper_mineral_amounts = {mineral: np.zeros(number) for mineral in list_minerals}
|
|
367
|
+
|
|
368
|
+
_helper_composition = self._sample_bounded_simplex_batch(
|
|
369
|
+
min_vals=_limits["lower"], max_vals=_limits["upper"], number=number)
|
|
370
|
+
_helper_mineral_amounts = {mineral: _helper_composition[:, j] for j, mineral in enumerate(list_minerals)}
|
|
371
|
+
|
|
372
|
+
# Collect mineral data
|
|
373
|
+
_mineral_data, _helper_elements, _helper_oxides = self.collect_initial_compositional_data(
|
|
374
|
+
list_minerals=list_minerals, n=number)
|
|
375
|
+
# Collect bulk data
|
|
376
|
+
_helper_bulk_data = self.collect_initial_bulk_data(
|
|
377
|
+
list_minerals=list_minerals, _mineral_data=_mineral_data, _helper_composition=_helper_composition)
|
|
378
|
+
# Assign porosity data
|
|
379
|
+
_helper_bulk_data["porosity"] = porosity
|
|
380
|
+
# Collect geophysical data
|
|
381
|
+
_helper_bulk_data = self.collect_geophysical_properties(
|
|
382
|
+
_helper_bulk_data=_helper_bulk_data, rho_f=density_fluid, n=number)
|
|
383
|
+
# Update chemistry data
|
|
384
|
+
_helper_bulk_data = self.update_compositional_bulk_data(
|
|
385
|
+
_helper_elements=_helper_elements, _helper_bulk_data=_helper_bulk_data, _mineral_data=_mineral_data,
|
|
386
|
+
_helper_composition=_helper_composition, _helper_oxides=_helper_oxides,
|
|
387
|
+
_helper_mineral_amounts=_helper_mineral_amounts, n=number)
|
|
388
|
+
# Conversion to a pandas dataframe object
|
|
389
|
+
_bulk_data = pd.DataFrame(_helper_bulk_data)
|
|
390
|
+
|
|
391
|
+
return _bulk_data
|
|
392
|
+
|
|
393
|
+
# TEST
|
|
394
|
+
if __name__ == "__main__":
|
|
395
|
+
DEFAULT_DATA = IsotropicRocks(name="Sandstone", random_seed=42).generate_dataset(number=10)
|