|
21 | 21 | from typing import Any |
22 | 22 |
|
23 | 23 | 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 |
26 | 33 | from geoh5py.objects import BlockModel, Curve, Grid2D, ObjectBase, Points, Surface |
27 | 34 | from geoh5py.shared import FLOAT_NDV, INTEGER_NDV, Entity |
28 | 35 | from geoh5py.workspace import Workspace |
29 | 36 |
|
30 | | -from omf.base import Project, UidModel |
| 37 | +from omf.base import ContentModel, Project, UidModel |
31 | 38 | from omf.data import ( |
32 | 39 | ColorArray, |
33 | 40 | Int2Array, |
@@ -203,7 +210,7 @@ def from_geoh5(self, entity, **kwargs) -> dict: |
203 | 210 | @staticmethod |
204 | 211 | def process_dependents( |
205 | 212 | element: UidModel | Entity, |
206 | | - parent: Entity, |
| 213 | + parent: Entity | None, |
207 | 214 | workspace: str | Path | Workspace, |
208 | 215 | compression: int, |
209 | 216 | ) -> list: |
@@ -238,7 +245,11 @@ def process_dependents( |
238 | 245 | converter = get_conversion_map( |
239 | 246 | child, workspace, compression=compression, parent=element |
240 | 247 | ) |
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) |
242 | 253 |
|
243 | 254 | if len(children_list) > 1: |
244 | 255 | _logger.info( |
@@ -368,6 +379,51 @@ def from_geoh5(self, entity: Data, **kwargs) -> UidModel | list: # type: ignore |
368 | 379 | return element |
369 | 380 |
|
370 | 381 |
|
| 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 | + |
371 | 427 | class ElementConversion(BaseConversion): |
372 | 428 | """ |
373 | 429 | Conversion between :obj:`omf.pointset.PointSetElement` and |
@@ -492,12 +548,13 @@ def from_geoh5(self, entity: RootGroup, **kwargs) -> Project: # type: ignore |
492 | 548 | uid = kwargs.pop("uid") |
493 | 549 | project = self.omf_type(**kwargs) |
494 | 550 | project._backend.update({"uid": uid}) # pylint: disable=W0212 |
495 | | - project.elements = self.process_dependents( |
| 551 | + elements = self.process_dependents( |
496 | 552 | entity, |
497 | 553 | project, |
498 | 554 | workspace, |
499 | 555 | self.compression, # type: ignore |
500 | 556 | ) |
| 557 | + project.elements = elements |
501 | 558 |
|
502 | 559 | return project |
503 | 560 |
|
@@ -565,6 +622,10 @@ def collect_attributes( |
565 | 622 | else: |
566 | 623 | values = getattr(element, "values", None) |
567 | 624 |
|
| 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 | + |
568 | 629 | if np.issubdtype(values.dtype, np.floating): |
569 | 630 | values[np.isclose(values, FLOAT_NDV, atol=2e-45)] = np.nan |
570 | 631 | else: |
@@ -612,6 +673,10 @@ def collect_attributes( |
612 | 673 | values = element.array.array |
613 | 674 | else: |
614 | 675 | 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 | + |
615 | 680 | values[np.isclose(values, INTEGER_NDV)] = 0 |
616 | 681 |
|
617 | 682 | if values is not None: |
@@ -706,6 +771,10 @@ def collect_h5_attributes( |
706 | 771 | return kwargs |
707 | 772 |
|
708 | 773 | labels = list(element.value_map().values()) |
| 774 | + |
| 775 | + if isinstance(labels[0], bytes): |
| 776 | + labels = [label.decode("utf-8") for label in labels] |
| 777 | + |
709 | 778 | ind = 0 |
710 | 779 | if "Unknown" in labels: |
711 | 780 | ind = 1 |
@@ -1304,6 +1373,7 @@ def block_model_reordering(entity: BlockModel | VolumeElement, values: np.ndarra |
1304 | 1373 |
|
1305 | 1374 | _CONVERSION_MAP: dict = { |
1306 | 1375 | BlockModel: VolumeConversion, |
| 1376 | + ContainerGroup: ContainerGroupConversion, |
1307 | 1377 | Curve: CurveConversion, |
1308 | 1378 | FloatData: ScalarDataConversion, |
1309 | 1379 | Grid2D: SurfaceGridConversion, |
|
0 commit comments