bmh 2026.1__tar.gz
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.
- bmh-2026.1/PKG-INFO +37 -0
- bmh-2026.1/README.md +6 -0
- bmh-2026.1/pyproject.toml +38 -0
- bmh-2026.1/src/bmh/__init__.py +0 -0
- bmh-2026.1/src/bmh/benchmark/__init__.py +1 -0
- bmh-2026.1/src/bmh/benchmark/core.py +159 -0
- bmh-2026.1/src/bmh/benchmark/data.py +211 -0
- bmh-2026.1/src/bmh/benchmark/material_deposition.py +398 -0
- bmh-2026.1/src/bmh/benchmark/reference_meta.py +57 -0
- bmh-2026.1/src/bmh/benchmark/simulator_meta.py +63 -0
- bmh-2026.1/src/bmh/helpers/__init__.py +0 -0
- bmh-2026.1/src/bmh/helpers/identifiers.py +19 -0
- bmh-2026.1/src/bmh/helpers/math.py +14 -0
- bmh-2026.1/src/bmh/helpers/reclaimed_material_evaluator.py +56 -0
- bmh-2026.1/src/bmh/helpers/simple.py +62 -0
- bmh-2026.1/src/bmh/helpers/stockpile_math.py +82 -0
- bmh-2026.1/src/bmh/helpers/test/__init__.py +0 -0
- bmh-2026.1/src/bmh/helpers/test/test_identifiers.py +24 -0
- bmh-2026.1/src/bmh/helpers/test/test_stockpile_math.py +63 -0
- bmh-2026.1/src/bmh/optimization/__init__.py +1 -0
- bmh-2026.1/src/bmh/optimization/homogenization_problem/__init__.py +0 -0
- bmh-2026.1/src/bmh/optimization/homogenization_problem/generator.py +84 -0
- bmh-2026.1/src/bmh/optimization/homogenization_problem/homogenization_problem.py +353 -0
- bmh-2026.1/src/bmh/optimization/homogenization_problem/test/__init__.py +0 -0
- bmh-2026.1/src/bmh/optimization/homogenization_problem/test/test_homogenization_problem.py +146 -0
- bmh-2026.1/src/bmh/optimization/optimization.py +478 -0
- bmh-2026.1/src/bmh/optimization/optimization_result.py +12 -0
- bmh-2026.1/src/bmh/optimization/plot_server/__init__.py +0 -0
- bmh-2026.1/src/bmh/optimization/plot_server/bokeh_plot_server.py +388 -0
- bmh-2026.1/src/bmh/optimization/plot_server/plot_server.py +88 -0
- bmh-2026.1/src/bmh/simulation/__init__.py +1 -0
- bmh-2026.1/src/bmh/simulation/blending_simulator.py +77 -0
- bmh-2026.1/src/bmh/simulation/bsl_blending_simulator.py +88 -0
- bmh-2026.1/src/bmh/simulation/mathematical_blending/__init__.py +0 -0
- bmh-2026.1/src/bmh/simulation/mathematical_blending/mathematical_blending.py +21 -0
- bmh-2026.1/src/bmh/simulation/mathematical_blending/tests/__init__.py +0 -0
- bmh-2026.1/src/bmh/simulation/mathematical_blending/tests/test_mathematical_blending.py +30 -0
- bmh-2026.1/src/bmh/simulation/mathematical_blending_simulator.py +26 -0
- bmh-2026.1/src/bmh/simulation/smooth_blending_simulator.py +33 -0
bmh-2026.1/PKG-INFO
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bmh
|
|
3
|
+
Version: 2026.1
|
|
4
|
+
Summary: Library for Bulk Material Homogenization simulation and optimization
|
|
5
|
+
Keywords: bulk-material,homogenization,simulation,optimization,bmh,jmetalpy
|
|
6
|
+
Author: Michael Cipold
|
|
7
|
+
Author-email: Michael Cipold <github@cipold.de>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering
|
|
13
|
+
Requires-Dist: jmetalpy==1.5.5
|
|
14
|
+
Requires-Dist: numpy>=1.20.0
|
|
15
|
+
Requires-Dist: pandas>=1.3.0
|
|
16
|
+
Requires-Dist: bmh-jmetalpy-extensions~=2026.1
|
|
17
|
+
Requires-Dist: blending-simulator-lib~=2026.1
|
|
18
|
+
Requires-Dist: bokeh ; extra == 'bokehplotserver'
|
|
19
|
+
Requires-Dist: dask ; extra == 'daskevaluator'
|
|
20
|
+
Requires-Dist: pytest ; extra == 'dev'
|
|
21
|
+
Requires-Dist: dask ; extra == 'distributedevaluator'
|
|
22
|
+
Requires-Dist: distributed ; extra == 'distributedevaluator'
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Project-URL: Homepage, https://github.com/jcbachmann/blending-evaluation
|
|
25
|
+
Project-URL: Repository, https://github.com/jcbachmann/blending-evaluation
|
|
26
|
+
Provides-Extra: bokehplotserver
|
|
27
|
+
Provides-Extra: daskevaluator
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Provides-Extra: distributedevaluator
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Bulk Material Homogenization (bmh)
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/bmh/)
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
|
|
37
|
+
Library for simulation, optimization, and evaluation of Bulk Material Homogenization processes.
|
bmh-2026.1/README.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bulk Material Homogenization (bmh)
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/bmh/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Library for simulation, optimization, and evaluation of Bulk Material Homogenization processes.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "bmh"
|
|
3
|
+
version = "2026.1"
|
|
4
|
+
description = "Library for Bulk Material Homogenization simulation and optimization"
|
|
5
|
+
keywords = ["bulk-material", "homogenization", "simulation", "optimization", "bmh", "jmetalpy"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Michael Cipold", email = "github@cipold.de" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"jmetalpy==1.5.5",
|
|
13
|
+
"numpy>=1.20.0",
|
|
14
|
+
"pandas>=1.3.0",
|
|
15
|
+
"bmh_jmetalpy_extensions~=2026.1",
|
|
16
|
+
"blending_simulator_lib~=2026.1",
|
|
17
|
+
]
|
|
18
|
+
license = "MIT"
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Development Status :: 4 - Beta",
|
|
23
|
+
"Topic :: Scientific/Engineering",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/jcbachmann/blending-evaluation"
|
|
28
|
+
Repository = "https://github.com/jcbachmann/blending-evaluation"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
BokehPlotServer = ["bokeh"]
|
|
32
|
+
DaskEvaluator = ["dask"]
|
|
33
|
+
DistributedEvaluator = ["dask", "distributed"]
|
|
34
|
+
dev = ["pytest"]
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["uv_build>=0.11.3,<0.12"]
|
|
38
|
+
build-backend = "uv_build"
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
name = "benchmark"
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from ..helpers import math
|
|
6
|
+
from ..helpers.reclaimed_material_evaluator import ReclaimedMaterialEvaluator
|
|
7
|
+
from .data import BenchmarkData, prepare_path
|
|
8
|
+
from .material_deposition import DepositionMeta, MaterialDeposition, MaterialMeta, write_data_file
|
|
9
|
+
from .reference_meta import ReferenceMeta
|
|
10
|
+
from .simulator_meta import SimulatorMeta
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_simulator(simulator_meta: SimulatorMeta):
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
logger.debug(f'Acquiring simulator type for "{simulator_meta.type}"')
|
|
16
|
+
|
|
17
|
+
# Acquire simulator type
|
|
18
|
+
sim_type = simulator_meta.get_type()
|
|
19
|
+
|
|
20
|
+
# Read simulator parameters
|
|
21
|
+
sim_params = simulator_meta.get_params()
|
|
22
|
+
|
|
23
|
+
sim_params_copy = sim_params.copy()
|
|
24
|
+
sim_params_copy["bed_size_x"] = 10.0
|
|
25
|
+
sim_params_copy["bed_size_z"] = 10.0
|
|
26
|
+
|
|
27
|
+
# Create demo simulator to test if params are all accepted
|
|
28
|
+
# If no exception occurs everything seems to be fine
|
|
29
|
+
logger.debug("Testing creation of simulator")
|
|
30
|
+
_sim = sim_type(**sim_params_copy)
|
|
31
|
+
|
|
32
|
+
logger.debug("Testing deletion of simulator")
|
|
33
|
+
del _sim
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def compute_sigma(material_meta: MaterialMeta):
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
logger.debug(f'Computing standard deviation sigma for material parameters of "{material_meta}"')
|
|
39
|
+
|
|
40
|
+
material = material_meta.get_material()
|
|
41
|
+
parameter_columns = material.get_parameter_columns()
|
|
42
|
+
sigmas = {}
|
|
43
|
+
|
|
44
|
+
for parameter_column in parameter_columns:
|
|
45
|
+
_mean, sigma = math.weighted_avg_and_std(
|
|
46
|
+
values=material.data[parameter_column].values,
|
|
47
|
+
weights=material.data["volume"].values,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
logger.debug(f"{material_meta} - {parameter_column}: sigma = {sigma}")
|
|
51
|
+
sigmas[parameter_column] = sigma
|
|
52
|
+
|
|
53
|
+
return sigmas
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def compute_sigma_reduction(material_before: MaterialMeta, material_after: MaterialMeta):
|
|
57
|
+
logger = logging.getLogger(__name__)
|
|
58
|
+
sigmas_before = compute_sigma(material_before)
|
|
59
|
+
sigmas_after = compute_sigma(material_after)
|
|
60
|
+
|
|
61
|
+
logger.info(f'Sigma reduction ratios for "{material_before}" -> "{material_after}":')
|
|
62
|
+
for parameter, sigma_before in sigmas_before.items():
|
|
63
|
+
reduction = sigma_before / sigmas_after[parameter]
|
|
64
|
+
logger.info(f"{parameter}\t1:{reduction:.2f}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def process(identifier: str, material_meta: MaterialMeta, deposition_meta: DepositionMeta, simulator_meta: SimulatorMeta, path: str, dry_run: bool) -> None:
|
|
68
|
+
logger = logging.getLogger(__name__)
|
|
69
|
+
logger.info(f'Processing "{identifier}" with material "{material_meta}" and deposition "{deposition_meta}" using simulator type {simulator_meta.type}')
|
|
70
|
+
|
|
71
|
+
logger.debug("Creating simulator")
|
|
72
|
+
sim_params = simulator_meta.get_params().copy()
|
|
73
|
+
sim_params["bed_size_x"] = deposition_meta.bed_size_x
|
|
74
|
+
sim_params["bed_size_z"] = deposition_meta.bed_size_z
|
|
75
|
+
sim = simulator_meta.get_type()(**sim_params)
|
|
76
|
+
|
|
77
|
+
logger.debug("Combining material and deposition")
|
|
78
|
+
material_deposition = MaterialDeposition(material_meta.get_material(), deposition_meta.get_deposition())
|
|
79
|
+
logger.debug(f"Material and deposition combined:\n{material_deposition.data.describe()}")
|
|
80
|
+
|
|
81
|
+
logger.debug("Stacking and reclaiming material")
|
|
82
|
+
reclaimed_material = sim.stack_reclaim(material_deposition)
|
|
83
|
+
logger.debug(f"Reclaimed material:\n{reclaimed_material.data.describe()}")
|
|
84
|
+
|
|
85
|
+
directory = os.path.join(path, BenchmarkData.REFERENCE_DIR, identifier)
|
|
86
|
+
prepare_path(directory, dry_run=dry_run)
|
|
87
|
+
|
|
88
|
+
simulator_file = os.path.join(directory, BenchmarkData.SIMULATOR_JSON)
|
|
89
|
+
logger.debug(f'Writing simulator type and parameters to "{simulator_file}"')
|
|
90
|
+
if not dry_run:
|
|
91
|
+
with open(simulator_file, "w") as file:
|
|
92
|
+
json.dump({"simulator": str(simulator_meta)}, file, indent=4)
|
|
93
|
+
|
|
94
|
+
reclaimed_reference = ReferenceMeta(
|
|
95
|
+
identifier,
|
|
96
|
+
directory,
|
|
97
|
+
{
|
|
98
|
+
"material": str(material_meta),
|
|
99
|
+
"deposition": str(deposition_meta),
|
|
100
|
+
},
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
meta_file = os.path.join(directory, BenchmarkData.META_JSON)
|
|
104
|
+
logger.debug(f'Writing reference meta to "{meta_file}"')
|
|
105
|
+
if not dry_run:
|
|
106
|
+
with open(meta_file, "w") as file:
|
|
107
|
+
json.dump(
|
|
108
|
+
reclaimed_reference.to_dict(),
|
|
109
|
+
file,
|
|
110
|
+
indent=4,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
reclaimed_material_path = os.path.join(directory, BenchmarkData.MATERIAL_DIR)
|
|
114
|
+
reclaimed_material_meta = MaterialMeta(
|
|
115
|
+
identifier,
|
|
116
|
+
path="",
|
|
117
|
+
meta_dict={
|
|
118
|
+
"label": "Reclaimed " + identifier,
|
|
119
|
+
"description": "Reclaimed material from " + identifier,
|
|
120
|
+
"category": "reclaimed",
|
|
121
|
+
"time": reclaimed_material.data.timestamp.max(),
|
|
122
|
+
"volume": reclaimed_material.data.volume.sum(),
|
|
123
|
+
"data": BenchmarkData.DATA_CSV,
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
reclaimed_material.meta = reclaimed_material_meta
|
|
127
|
+
reclaimed_material_meta.data = reclaimed_material
|
|
128
|
+
|
|
129
|
+
logger.debug(f'Creating directory "{reclaimed_material_path}"')
|
|
130
|
+
prepare_path(reclaimed_material_path, dry_run=dry_run)
|
|
131
|
+
|
|
132
|
+
reclaimed_material_meta_file = os.path.join(reclaimed_material_path, BenchmarkData.META_JSON)
|
|
133
|
+
logger.debug(f'Writing reclaimed material meta to "{reclaimed_material_meta_file}"')
|
|
134
|
+
if not dry_run:
|
|
135
|
+
with open(reclaimed_material_meta_file, "w") as file:
|
|
136
|
+
json.dump(
|
|
137
|
+
reclaimed_material_meta.to_dict(),
|
|
138
|
+
file,
|
|
139
|
+
indent=4,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
if not dry_run:
|
|
143
|
+
write_data_file(
|
|
144
|
+
data=reclaimed_material.data,
|
|
145
|
+
data_file=os.path.join(reclaimed_material_path, BenchmarkData.DATA_CSV),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
z_center = 0.5 * deposition_meta.bed_size_z
|
|
149
|
+
evaluator = ReclaimedMaterialEvaluator(
|
|
150
|
+
reclaimed_material,
|
|
151
|
+
x_min=z_center,
|
|
152
|
+
x_max=deposition_meta.bed_size_x - z_center,
|
|
153
|
+
)
|
|
154
|
+
parameter_stdev = evaluator.get_parameter_stdev()
|
|
155
|
+
logger.info("Parameter standard deviations:")
|
|
156
|
+
for k, v in parameter_stdev.items():
|
|
157
|
+
logger.info(f"{k}\t{v}")
|
|
158
|
+
|
|
159
|
+
# compute_sigma_reduction(material_meta, reclaimed_material_meta)
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from .material_deposition import DepositionMeta, MaterialMeta, write_data_file
|
|
6
|
+
from .reference_meta import ReferenceMeta
|
|
7
|
+
from .simulator_meta import SIMULATOR_TYPE, SimulatorMeta
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_instance_for_each_managed_dir(path: str, instance_type: type, *, recursive: bool = False) -> dict:
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
logger.debug(f'Creating class "{instance_type.__name__}" for each managed directory in path "{path}"')
|
|
13
|
+
entries = {}
|
|
14
|
+
for entry in os.listdir(path):
|
|
15
|
+
entry_path = os.path.join(path, entry)
|
|
16
|
+
|
|
17
|
+
if os.path.isdir(entry_path):
|
|
18
|
+
meta_path = os.path.join(entry_path, BenchmarkData.META_JSON)
|
|
19
|
+
if os.path.isfile(meta_path):
|
|
20
|
+
logger.debug(f'Reading "{instance_type.__name__}" from path "{entry_path}"')
|
|
21
|
+
|
|
22
|
+
# Errors which occur during JSON parsing and interpretation should interrupt program execution
|
|
23
|
+
with open(meta_path) as file:
|
|
24
|
+
meta = json.load(file)
|
|
25
|
+
entries[entry] = instance_type(entry, os.path.abspath(entry_path), meta)
|
|
26
|
+
else:
|
|
27
|
+
if recursive:
|
|
28
|
+
sub_entries = create_instance_for_each_managed_dir(entry_path, instance_type, recursive=True)
|
|
29
|
+
duplicate_identifiers = set(entries.keys()).intersection(sub_entries.keys())
|
|
30
|
+
if len(duplicate_identifiers) > 0:
|
|
31
|
+
raise ValueError(f"Duplicate identifiers {duplicate_identifiers}")
|
|
32
|
+
entries.update(sub_entries)
|
|
33
|
+
else:
|
|
34
|
+
logger.debug(f'Ignoring directory "{entry_path}"')
|
|
35
|
+
else:
|
|
36
|
+
logger.debug(f'Ignoring file "{entry_path}"')
|
|
37
|
+
|
|
38
|
+
return entries
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def prepare_path(path: str, *, dry_run: bool = False, empty_required: bool = True):
|
|
42
|
+
logger = logging.getLogger(__name__)
|
|
43
|
+
logger.debug(f'Preparing path "{path}"')
|
|
44
|
+
if os.path.exists(path):
|
|
45
|
+
if os.path.isdir(path):
|
|
46
|
+
if empty_required:
|
|
47
|
+
if len(os.listdir(path)) > 0:
|
|
48
|
+
raise OSError(f'Path "{path}" is not empty')
|
|
49
|
+
logger.debug(f'Path "{path}" already exists and is empty')
|
|
50
|
+
else:
|
|
51
|
+
logger.debug(f'Path "{path}" already exists')
|
|
52
|
+
else:
|
|
53
|
+
raise OSError(f'Path "{path}" exists but is not a directory')
|
|
54
|
+
else:
|
|
55
|
+
logger.debug(f'Creating path "{path}"')
|
|
56
|
+
if not dry_run:
|
|
57
|
+
os.makedirs(path)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class BenchmarkData:
|
|
61
|
+
META_JSON = "meta.json"
|
|
62
|
+
MATERIAL_DIR = "material"
|
|
63
|
+
DEPOSITION_DIR = "deposition"
|
|
64
|
+
SIMULATOR_DIR = "simulator"
|
|
65
|
+
REFERENCE_DIR = "reference"
|
|
66
|
+
BENCHMARK_DIR = "benchmark"
|
|
67
|
+
DATA_CSV = "data.csv"
|
|
68
|
+
PREDICTION_CSV = "prediction.csv"
|
|
69
|
+
SIMULATOR_JSON = "simulator.json"
|
|
70
|
+
|
|
71
|
+
def __init__(self, base_path: str | None = None):
|
|
72
|
+
self.base_path = base_path
|
|
73
|
+
|
|
74
|
+
self.materials: dict[str, MaterialMeta] = {}
|
|
75
|
+
self.depositions: dict[str, DepositionMeta] = {}
|
|
76
|
+
self.simulators: dict[str, SimulatorMeta] = {}
|
|
77
|
+
|
|
78
|
+
self.logger = logging.getLogger(__name__)
|
|
79
|
+
|
|
80
|
+
def get_benchmark_dir_path(self, path: str | None, benchmark_dir: str):
|
|
81
|
+
if path:
|
|
82
|
+
return path
|
|
83
|
+
if self.base_path:
|
|
84
|
+
return os.path.join(self.base_path, benchmark_dir)
|
|
85
|
+
raise ValueError("Base path not provided")
|
|
86
|
+
|
|
87
|
+
def read_materials(self, path: str | None = None) -> dict[str, MaterialMeta]:
|
|
88
|
+
path = self.get_benchmark_dir_path(path, BenchmarkData.MATERIAL_DIR)
|
|
89
|
+
self.logger.debug("Reading materials")
|
|
90
|
+
self.materials = create_instance_for_each_managed_dir(path, MaterialMeta, recursive=True)
|
|
91
|
+
self.logger.info(f"{len(self.materials)} materials read")
|
|
92
|
+
return self.materials
|
|
93
|
+
|
|
94
|
+
def read_depositions(self, path: str | None = None) -> dict[str, DepositionMeta]:
|
|
95
|
+
path = self.get_benchmark_dir_path(path, BenchmarkData.DEPOSITION_DIR)
|
|
96
|
+
self.logger.debug("Reading depositions")
|
|
97
|
+
self.depositions = create_instance_for_each_managed_dir(path, DepositionMeta, recursive=True)
|
|
98
|
+
self.logger.info(f"{len(self.depositions)} depositions read")
|
|
99
|
+
return self.depositions
|
|
100
|
+
|
|
101
|
+
def read_simulators(self, path: str | None = None) -> dict[str, SimulatorMeta]:
|
|
102
|
+
path = self.get_benchmark_dir_path(path, BenchmarkData.SIMULATOR_DIR)
|
|
103
|
+
self.logger.debug("Reading simulators")
|
|
104
|
+
self.simulators = create_instance_for_each_managed_dir(path, SimulatorMeta, recursive=True)
|
|
105
|
+
self.logger.info(f"{len(self.simulators)} simulators read")
|
|
106
|
+
return self.simulators
|
|
107
|
+
|
|
108
|
+
def read_references(self, path: str | None = None) -> dict[str, ReferenceMeta]:
|
|
109
|
+
path = self.get_benchmark_dir_path(path, BenchmarkData.REFERENCE_DIR)
|
|
110
|
+
self.logger.debug("Reading references")
|
|
111
|
+
references = create_instance_for_each_managed_dir(path, ReferenceMeta, recursive=True)
|
|
112
|
+
self.logger.info(f"{len(references)} references read")
|
|
113
|
+
return references
|
|
114
|
+
|
|
115
|
+
def read_base(self, path: str | None = None) -> None:
|
|
116
|
+
if not path and not self.base_path:
|
|
117
|
+
raise ValueError("Neither path nor base path provided")
|
|
118
|
+
|
|
119
|
+
self.read_materials(path)
|
|
120
|
+
self.read_depositions(path)
|
|
121
|
+
self.read_simulators(path)
|
|
122
|
+
|
|
123
|
+
def validate_references(self, references: dict[str, ReferenceMeta]):
|
|
124
|
+
self.logger.debug("Validating references")
|
|
125
|
+
for reference in references.values():
|
|
126
|
+
self.logger.debug(f'Validating reference "{reference}"')
|
|
127
|
+
if reference.material not in self.materials:
|
|
128
|
+
raise ValueError(f'Material "{reference.material}" not found in materials')
|
|
129
|
+
if reference.deposition not in self.depositions:
|
|
130
|
+
raise ValueError(f'Deposition "{reference.deposition}" not found in depositions')
|
|
131
|
+
self.logger.info("References validated")
|
|
132
|
+
|
|
133
|
+
def validate_simulators(self, sim_identifiers: list[str]):
|
|
134
|
+
self.logger.debug("Validating simulators")
|
|
135
|
+
for sim_identifier in sim_identifiers:
|
|
136
|
+
self.logger.debug(f'Validating simulator identifier "{sim_identifier}"')
|
|
137
|
+
if sim_identifier not in self.simulators:
|
|
138
|
+
raise ValueError(f'Simulator identifier "{sim_identifier}" not found in simulators')
|
|
139
|
+
if self.simulators[sim_identifier].type not in SIMULATOR_TYPE:
|
|
140
|
+
raise ValueError(f'Simulator type "{self.simulators[sim_identifier]}" not found for identifier "{sim_identifier}"')
|
|
141
|
+
self.logger.info("Simulators validated")
|
|
142
|
+
|
|
143
|
+
def validate_simulator(self, sim_identifier: str):
|
|
144
|
+
self.logger.debug(f'Validating simulator identifier "{sim_identifier}"')
|
|
145
|
+
if sim_identifier not in self.simulators:
|
|
146
|
+
raise ValueError(f'Simulator identifier "{sim_identifier}" not found in simulators')
|
|
147
|
+
if self.simulators[sim_identifier].type not in SIMULATOR_TYPE:
|
|
148
|
+
raise ValueError(f'Simulator type "{self.simulators[sim_identifier]}" not found for identifier "{sim_identifier}"')
|
|
149
|
+
self.logger.info(f'Simulator identifier "{sim_identifier}" validated')
|
|
150
|
+
|
|
151
|
+
def get_simulator_meta(self, sim_identifier: str) -> SimulatorMeta:
|
|
152
|
+
self.validate_simulator(sim_identifier)
|
|
153
|
+
return self.simulators[sim_identifier]
|
|
154
|
+
|
|
155
|
+
def validate_material(self, material_identifier: str):
|
|
156
|
+
self.logger.debug(f'Validating material identifier "{material_identifier}"')
|
|
157
|
+
if material_identifier not in self.materials:
|
|
158
|
+
raise ValueError(f'Material "{material_identifier}" not found in materials')
|
|
159
|
+
self.logger.info(f'Material identifier "{material_identifier}" validated')
|
|
160
|
+
|
|
161
|
+
def validate_deposition(self, deposition_identifiers: str):
|
|
162
|
+
self.logger.debug(f'Validating deposition identifier "{deposition_identifiers}"')
|
|
163
|
+
if deposition_identifiers not in self.depositions:
|
|
164
|
+
raise ValueError(f'Deposition "{deposition_identifiers}" not found in depositions')
|
|
165
|
+
self.logger.info(f'Deposition identifier "{deposition_identifiers}" validated')
|
|
166
|
+
|
|
167
|
+
def get_material_meta(self, material_identifier: str) -> MaterialMeta:
|
|
168
|
+
self.validate_material(material_identifier)
|
|
169
|
+
return self.materials[material_identifier]
|
|
170
|
+
|
|
171
|
+
def get_deposition_meta(self, deposition_identifiers: str) -> DepositionMeta:
|
|
172
|
+
self.validate_deposition(deposition_identifiers)
|
|
173
|
+
return self.depositions[deposition_identifiers]
|
|
174
|
+
|
|
175
|
+
def write_material(self, material_meta: MaterialMeta, path: str | None = None):
|
|
176
|
+
path = self.get_benchmark_dir_path(path, os.path.join(BenchmarkData.MATERIAL_DIR, material_meta.identifier))
|
|
177
|
+
|
|
178
|
+
if not os.path.exists(path):
|
|
179
|
+
self.logger.debug(f'Creating directory "{path}"')
|
|
180
|
+
os.makedirs(path)
|
|
181
|
+
|
|
182
|
+
material_meta_file = os.path.join(path, BenchmarkData.META_JSON)
|
|
183
|
+
self.logger.debug(f'Writing material meta to "{material_meta_file}"')
|
|
184
|
+
with open(material_meta_file, "w") as file:
|
|
185
|
+
json.dump(
|
|
186
|
+
material_meta.to_dict(),
|
|
187
|
+
file,
|
|
188
|
+
indent=4,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
write_data_file(material_meta.get_material().data, os.path.join(path, BenchmarkData.DATA_CSV))
|
|
192
|
+
prediction = material_meta.get_prediction()
|
|
193
|
+
if prediction is not None:
|
|
194
|
+
write_data_file(prediction.data, os.path.join(path, BenchmarkData.PREDICTION_CSV))
|
|
195
|
+
|
|
196
|
+
def write_deposition(self, deposition_meta: DepositionMeta, path: str | None = None):
|
|
197
|
+
path = self.get_benchmark_dir_path(path, os.path.join(BenchmarkData.DEPOSITION_DIR, deposition_meta.identifier))
|
|
198
|
+
if not os.path.exists(path):
|
|
199
|
+
self.logger.debug(f'Creating directory "{path}"')
|
|
200
|
+
os.makedirs(path)
|
|
201
|
+
|
|
202
|
+
deposition_meta_file = os.path.join(path, BenchmarkData.META_JSON)
|
|
203
|
+
self.logger.debug(f'Writing deposition meta to "{deposition_meta_file}"')
|
|
204
|
+
with open(deposition_meta_file, "w") as file:
|
|
205
|
+
json.dump(
|
|
206
|
+
deposition_meta.to_dict(),
|
|
207
|
+
file,
|
|
208
|
+
indent=4,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
write_data_file(deposition_meta.get_deposition().data, os.path.join(path, BenchmarkData.DATA_CSV))
|