geometallurgy 0.4.11__py3-none-any.whl → 0.4.12__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.
- elphick/geomet/base.py +5 -5
- elphick/geomet/flowsheet/flowsheet.py +31 -8
- elphick/geomet/flowsheet/stream.py +7 -6
- elphick/geomet/interval_sample.py +3 -3
- elphick/geomet/utils/timer.py +1 -1
- {geometallurgy-0.4.11.dist-info → geometallurgy-0.4.12.dist-info}/METADATA +1 -1
- {geometallurgy-0.4.11.dist-info → geometallurgy-0.4.12.dist-info}/RECORD +10 -11
- elphick/geomet/utils/sampling.py +0 -5
- {geometallurgy-0.4.11.dist-info → geometallurgy-0.4.12.dist-info}/LICENSE +0 -0
- {geometallurgy-0.4.11.dist-info → geometallurgy-0.4.12.dist-info}/WHEEL +0 -0
- {geometallurgy-0.4.11.dist-info → geometallurgy-0.4.12.dist-info}/entry_points.txt +0 -0
elphick/geomet/base.py
CHANGED
|
@@ -2,6 +2,7 @@ import copy
|
|
|
2
2
|
import inspect
|
|
3
3
|
import logging
|
|
4
4
|
import re
|
|
5
|
+
import uuid
|
|
5
6
|
from abc import ABC
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Optional, Union, Literal, TypeVar, TYPE_CHECKING
|
|
@@ -15,7 +16,6 @@ from elphick.geomet.config import read_yaml
|
|
|
15
16
|
from elphick.geomet.utils.components import get_components, is_compositional
|
|
16
17
|
from elphick.geomet.utils.moisture import solve_mass_moisture
|
|
17
18
|
from elphick.geomet.utils.pandas import mass_to_composition, composition_to_mass, composition_factors
|
|
18
|
-
from elphick.geomet.utils.sampling import random_int
|
|
19
19
|
from elphick.geomet.utils.timer import log_timer
|
|
20
20
|
from .config.config_read import get_column_config
|
|
21
21
|
from .plot import parallel_plot, comparison_plot
|
|
@@ -714,8 +714,8 @@ class MassComposition(ABC):
|
|
|
714
714
|
comp: 'Stream'
|
|
715
715
|
|
|
716
716
|
# create the relationships
|
|
717
|
-
ref.nodes = [self.nodes[1],
|
|
718
|
-
comp.nodes = [self.nodes[1],
|
|
717
|
+
ref.nodes = [self.nodes[1], uuid.uuid4()]
|
|
718
|
+
comp.nodes = [self.nodes[1], uuid.uuid4()]
|
|
719
719
|
|
|
720
720
|
return ref, comp
|
|
721
721
|
|
|
@@ -747,7 +747,7 @@ class MassComposition(ABC):
|
|
|
747
747
|
|
|
748
748
|
# create the relationships
|
|
749
749
|
other.nodes = [other.nodes[0], self.nodes[1]]
|
|
750
|
-
res.nodes = [self.nodes[1],
|
|
750
|
+
res.nodes = [self.nodes[1], uuid.uuid4()]
|
|
751
751
|
|
|
752
752
|
return res
|
|
753
753
|
|
|
@@ -780,7 +780,7 @@ class MassComposition(ABC):
|
|
|
780
780
|
|
|
781
781
|
# create the relationships
|
|
782
782
|
other.nodes = [self.nodes[1], other.nodes[1]]
|
|
783
|
-
res.nodes = [self.nodes[1],
|
|
783
|
+
res.nodes = [self.nodes[1], uuid.uuid4()]
|
|
784
784
|
|
|
785
785
|
return res
|
|
786
786
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import json
|
|
3
3
|
import logging
|
|
4
|
+
import uuid
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Dict, List, Optional, Tuple, Union, TypeVar, TYPE_CHECKING
|
|
6
7
|
import re
|
|
@@ -25,7 +26,6 @@ from elphick.geomet.flowsheet.operation import NodeType, OP, PartitionOperation,
|
|
|
25
26
|
from elphick.geomet.plot import parallel_plot, comparison_plot
|
|
26
27
|
from elphick.geomet.utils.layout import digraph_linear_layout
|
|
27
28
|
from elphick.geomet.flowsheet.loader import streams_from_dataframe
|
|
28
|
-
from elphick.geomet.utils.sampling import random_int
|
|
29
29
|
|
|
30
30
|
# if TYPE_CHECKING:
|
|
31
31
|
from elphick.geomet.flowsheet.stream import Stream
|
|
@@ -307,7 +307,11 @@ class Flowsheet:
|
|
|
307
307
|
def solve(self):
|
|
308
308
|
"""Solve missing streams"""
|
|
309
309
|
|
|
310
|
-
|
|
310
|
+
if not is_directed_acyclic_graph(self.graph):
|
|
311
|
+
self._logger.error("Graph is not a Directed Acyclic Graph (DAG), so cannot be solved.")
|
|
312
|
+
self._logger.debug(f"Graph nodes: {self.graph.nodes(data=True)}")
|
|
313
|
+
self._logger.debug(f"Graph edges: {self.graph.edges(data=True)}")
|
|
314
|
+
raise ValueError("Graph is not a Directed Acyclic Graph (DAG), so cannot be solved.")
|
|
311
315
|
|
|
312
316
|
# Check the number of missing mc's on edges in the network
|
|
313
317
|
missing_count: int = sum([1 for u, v, d in self.graph.edges(data=True) if d['mc'] is None])
|
|
@@ -353,6 +357,12 @@ class Flowsheet:
|
|
|
353
357
|
self.set_operation_data(node)
|
|
354
358
|
|
|
355
359
|
missing_count: int = sum([1 for u, v, d in self.graph.edges(data=True) if d['mc'] is None])
|
|
360
|
+
self._logger.info(f"Missing count: {missing_count}")
|
|
361
|
+
|
|
362
|
+
if missing_count > 0:
|
|
363
|
+
self._logger.error(f"Failed to solve the flowsheet. Missing count: {missing_count}")
|
|
364
|
+
raise ValueError(
|
|
365
|
+
f"Failed to solve the flowsheet. Some streams are still missing. Missing count: {missing_count}")
|
|
356
366
|
|
|
357
367
|
def query(self, expr: str, stream_name: Optional[str] = None, inplace=False) -> 'Flowsheet':
|
|
358
368
|
"""Reduce the Flowsheet Stream records with a query
|
|
@@ -427,6 +437,8 @@ class Flowsheet:
|
|
|
427
437
|
degrees = {n: d for n, d in self.graph.degree()}
|
|
428
438
|
|
|
429
439
|
res: list[MC] = [d['mc'] for u, v, d in self.graph.edges(data=True) if degrees[u] == 1]
|
|
440
|
+
if not res:
|
|
441
|
+
raise ValueError("No input streams found")
|
|
430
442
|
return res
|
|
431
443
|
|
|
432
444
|
def get_output_streams(self) -> list[MC]:
|
|
@@ -440,6 +452,8 @@ class Flowsheet:
|
|
|
440
452
|
degrees = {n: d for n, d in self.graph.degree()}
|
|
441
453
|
|
|
442
454
|
res: list[MC] = [d['mc'] for u, v, d in self.graph.edges(data=True) if degrees[v] == 1]
|
|
455
|
+
if not res:
|
|
456
|
+
raise ValueError("No output streams found")
|
|
443
457
|
return res
|
|
444
458
|
|
|
445
459
|
@staticmethod
|
|
@@ -1039,6 +1053,7 @@ class Flowsheet:
|
|
|
1039
1053
|
if ('mc' in self.graph.nodes[node].keys()) and (node in node_names.keys()):
|
|
1040
1054
|
self.graph.nodes[node]['mc'].name = node_names[node]
|
|
1041
1055
|
|
|
1056
|
+
|
|
1042
1057
|
def set_stream_data(self, stream_data: dict[str, Optional[MC]]):
|
|
1043
1058
|
"""Set the data (MassComposition) of network edges (streams) with a Dict"""
|
|
1044
1059
|
for stream_name, stream_data in stream_data.items():
|
|
@@ -1060,6 +1075,7 @@ class Flowsheet:
|
|
|
1060
1075
|
self.graph.nodes[node]['mc'].outputs = [self.graph.get_edge_data(e[0], e[1])['mc'] for e in
|
|
1061
1076
|
self.graph.out_edges(node)]
|
|
1062
1077
|
|
|
1078
|
+
|
|
1063
1079
|
def set_operation_data(self, node):
|
|
1064
1080
|
"""Set the input and output data for a node.
|
|
1065
1081
|
Uses the data on the edges (streams) connected to the node to refresh the data and check for node balance.
|
|
@@ -1069,6 +1085,7 @@ class Flowsheet:
|
|
|
1069
1085
|
node_data.outputs = [self.graph.get_edge_data(e[0], e[1])['mc'] for e in self.graph.out_edges(node)]
|
|
1070
1086
|
node_data.check_balance()
|
|
1071
1087
|
|
|
1088
|
+
|
|
1072
1089
|
def streams_to_dict(self) -> Dict[str, MC]:
|
|
1073
1090
|
"""Export the Stream objects to a Dict
|
|
1074
1091
|
|
|
@@ -1082,6 +1099,7 @@ class Flowsheet:
|
|
|
1082
1099
|
streams[data['mc'].name] = data['mc']
|
|
1083
1100
|
return streams
|
|
1084
1101
|
|
|
1102
|
+
|
|
1085
1103
|
def nodes_to_dict(self) -> Dict[int, OP]:
|
|
1086
1104
|
"""Export the MCNode objects to a Dict
|
|
1087
1105
|
|
|
@@ -1095,13 +1113,14 @@ class Flowsheet:
|
|
|
1095
1113
|
nodes[node] = self.graph.nodes[node]['mc']
|
|
1096
1114
|
return nodes
|
|
1097
1115
|
|
|
1116
|
+
|
|
1098
1117
|
def set_nodes(self, stream: str, nodes: Tuple[int, int]):
|
|
1099
1118
|
mc: MC = self.get_stream_by_name(stream)
|
|
1100
1119
|
mc._nodes = nodes
|
|
1101
1120
|
self._update_graph(mc)
|
|
1102
1121
|
|
|
1103
|
-
def reset_nodes(self, stream: Optional[str] = None):
|
|
1104
1122
|
|
|
1123
|
+
def reset_nodes(self, stream: Optional[str] = None):
|
|
1105
1124
|
"""Reset stream nodes to break relationships
|
|
1106
1125
|
|
|
1107
1126
|
Args:
|
|
@@ -1115,13 +1134,14 @@ class Flowsheet:
|
|
|
1115
1134
|
if stream is None:
|
|
1116
1135
|
streams: Dict[str, MC] = self.streams_to_dict()
|
|
1117
1136
|
for k, v in streams.items():
|
|
1118
|
-
streams[k] = v.set_nodes([
|
|
1137
|
+
streams[k] = v.set_nodes([uuid.uuid4(), uuid.uuid4()])
|
|
1119
1138
|
self.graph = Flowsheet(name=self.name).from_objects(objects=list(streams.values())).graph
|
|
1120
1139
|
else:
|
|
1121
1140
|
mc: MC = self.get_stream_by_name(stream)
|
|
1122
|
-
mc.set_nodes([
|
|
1141
|
+
mc.set_nodes([uuid.uuid4(), uuid.uuid4()])
|
|
1123
1142
|
self._update_graph(mc)
|
|
1124
1143
|
|
|
1144
|
+
|
|
1125
1145
|
def _update_graph(self, mc: MC):
|
|
1126
1146
|
"""Update the graph with an existing stream object
|
|
1127
1147
|
|
|
@@ -1140,6 +1160,7 @@ class Flowsheet:
|
|
|
1140
1160
|
strms.append(a['mc'])
|
|
1141
1161
|
self.graph = Flowsheet(name=self.name).from_objects(objects=strms).graph
|
|
1142
1162
|
|
|
1163
|
+
|
|
1143
1164
|
def get_stream_by_name(self, name: str) -> MC:
|
|
1144
1165
|
"""Get the Stream object from the network by its name
|
|
1145
1166
|
|
|
@@ -1160,18 +1181,20 @@ class Flowsheet:
|
|
|
1160
1181
|
|
|
1161
1182
|
return res
|
|
1162
1183
|
|
|
1184
|
+
|
|
1163
1185
|
def set_stream_parent(self, stream: str, parent: str):
|
|
1164
1186
|
mc: MC = self.get_stream_by_name(stream)
|
|
1165
1187
|
mc.set_parent_node(self.get_stream_by_name(parent))
|
|
1166
1188
|
self._update_graph(mc)
|
|
1167
1189
|
|
|
1190
|
+
|
|
1168
1191
|
def set_stream_child(self, stream: str, child: str):
|
|
1169
1192
|
mc: MC = self.get_stream_by_name(stream)
|
|
1170
1193
|
mc.set_child_node(self.get_stream_by_name(child))
|
|
1171
1194
|
self._update_graph(mc)
|
|
1172
1195
|
|
|
1173
|
-
def reset_stream_nodes(self, stream: Optional[str] = None):
|
|
1174
1196
|
|
|
1197
|
+
def reset_stream_nodes(self, stream: Optional[str] = None):
|
|
1175
1198
|
"""Reset stream nodes to break relationships
|
|
1176
1199
|
|
|
1177
1200
|
Args:
|
|
@@ -1185,9 +1208,9 @@ class Flowsheet:
|
|
|
1185
1208
|
if stream is None:
|
|
1186
1209
|
streams: Dict[str, MC] = self.streams_to_dict()
|
|
1187
1210
|
for k, v in streams.items():
|
|
1188
|
-
streams[k] = v.set_nodes([
|
|
1211
|
+
streams[k] = v.set_nodes([uuid.uuid4(), uuid.uuid4()])
|
|
1189
1212
|
self.graph = Flowsheet(name=self.name).from_objects(objects=list(streams.values())).graph
|
|
1190
1213
|
else:
|
|
1191
1214
|
mc: MC = self.get_stream_by_name(stream)
|
|
1192
|
-
mc.set_nodes([
|
|
1215
|
+
mc.set_nodes([uuid.uuid4(), uuid.uuid4()])
|
|
1193
1216
|
self._update_graph(mc)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
1
3
|
from elphick.geomet.base import MassComposition
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
class Stream(MassComposition):
|
|
5
7
|
def __init__(self, *args, **kwargs):
|
|
6
8
|
super().__init__(*args, **kwargs)
|
|
7
|
-
self.nodes = [
|
|
9
|
+
self.nodes = [uuid.uuid4(), uuid.uuid4()]
|
|
8
10
|
|
|
9
11
|
def set_parent_node(self, parent: 'Stream') -> 'Stream':
|
|
10
12
|
self.nodes = [parent.nodes[1], self.nodes[1]]
|
|
@@ -15,14 +17,13 @@ class Stream(MassComposition):
|
|
|
15
17
|
return self
|
|
16
18
|
|
|
17
19
|
def set_nodes(self, nodes: list) -> 'Stream':
|
|
20
|
+
if len(nodes) != 2:
|
|
21
|
+
raise ValueError('Nodes must be a list of length 2')
|
|
22
|
+
if nodes[0] == nodes[1]:
|
|
23
|
+
raise ValueError('Nodes must be different')
|
|
18
24
|
self.nodes = nodes
|
|
19
25
|
return self
|
|
20
26
|
|
|
21
|
-
@staticmethod
|
|
22
|
-
def random_int():
|
|
23
|
-
import random
|
|
24
|
-
return random.randint(0, 100)
|
|
25
|
-
|
|
26
27
|
# @classmethod
|
|
27
28
|
# def from_mass_composition(cls, obj: MassComposition) -> 'Stream':
|
|
28
29
|
# filtered_kwargs = filter_kwargs(obj, **obj.__dict__)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import functools
|
|
4
|
+
import uuid
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Optional, Literal, Callable, Union, Iterable, TYPE_CHECKING
|
|
6
7
|
|
|
@@ -18,7 +19,6 @@ from elphick.geomet.utils.interp import mass_preserving_interp
|
|
|
18
19
|
from elphick.geomet.utils.interp2 import mass_preserving_interp_2d
|
|
19
20
|
from elphick.geomet.utils.pandas import MeanIntervalIndex, weight_average, calculate_recovery, calculate_partition, \
|
|
20
21
|
cumulate, mass_to_composition
|
|
21
|
-
from elphick.geomet.utils.sampling import random_int
|
|
22
22
|
|
|
23
23
|
from elphick.geomet.base import MassComposition
|
|
24
24
|
|
|
@@ -146,10 +146,10 @@ class IntervalSample(MassComposition):
|
|
|
146
146
|
|
|
147
147
|
sample_1 = self.create_congruent_object(name=name_1).to_stream()
|
|
148
148
|
sample_1.mass_data = self.mass_data.copy().multiply(pn, axis=0)
|
|
149
|
-
sample_1.set_nodes([self.nodes[1],
|
|
149
|
+
sample_1.set_nodes([self.nodes[1], uuid.uuid4()])
|
|
150
150
|
sample_2 = self.create_congruent_object(name=name_2)
|
|
151
151
|
sample_2.mass_data = self.mass_data.copy().multiply((1 - pn), axis=0)
|
|
152
|
-
sample_2.set_nodes([self.nodes[1],
|
|
152
|
+
sample_2.set_nodes([self.nodes[1], uuid.uuid4()])
|
|
153
153
|
|
|
154
154
|
return sample_1, sample_2
|
|
155
155
|
|
elphick/geomet/utils/timer.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
elphick/geomet/__init__.py,sha256=gcaArz-agLsm_Tf9KNvmGznw4Jml2QTjj_CxKUC1Ejg,274
|
|
2
|
-
elphick/geomet/base.py,sha256=
|
|
2
|
+
elphick/geomet/base.py,sha256=vp0C7DEAAUDGhTdQ8_Hz9WmqZRjNGn7m5CqEGy3L_98,50603
|
|
3
3
|
elphick/geomet/block_model.py,sha256=Q-LEdILajUoteO0834IXeS75k8pcPqSaMrinMcWD8R4,14639
|
|
4
4
|
elphick/geomet/config/__init__.py,sha256=F94hbxN3KzSaljbElIGVhdEwX0FKmHxST4jJ7rNohxY,35
|
|
5
5
|
elphick/geomet/config/config_read.py,sha256=frRwfRwUXpgxwMNCiBVFUw1-yPbBHs3h2KjmzXImvxY,1396
|
|
@@ -15,11 +15,11 @@ elphick/geomet/datasets/register.csv,sha256=-N3F6L0097C-I79axINi_ewFAxiqbT_SOSW3
|
|
|
15
15
|
elphick/geomet/datasets/sample_data.py,sha256=jt5DWxdMmPbZGDuon2s8Q2wlX3cEegB0dSmRKF4pz4I,7684
|
|
16
16
|
elphick/geomet/extras.py,sha256=0yDwbPMylP21EOo27juu4gUiewygSXLSjggYDrPvDcQ,1128
|
|
17
17
|
elphick/geomet/flowsheet/__init__.py,sha256=-lxSLPZNQfiLXKZ2qqS5XbbhrZA2ABi3ppx0LaHnNEI,33
|
|
18
|
-
elphick/geomet/flowsheet/flowsheet.py,sha256=
|
|
18
|
+
elphick/geomet/flowsheet/flowsheet.py,sha256=__kgowBIyWfvXcdPWCFihoEUdOqTj7KszSbKGF1AkBo,52032
|
|
19
19
|
elphick/geomet/flowsheet/loader.py,sha256=8nd9Vqbg1de35iuoc4mdRFxrUsIBZed0ivXIAu80jBk,4756
|
|
20
20
|
elphick/geomet/flowsheet/operation.py,sha256=f8k0-Gr_Uy2SlEp8bwAaG4yeBa3DU0HoPn9wyWhYipE,9720
|
|
21
|
-
elphick/geomet/flowsheet/stream.py,sha256=
|
|
22
|
-
elphick/geomet/interval_sample.py,sha256=
|
|
21
|
+
elphick/geomet/flowsheet/stream.py,sha256=NOXcYeZLSmOSoSRFc7M36Jc8c1ARgjiCvtRuixYfuqA,1370
|
|
22
|
+
elphick/geomet/interval_sample.py,sha256=fhcWBTA01TqvCBsJv7dzWZHRBpw_4W2Ahawks5SPj28,31320
|
|
23
23
|
elphick/geomet/io.py,sha256=tZsX_getGxL07dPlF3Ozyzvt2tFHE5OdgPM5pc5xL68,15709
|
|
24
24
|
elphick/geomet/plot.py,sha256=e9uz8L3QZ23CW4OYm78NhdZl01i0DxHfC4r1kigz7Ss,5732
|
|
25
25
|
elphick/geomet/profile.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -37,13 +37,12 @@ elphick/geomet/utils/moisture.py,sha256=t9WMwADyz-QAMW-cdah1tIlzTDrhooSoKOPdIlVQ
|
|
|
37
37
|
elphick/geomet/utils/pandas.py,sha256=6sKl3WUjXLR7qFmqBzuCjnfCoUsLRapwZk2nO5BfzYI,17397
|
|
38
38
|
elphick/geomet/utils/parallel.py,sha256=l38JBTkCmdqKHQkS8njoA-sBN9XQGkhF59XtAhWShgs,842
|
|
39
39
|
elphick/geomet/utils/partition.py,sha256=U0jFpvdvZJVdutfB6RzUzKfO9NWCGtBkeySx-QbP-l4,1534
|
|
40
|
-
elphick/geomet/utils/sampling.py,sha256=qwf1ZUjsg431rpFqto_8WxLwlMCGyC5bWUlPXo-nHIM,61
|
|
41
40
|
elphick/geomet/utils/size.py,sha256=EmV_sv2bOImQN3s7TWCniU_y83HNJEPtZH7fMMkYTcc,2272
|
|
42
|
-
elphick/geomet/utils/timer.py,sha256=
|
|
41
|
+
elphick/geomet/utils/timer.py,sha256=8WNKLFcINRsZ3IsKtOIZ77YbKtqczyOOTEWY9h9Uxxw,3112
|
|
43
42
|
elphick/geomet/utils/viz.py,sha256=M0CnfDXBHtYb8aak1Sfz6XLvRSmkzX3ybIDllEmDR8A,1718
|
|
44
43
|
elphick/geomet/validate.py.hide,sha256=qAWJlgq0jp19UakVV0dEU_AsqV_JctUn1QTHn8cCRw0,6738
|
|
45
|
-
geometallurgy-0.4.
|
|
46
|
-
geometallurgy-0.4.
|
|
47
|
-
geometallurgy-0.4.
|
|
48
|
-
geometallurgy-0.4.
|
|
49
|
-
geometallurgy-0.4.
|
|
44
|
+
geometallurgy-0.4.12.dist-info/LICENSE,sha256=GrSVdcGtNbGvAYC_tIjLHBrIVPyg-Ksfe7ZGr087yCI,1069
|
|
45
|
+
geometallurgy-0.4.12.dist-info/METADATA,sha256=iatuwf4Pey2ZHhaEu-p-NJ-tEVCdZAijNXZf91jhgpM,4386
|
|
46
|
+
geometallurgy-0.4.12.dist-info/WHEEL,sha256=WGfLGfLX43Ei_YORXSnT54hxFygu34kMpcQdmgmEwCQ,88
|
|
47
|
+
geometallurgy-0.4.12.dist-info/entry_points.txt,sha256=aQI-8kmaba_c9ZGOFkJgWl0MWBke5BQLNyPSVcbS7EU,58
|
|
48
|
+
geometallurgy-0.4.12.dist-info/RECORD,,
|
elphick/geomet/utils/sampling.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|