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 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], random_int()]
718
- comp.nodes = [self.nodes[1], random_int()]
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], random_int()]
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], random_int()]
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
- assert is_directed_acyclic_graph(self.graph), "Graph is not a Directed Acyclic Graph (DAG), so cannot be solved."
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([random_int(), random_int()])
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([random_int(), random_int()])
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([random_int(), random_int()])
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([random_int(), random_int()])
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 = [self.random_int(), self.random_int()]
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], random_int()])
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], random_int()])
152
+ sample_2.set_nodes([self.nodes[1], uuid.uuid4()])
153
153
 
154
154
  return sample_1, sample_2
155
155
 
@@ -10,7 +10,7 @@ from typing import Union
10
10
 
11
11
  class MyLogger:
12
12
  def __init__(self):
13
- logging.basicConfig(level=logging.INFO,
13
+ logging.basicConfig(level=logging.DEBUG,
14
14
  format=' %(asctime)s - %(levelname)s - %(message)s')
15
15
 
16
16
  def get_logger(self, name=None):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: geometallurgy
3
- Version: 0.4.11
3
+ Version: 0.4.12
4
4
  Summary: Tools for the geometallurgist
5
5
  Home-page: https://github.com/elphick/geometallurgy
6
6
  Author: Greg
@@ -1,5 +1,5 @@
1
1
  elphick/geomet/__init__.py,sha256=gcaArz-agLsm_Tf9KNvmGznw4Jml2QTjj_CxKUC1Ejg,274
2
- elphick/geomet/base.py,sha256=4e4cJUDUPsVgv6xEyU8ML9xYUkOznCLPidQB3fXcVnM,50644
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=orMHEQx3tCFm7n3mzNczjd_0rxYcuYBZu1D9qaMRBFo,51290
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=RL4ZNcSm-u0MwdXp1gWq2q6FTnPs5q4xIOavs9FEDVg,1286
22
- elphick/geomet/interval_sample.py,sha256=KBiad0MZcfdcB96OQL60cbasTu5dz2Cek4tie5Kozk0,31361
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=J09nGNSkH8jdHzSmY1F3goBmycDacVe0SUMEhj7ATzw,3111
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.11.dist-info/LICENSE,sha256=GrSVdcGtNbGvAYC_tIjLHBrIVPyg-Ksfe7ZGr087yCI,1069
46
- geometallurgy-0.4.11.dist-info/METADATA,sha256=z0IpMOosGVEPcGgBuTIAhgL7Jxt3v718Cvb-SnhFF7Y,4386
47
- geometallurgy-0.4.11.dist-info/WHEEL,sha256=WGfLGfLX43Ei_YORXSnT54hxFygu34kMpcQdmgmEwCQ,88
48
- geometallurgy-0.4.11.dist-info/entry_points.txt,sha256=aQI-8kmaba_c9ZGOFkJgWl0MWBke5BQLNyPSVcbS7EU,58
49
- geometallurgy-0.4.11.dist-info/RECORD,,
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,,
@@ -1,5 +0,0 @@
1
- import uuid
2
-
3
-
4
- def random_int():
5
- return int(uuid.uuid4())