geometallurgy 0.4.12__tar.gz → 0.4.14__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.
Files changed (47) hide show
  1. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/PKG-INFO +6 -5
  2. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/block_model.py +55 -94
  3. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/extras.py +5 -5
  4. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/pyproject.toml +9 -6
  5. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/LICENSE +0 -0
  6. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/README.md +0 -0
  7. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/__init__.py +0 -0
  8. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/base.py +0 -0
  9. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/config/__init__.py +0 -0
  10. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/config/config_read.py +0 -0
  11. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/config/flowsheet_example_partition.yaml +0 -0
  12. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/config/flowsheet_example_simple.yaml +0 -0
  13. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/config/mc_config.yml +0 -0
  14. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/data/downloader.py +0 -0
  15. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/data/register.csv +0 -0
  16. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/datasets/__init__.py +0 -0
  17. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/datasets/datasets.py +0 -0
  18. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/datasets/downloader.py +0 -0
  19. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/datasets/register.csv +0 -0
  20. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/datasets/sample_data.py +0 -0
  21. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/flowsheet/__init__.py +0 -0
  22. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/flowsheet/flowsheet.py +0 -0
  23. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/flowsheet/loader.py +0 -0
  24. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/flowsheet/operation.py +0 -0
  25. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/flowsheet/stream.py +0 -0
  26. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/interval_sample.py +0 -0
  27. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/io.py +0 -0
  28. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/plot.py +0 -0
  29. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/profile.py +0 -0
  30. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/sample.py +0 -0
  31. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/__init__.py +0 -0
  32. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/amenability.py +0 -0
  33. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/block_model_converter.py +0 -0
  34. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/components.py +0 -0
  35. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/data.py +0 -0
  36. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/estimates.py +0 -0
  37. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/interp.py +0 -0
  38. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/interp2.py +0 -0
  39. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/layout.py +0 -0
  40. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/moisture.py +0 -0
  41. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/pandas.py +0 -0
  42. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/parallel.py +0 -0
  43. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/partition.py +0 -0
  44. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/size.py +0 -0
  45. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/timer.py +0 -0
  46. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/utils/viz.py +0 -0
  47. {geometallurgy-0.4.12 → geometallurgy-0.4.14}/elphick/geomet/validate.py.hide +0 -0
@@ -1,26 +1,27 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: geometallurgy
3
- Version: 0.4.12
3
+ Version: 0.4.14
4
4
  Summary: Tools for the geometallurgist
5
5
  Home-page: https://github.com/elphick/geometallurgy
6
6
  Author: Greg
7
7
  Author-email: 11791585+elphick@users.noreply.github.com
8
- Requires-Python: >=3.9,<3.13
8
+ Requires-Python: >=3.10,<3.13
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.9
11
10
  Classifier: Programming Language :: Python :: 3.10
12
11
  Classifier: Programming Language :: Python :: 3.11
13
12
  Provides-Extra: all
14
13
  Provides-Extra: blockmodel
15
- Provides-Extra: map
14
+ Provides-Extra: spatial
16
15
  Provides-Extra: validation
17
- Requires-Dist: folium (>=0.16.0,<0.17.0) ; extra == "map"
16
+ Requires-Dist: folium (>=0.16.0,<0.17.0) ; extra == "spatial"
17
+ Requires-Dist: omfpandas (>=0.8.1,<0.9.0) ; extra == "blockmodel"
18
18
  Requires-Dist: omfvista (>=0.3.0) ; extra == "blockmodel"
19
19
  Requires-Dist: pandas (>=1.0)
20
20
  Requires-Dist: pandera[io] (>=0.19.3,<0.21.0) ; extra == "validation"
21
21
  Requires-Dist: periodictable (>=1.7.0,<2.0.0)
22
22
  Requires-Dist: plotly (>=5.22.0,<6.0.0)
23
23
  Requires-Dist: pyarrow (>=16.1.0,<18.0.0)
24
+ Requires-Dist: rioxarray (>=0.18.2,<0.19.0) ; extra == "spatial"
24
25
  Project-URL: Documentation, https://elphick.github.io/geometallurgy
25
26
  Project-URL: Repository, https://github.com/elphick/geometallurgy
26
27
  Description-Content-Type: text/markdown
@@ -10,7 +10,6 @@ from scipy import stats
10
10
  from elphick.geomet import extras
11
11
  from elphick.geomet.base import MassComposition
12
12
  from elphick.geomet.extras import BlockmodelExtras
13
- from elphick.geomet.utils.block_model_converter import volume_to_vtk
14
13
  from elphick.geomet.utils.timer import log_timer
15
14
 
16
15
  if TYPE_CHECKING:
@@ -21,8 +20,8 @@ if TYPE_CHECKING:
21
20
  def import_extras(func):
22
21
  @wraps(func)
23
22
  def wrapper(*args, **kwargs):
24
- omf, omfvista, pv = extras.import_blockmodel_packages()
25
- extras_instance = BlockmodelExtras(omf, omfvista, pv)
23
+ omfpandas, omfvista, pv = extras.import_blockmodel_packages()
24
+ extras_instance = BlockmodelExtras(omfpandas, omfvista, pv)
26
25
  return func(*args, imports=extras_instance, **kwargs)
27
26
 
28
27
  return wrapper
@@ -66,105 +65,67 @@ class BlockModel(MassComposition):
66
65
  @classmethod
67
66
  @import_extras
68
67
  def from_omf(cls, omf_filepath: Path, imports,
69
- name: Optional[str] = None,
70
- columns: Optional[list[str]] = None) -> 'BlockModel':
71
-
72
- reader = imports.omf.OMFReader(str(omf_filepath))
73
- project: imports.omf.Project = reader.get_project()
74
- # get the first block model detected in the omf project
75
- block_model_candidates = [obj for obj in project.elements if isinstance(obj, imports.omf.volume.VolumeElement)]
76
- if name:
77
- omf_bm = [obj for obj in block_model_candidates if obj.name == name]
78
- if len(omf_bm) == 0:
79
- raise ValueError(f"No block model named '{name}' found in the OMF file.")
80
- else:
81
- omf_bm = omf_bm[0]
82
- elif len(block_model_candidates) > 1:
83
- names: list[str] = [obj.name for obj in block_model_candidates]
84
- raise ValueError(f"Multiple block models detected in the OMF file - provide a name argument from: {names}")
85
- else:
86
- omf_bm = block_model_candidates[0]
87
-
88
- origin = np.array(project.origin)
89
- bm = volume_to_vtk(omf_bm, origin=origin, columns=columns)
90
-
91
- # Create DataFrame
92
- df = pd.DataFrame(bm.cell_centers().points, columns=['x', 'y', 'z'])
93
-
94
- # set the index to the cell centroids
95
- df.set_index(['x', 'y', 'z'], drop=True, inplace=True)
68
+ element_name: Optional[str] = None,
69
+ columns: Optional[list[str]] = None,
70
+ query: Optional[str] = None,
71
+ density: float = 2.5) -> 'BlockModel':
72
+ """Create a BlockModel from an OMF file.
73
+
74
+ Args:
75
+ omf_filepath: Path to the OMF file.
76
+ imports: internally used to import the necessary packages.
77
+ element_name: The name of the element in the OMF file.
78
+ columns: The columns to extract from the OMF file.
79
+ query: The query to filter the DataFrame.
80
+ density: The density of the material in g/cm3, used to calculate DMT (Dry Mass Tonnes). A workaround.
81
+
82
+ Returns:
83
+ BlockModel: The BlockModel instance.
96
84
 
97
- if not isinstance(bm, imports.pv.RectilinearGrid):
98
- for d, t in zip(['dx', 'dy', 'dz'], ['tensor_u', 'tensor_v', 'tensor_w']):
99
- # todo: fix - wrong shape
100
- df[d] = eval(f"omf_bm.geometry.{t}")
101
- df.set_index(['dx', 'dy', 'dz'], append=True, inplace=True)
85
+ """
102
86
 
103
- # Add the array data to the DataFrame
104
- for name in bm.array_names:
105
- df[name] = bm.get_array(name)
87
+ omfpr: imports.omfpandas.OMFPandasReader = imports.omfpandas.OMFPandasReader(filepath=omf_filepath)
88
+ blocks: pd.DataFrame = omfpr.read_blockmodel(blockmodel_name=element_name, attributes=columns,
89
+ query=query)
106
90
 
107
- # temporary workaround for no mass
108
- df['DMT'] = 2000
109
- moisture_in_scope = False
91
+ # get the block volume
110
92
 
111
- return cls(data=df, name=omf_bm.name, moisture_in_scope=moisture_in_scope)
93
+ volume: Union[float, np.ndarray[float]]
94
+ from omfpandas.blockmodel import OMFBlockModel
95
+ from omfpandas.blockmodels.convert_blockmodel import df_to_blockmodel
96
+ from omfpandas.blockmodels.geometry import Geometry
97
+ geom: Geometry = OMFBlockModel(df_to_blockmodel(blocks, blockmodel_name=element_name)).geometry
112
98
 
113
- @import_extras
114
- def to_omf(self, omf_filepath: Path, imports, name: str = 'Block Model', description: str = 'A block model'):
115
-
116
- # Create a Project instance
117
- project = imports.omf.Project(name=name, description=description)
118
-
119
- # Create a VolumeElement instance for the block model
120
- block_model = imports.omf.VolumeElement(name=name, description=description,
121
- geometry=imports.omf.VolumeGridGeometry())
122
-
123
- # Set the geometry of the block model
124
- block_model.geometry.origin = self.data.index.get_level_values('x').min(), \
125
- self.data.index.get_level_values('y').min(), \
126
- self.data.index.get_level_values('z').min()
127
-
128
- # Set the axis directions
129
- block_model.geometry.axis_u = [1, 0, 0] # Set the u-axis to point along the x-axis
130
- block_model.geometry.axis_v = [0, 1, 0] # Set the v-axis to point along the y-axis
131
- block_model.geometry.axis_w = [0, 0, 1] # Set the w-axis to point along the z-axis
132
-
133
- # Set the tensor locations and dimensions
134
- if 'dx' not in self.data.index.names:
135
- # Calculate the dimensions of the cells
136
- x_dims = np.diff(self.data.index.get_level_values('x').unique())
137
- y_dims = np.diff(self.data.index.get_level_values('y').unique())
138
- z_dims = np.diff(self.data.index.get_level_values('z').unique())
139
-
140
- # Append an extra value to the end of the dimensions arrays
141
- x_dims = np.append(x_dims, x_dims[-1])
142
- y_dims = np.append(y_dims, y_dims[-1])
143
- z_dims = np.append(z_dims, z_dims[-1])
144
-
145
- # Assign the dimensions to the tensor attributes
146
- block_model.geometry.tensor_u = x_dims
147
- block_model.geometry.tensor_v = y_dims
148
- block_model.geometry.tensor_w = z_dims
99
+ if geom.__class__.__name__ == 'RegularGeometry':
100
+ volume = geom.block_size[0] * geom.block_size[1] * geom.block_size[2]
101
+ elif geom.__class__.__name__ == 'TensorGeometry':
102
+ # TODO: Implement the volume calculation for TensorGeometry - this is a placeholder.
103
+ volume = geom.block_sizes[0][0] * geom.block_sizes[0][1] * geom.block_sizes[0][2]
149
104
  else:
150
- block_model.geometry.tensor_u = self.data.index.get_level_values('dx').unique().tolist()
151
- block_model.geometry.tensor_v = self.data.index.get_level_values('dy').unique().tolist()
152
- block_model.geometry.tensor_w = self.data.index.get_level_values('dz').unique().tolist()
153
-
154
- # Sort the blocks by their x, y, and z coordinates
155
- blocks: pd.DataFrame = self.data.sort_index()
105
+ raise ValueError(f"Geometry type '{geom.__class__.__name__}' not supported.")
156
106
 
157
- # Add the data to the block model
158
- data = [imports.omf.ScalarData(name=col, location='cells', array=blocks[col].values) for col in blocks.columns]
159
- block_model.data = data
107
+ if density is not None:
108
+ blocks['mass_dry'] = volume * density
109
+ moisture_in_scope = False
160
110
 
161
- # Add the block model to the project
162
- project.elements = [block_model]
111
+ return cls(data=blocks, name=element_name, mass_dry_var='mass_dry', moisture_in_scope=moisture_in_scope)
163
112
 
164
- assert project.validate()
113
+ @import_extras
114
+ def to_omf(self, omf_filepath: Path, imports, element_name: str = 'Block Model',
115
+ description: str = 'A block model'):
116
+ """Write the BlockModel to an OMF file.
117
+
118
+ Args:
119
+ omf_filepath: Path to the OMF file.
120
+ imports: internally used to import the necessary packages.
121
+ element_name: The name of the element in the OMF file.
122
+ description: Description of the block model.
123
+ """
124
+ # Create an OMFPandasWriter instance
125
+ writer = imports.omfpandas.OMFPandasWriter(filepath=omf_filepath)
165
126
 
166
- # Write the project to a file
167
- imports.omf.OMFWriter(project, str(omf_filepath))
127
+ # Write the block model to the OMF file
128
+ writer.write_blockmodel(blockmodel_name=element_name, description=description, dataframe=self.data)
168
129
 
169
130
  @log_timer
170
131
  def get_blocks(self) -> Union['pv.StructuredGrid', 'pv.UnstructuredGrid']:
@@ -235,7 +196,7 @@ class BlockModel(MassComposition):
235
196
  def create_structured_grid(self, imports) -> 'pv.StructuredGrid':
236
197
 
237
198
  # Get the unique x, y, z coordinates (centroids)
238
- data = self.data
199
+ data = self.data.sort_values(['z', 'y', 'x']) # ensure the data is sorted F-style
239
200
  x_centroids = data.index.get_level_values('x').unique()
240
201
  y_centroids = data.index.get_level_values('y').unique()
241
202
  z_centroids = data.index.get_level_values('z').unique()
@@ -274,7 +235,7 @@ class BlockModel(MassComposition):
274
235
  """
275
236
 
276
237
  # Get the x, y, z coordinates and cell dimensions
277
- blocks = self.data.reset_index().sort_values(['z', 'y', 'x'])
238
+ blocks = self.data.reset_index().sort_values(['z', 'y', 'x']) # ensure the data is sorted F-style
278
239
  # if no dims are passed, estimate them
279
240
  if 'dx' not in blocks.columns:
280
241
  dx, dy, dz = self.common_block_size()
@@ -3,8 +3,8 @@ _blockmodel_imports = None
3
3
 
4
4
  # Define the Extras class to encapsulate the imported modules
5
5
  class BlockmodelExtras:
6
- def __init__(self, omf, omfvista, pv):
7
- self.omf = omf
6
+ def __init__(self, omfpandas, omfvista, pv):
7
+ self.omfpandas = omfpandas
8
8
  self.omfvista = omfvista
9
9
  self.pv = pv
10
10
 
@@ -15,7 +15,7 @@ def import_blockmodel_packages():
15
15
 
16
16
  # Optional imports
17
17
  try:
18
- import omf
18
+ import omfpandas
19
19
  import omfvista
20
20
  import pyvista as pv
21
21
  from pyvista import CellType
@@ -25,10 +25,10 @@ def import_blockmodel_packages():
25
25
 
26
26
  if _blockmodel_imports is None:
27
27
  try:
28
- import omf
28
+ import omfpandas
29
29
  import omfvista
30
30
  import pyvista as pv
31
- _blockmodel_imports = (omf, omfvista, pv)
31
+ _blockmodel_imports = (omfpandas, omfvista, pv)
32
32
  except ImportError:
33
33
  raise ImportError("Failed to import blockmodel related packages. "
34
34
  "Consider executing: 'poetry install --extras blockmodel'")
@@ -1,7 +1,7 @@
1
1
  [tool.poetry]
2
2
  name = "geometallurgy"
3
3
  packages = [{ include = "elphick/geomet" }]
4
- version = "0.4.12"
4
+ version = "0.4.14"
5
5
  description = "Tools for the geometallurgist"
6
6
  authors = ["Greg <11791585+elphick@users.noreply.github.com>"]
7
7
  repository = "https://github.com/elphick/geometallurgy"
@@ -36,22 +36,25 @@ showcontent = true
36
36
  #log_cli_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
37
37
 
38
38
  [tool.poetry.dependencies]
39
- python = ">=3.9,<3.13"
39
+ python = ">=3.10,<3.13"
40
40
  plotly = "^5.22.0"
41
41
  pandas = ">=1.0"
42
42
  periodictable = "^1.7.0"
43
43
  #geoh5py = ">=0.8.0,<10.0.0"
44
44
  pyarrow = ">=16.1.0,<18.0.0"
45
45
  folium = { version = "^0.16.0", optional = true }
46
+ rioxarray = { version = "^0.18.2", optional = true }
46
47
  pandera = { version = ">=0.19.3,<0.21.0", extras = ['io'], optional = true }
47
- #omfpandas = { version = ">=0.2.1", optional = true } # last omfv1 version
48
+ omfpandas = { version = "^0.8.1", optional = true }
49
+ #omf = { version = "<2.0" }
50
+
48
51
  omfvista = { version = ">=0.3.0", optional = true }
49
52
 
50
53
  [tool.poetry.extras]
51
- map = ["folium"]
52
54
  validation = ["pandera"]
53
- blockmodel = ["omfvista"] #, "omfpandas"]
54
- all = ["map", "validation", "blockmodel"]
55
+ blockmodel = ["omfvista", "omfpandas"]
56
+ spatial = ["folium", "rioxarray"]
57
+ all = ["validation", "blockmodel", "spatial"]
55
58
 
56
59
  [tool.poetry.group.dev.dependencies]
57
60
  pytest = "^8.2.1"
File without changes
File without changes