Skip to content

Commit 7d58f85

Browse files
authored
Merge pull request #99 from MiraGeoscience/GEOPY-2319
GEOPY-2319: OMF export fails on container group
2 parents 1c97986 + ae5b100 commit 7d58f85

3 files changed

Lines changed: 462 additions & 364 deletions

File tree

omf/fileio/geoh5.py

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,20 @@
2121
from typing import Any
2222

2323
import numpy as np
24-
from geoh5py.data import Data, FloatData, IntegerData, ReferencedData
25-
from geoh5py.groups import PropertyGroup, RootGroup
24+
from geoh5py.data import (
25+
Data,
26+
DataTypeEnum,
27+
FloatData,
28+
IntegerData,
29+
NumericData,
30+
ReferencedData,
31+
)
32+
from geoh5py.groups import ContainerGroup, PropertyGroup, RootGroup
2633
from geoh5py.objects import BlockModel, Curve, Grid2D, ObjectBase, Points, Surface
2734
from geoh5py.shared import FLOAT_NDV, INTEGER_NDV, Entity
2835
from geoh5py.workspace import Workspace
2936

30-
from omf.base import Project, UidModel
37+
from omf.base import ContentModel, Project, UidModel
3138
from omf.data import (
3239
ColorArray,
3340
Int2Array,
@@ -203,7 +210,7 @@ def from_geoh5(self, entity, **kwargs) -> dict:
203210
@staticmethod
204211
def process_dependents(
205212
element: UidModel | Entity,
206-
parent: Entity,
213+
parent: Entity | None,
207214
workspace: str | Path | Workspace,
208215
compression: int,
209216
) -> list:
@@ -238,7 +245,11 @@ def process_dependents(
238245
converter = get_conversion_map(
239246
child, workspace, compression=compression, parent=element
240247
)
241-
children += [getattr(converter, method)(child, **kwargs)]
248+
converted = getattr(converter, method)(child, **kwargs)
249+
if isinstance(converted, list):
250+
children += converted
251+
else:
252+
children.append(converted)
242253

243254
if len(children_list) > 1:
244255
_logger.info(
@@ -368,6 +379,51 @@ def from_geoh5(self, entity: Data, **kwargs) -> UidModel | list: # type: ignore
368379
return element
369380

370381

382+
class ContainerGroupConversion(BaseConversion):
383+
"""
384+
Forward only conversion from :obj:`geoh5py.groups.ContainerGroup` to a flatten
385+
OMF project.
386+
387+
:param obj: Either an omf or geoh5 class.
388+
:param geoh5: Path to a geoh5 or active :obj:`geoh5py.workspace.Workspace`.
389+
:param compression: Compression level for data.
390+
"""
391+
392+
_attribute_map: dict[str, Any] = {
393+
"name": "name",
394+
"uid": "uid",
395+
}
396+
397+
def __init__(
398+
self,
399+
obj: UidModel | Entity,
400+
geoh5: str | Path | Workspace,
401+
compression: int,
402+
**kwargs,
403+
):
404+
super().__init__(obj, geoh5, compression, **kwargs)
405+
406+
def from_omf(self, element: ContentModel, **kwargs) -> Entity | None: # type: ignore
407+
pass
408+
409+
def from_geoh5(self, entity: ObjectBase, **kwargs) -> UidModel: # type: ignore
410+
"""
411+
Convert :obj:`geoh5.objects` object to :obj:`omf.base.Element` class.
412+
413+
:param entity: Input :obj:`geoh5.objects` class.
414+
:param kwargs: Input dictionary of attributes to be appended.
415+
416+
:returns: An OMF Element.
417+
"""
418+
with fetch_h5_handle(self.geoh5) as workspace:
419+
return self.process_dependents(
420+
entity,
421+
None,
422+
workspace,
423+
self.compression, # type: ignore
424+
)
425+
426+
371427
class ElementConversion(BaseConversion):
372428
"""
373429
Conversion between :obj:`omf.pointset.PointSetElement` and
@@ -492,12 +548,13 @@ def from_geoh5(self, entity: RootGroup, **kwargs) -> Project: # type: ignore
492548
uid = kwargs.pop("uid")
493549
project = self.omf_type(**kwargs)
494550
project._backend.update({"uid": uid}) # pylint: disable=W0212
495-
project.elements = self.process_dependents(
551+
elements = self.process_dependents(
496552
entity,
497553
project,
498554
workspace,
499555
self.compression, # type: ignore
500556
)
557+
project.elements = elements
501558

502559
return project
503560

@@ -565,6 +622,10 @@ def collect_attributes(
565622
else:
566623
values = getattr(element, "values", None)
567624

625+
if values is None and isinstance(element, NumericData):
626+
dtype = DataTypeEnum[element.entity_type.primitive_type.name].value
627+
values = np.ones(element.n_values, dtype=dtype) * element.ndv
628+
568629
if np.issubdtype(values.dtype, np.floating):
569630
values[np.isclose(values, FLOAT_NDV, atol=2e-45)] = np.nan
570631
else:
@@ -612,6 +673,10 @@ def collect_attributes(
612673
values = element.array.array
613674
else:
614675
values = getattr(element, "values", None)
676+
677+
if values is None and isinstance(element, NumericData):
678+
values = np.ones(element.n_values, dtype=np.int32) * INTEGER_NDV
679+
615680
values[np.isclose(values, INTEGER_NDV)] = 0
616681

617682
if values is not None:
@@ -706,6 +771,10 @@ def collect_h5_attributes(
706771
return kwargs
707772

708773
labels = list(element.value_map().values())
774+
775+
if isinstance(labels[0], bytes):
776+
labels = [label.decode("utf-8") for label in labels]
777+
709778
ind = 0
710779
if "Unknown" in labels:
711780
ind = 1
@@ -1304,6 +1373,7 @@ def block_model_reordering(entity: BlockModel | VolumeElement, values: np.ndarra
13041373

13051374
_CONVERSION_MAP: dict = {
13061375
BlockModel: VolumeConversion,
1376+
ContainerGroup: ContainerGroupConversion,
13071377
Curve: CurveConversion,
13081378
FloatData: ScalarDataConversion,
13091379
Grid2D: SurfaceGridConversion,

0 commit comments

Comments
 (0)