Skip to content

Commit

Permalink
ENH: Return BaseModel from bbox getters
Browse files Browse the repository at this point in the history
This also allows the getter to be optional in the cases in which the
method will never be called because a bounding box is not relevant to
the data type.

Schema was updated to reflect the added docstrings.
  • Loading branch information
mferrera committed May 27, 2024
1 parent 282ea0a commit fc2abed
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 68 deletions.
2 changes: 2 additions & 0 deletions schema/definitions/0.8.0/schema/fmu_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@
"type": "integer"
},
"BoundingBox2D": {
"description": "Contains the 2D coordinates within which a data object is contained.",
"properties": {
"xmax": {
"description": "Maximum x-coordinate",
Expand Down Expand Up @@ -269,6 +270,7 @@
"type": "object"
},
"BoundingBox3D": {
"description": "Contains the 3D coordinates within which a data object is contained.",
"properties": {
"xmax": {
"description": "Maximum x-coordinate",
Expand Down
4 changes: 4 additions & 0 deletions src/fmu/dataio/datastructure/meta/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ class Layer(BaseModel):


class BoundingBox2D(BaseModel):
"""Contains the 2D coordinates within which a data object is contained."""

xmin: float = Field(
description="Minimum x-coordinate",
allow_inf_nan=False,
Expand All @@ -141,6 +143,8 @@ class BoundingBox2D(BaseModel):


class BoundingBox3D(BoundingBox2D):
"""Contains the 3D coordinates within which a data object is contained."""

zmin: float = Field(
description=(
"Minimum z-coordinate. For regular surfaces this field represents the "
Expand Down
3 changes: 2 additions & 1 deletion src/fmu/dataio/providers/objectdata/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

if TYPE_CHECKING:
from fmu.dataio.dataio import ExportData
from fmu.dataio.datastructure.meta.content import BoundingBox2D, BoundingBox3D
from fmu.dataio.types import Classname, Efolder, Inferrable, Layout, Subtype

logger: Final = null_logger(__name__)
Expand Down Expand Up @@ -261,7 +262,7 @@ def get_spec(self) -> dict:
raise NotImplementedError

@abstractmethod
def get_bbox(self) -> dict:
def get_bbox(self) -> BoundingBox2D | BoundingBox3D | None:
raise NotImplementedError

@abstractmethod
Expand Down
25 changes: 11 additions & 14 deletions src/fmu/dataio/providers/objectdata/_faultroom.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from fmu.dataio._definitions import ValidFormats
from fmu.dataio._logging import null_logger
from fmu.dataio.datastructure.meta import meta, specification
from fmu.dataio.datastructure.meta import specification
from fmu.dataio.datastructure.meta.content import BoundingBox3D
from fmu.dataio.readers import FaultRoomSurface

from ._base import (
Expand All @@ -20,20 +21,16 @@
class FaultRoomSurfaceProvider(ObjectDataProvider):
obj: FaultRoomSurface

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> BoundingBox3D:
"""Derive data.bbox for FaultRoomSurface."""
logger.info("Get bbox for FaultRoomSurface")
faultsurf = self.obj
return meta.content.BoundingBox3D(
xmin=float(faultsurf.bbox["xmin"]),
xmax=float(faultsurf.bbox["xmin"]),
ymin=float(faultsurf.bbox["ymin"]),
ymax=float(faultsurf.bbox["ymax"]),
zmin=float(faultsurf.bbox["zmin"]),
zmax=float(faultsurf.bbox["zmax"]),
).model_dump(
mode="json",
exclude_none=True,
return BoundingBox3D(
xmin=float(self.obj.bbox["xmin"]),
xmax=float(self.obj.bbox["xmin"]),
ymin=float(self.obj.bbox["ymin"]),
ymax=float(self.obj.bbox["ymax"]),
zmin=float(self.obj.bbox["zmin"]),
zmax=float(self.obj.bbox["zmax"]),
)

def get_spec(self) -> dict[str, Any]:
Expand Down Expand Up @@ -61,7 +58,7 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
efolder="maps",
fmt=(fmt := self.dataio.dict_fformat),
spec=self.get_spec(),
bbox=self.get_bbox(),
bbox=self.get_bbox().model_dump(mode="json", exclude_none=True),
extension=self._validate_get_ext(fmt, "JSON", ValidFormats().dictionary),
table_index=None,
)
12 changes: 4 additions & 8 deletions src/fmu/dataio/providers/objectdata/_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,8 @@ def get_spec(self) -> dict:
"""Derive data.spec from existing metadata."""
return self.metadata["spec"]

def get_bbox(self) -> dict:
def get_bbox(self) -> None:
"""Derive data.bbox from existing metadata."""
return self.metadata["bbox"]

def get_objectdata(self) -> DerivedObjectDescriptor:
"""Derive object data for existing metadata."""
Expand All @@ -185,14 +184,13 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=self.fmt,
extension=self.extension,
spec=self.get_spec(),
bbox=self.get_bbox(),
bbox=self.metadata["bbox"],
table_index=None,
)

def derive_metadata(self) -> None:
"""Metadata has already been derived for this provider, and is already set from
instantiation, so override this method and do nothing."""
return


@dataclass
Expand All @@ -204,10 +202,8 @@ def get_spec(self) -> dict[str, Any]:
logger.info("Get spec for dictionary")
return {}

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> None:
"""Derive data.bbox for dict."""
logger.info("Get bbox for dictionary")
return {}

def get_objectdata(self) -> DerivedObjectDescriptor:
"""Derive object data for dict."""
Expand All @@ -219,6 +215,6 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=(fmt := self.dataio.dict_fformat),
extension=self._validate_get_ext(fmt, "JSON", ValidFormats().dictionary),
spec=self.get_spec() or None,
bbox=self.get_bbox() or None,
bbox=None,
table_index=None,
)
12 changes: 4 additions & 8 deletions src/fmu/dataio/providers/objectdata/_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ def get_spec(self) -> dict:
exclude_none=True,
)

def get_bbox(self) -> dict:
def get_bbox(self) -> None:
"""Derive data.bbox for pd.DataFrame."""
logger.info("Get bbox for pd.DataFrame (tables)")
return {}

def get_objectdata(self) -> DerivedObjectDescriptor:
"""Derive object data for pd.DataFrame."""
Expand All @@ -87,7 +85,7 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=(fmt := self.dataio.table_fformat),
extension=self._validate_get_ext(fmt, "DataFrame", ValidFormats().table),
spec=self.get_spec(),
bbox=self.get_bbox() or None,
bbox=None,
table_index=table_index,
)

Expand All @@ -108,10 +106,8 @@ def get_spec(self) -> dict:
exclude_none=True,
)

def get_bbox(self) -> dict:
def get_bbox(self) -> None:
"""Derive data.bbox for pyarrow.Table."""
logger.info("Get bbox for pyarrow (tables)")
return {}

def get_objectdata(self) -> DerivedObjectDescriptor:
"""Derive object data from pyarrow.Table."""
Expand All @@ -124,6 +120,6 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=(fmt := self.dataio.arrow_fformat),
extension=self._validate_get_ext(fmt, "ArrowTable", ValidFormats().table),
spec=self.get_spec(),
bbox=self.get_bbox() or None,
bbox=None,
table_index=table_index,
)
57 changes: 22 additions & 35 deletions src/fmu/dataio/providers/objectdata/_xtgeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from fmu.dataio._definitions import ValidFormats
from fmu.dataio._logging import null_logger
from fmu.dataio._utils import npfloat_to_float
from fmu.dataio.datastructure.meta import meta, specification
from fmu.dataio.datastructure.meta import specification
from fmu.dataio.datastructure.meta.content import BoundingBox2D, BoundingBox3D

from ._base import (
DerivedObjectDescriptor,
Expand Down Expand Up @@ -47,7 +48,7 @@ def get_spec(self) -> dict[str, Any]:
exclude_none=True,
)

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> BoundingBox2D | BoundingBox3D:
"""
Derive data.bbox for xtgeo.RegularSurface. The zmin/zmax fields represents
the minimum/maximum surface values and should be absent in the metadata if the
Expand All @@ -56,21 +57,21 @@ def get_bbox(self) -> dict[str, Any]:
logger.info("Get bbox for RegularSurface")

if np.isfinite(self.obj.values).any():
return meta.content.BoundingBox3D(
return BoundingBox3D(
xmin=float(self.obj.xmin),
xmax=float(self.obj.xmax),
ymin=float(self.obj.ymin),
ymax=float(self.obj.ymax),
zmin=float(self.obj.values.min()),
zmax=float(self.obj.values.max()),
).model_dump(mode="json", exclude_none=True)
)

return meta.content.BoundingBox2D(
return BoundingBox2D(
xmin=float(self.obj.xmin),
xmax=float(self.obj.xmax),
ymin=float(self.obj.ymin),
ymax=float(self.obj.ymax),
).model_dump(mode="json", exclude_none=True)
)

def get_objectdata(self) -> DerivedObjectDescriptor:
"""Derive object data for xtgeo.RegularSurface."""
Expand All @@ -81,7 +82,7 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
efolder="maps",
fmt=(fmt := self.dataio.surface_fformat),
spec=self.get_spec(),
bbox=self.get_bbox(),
bbox=self.get_bbox().model_dump(mode="json", exclude_none=True),
extension=self._validate_get_ext(
fmt, "RegularSurface", ValidFormats().surface
),
Expand All @@ -106,21 +107,18 @@ def get_spec(self) -> dict[str, Any]:
exclude_none=True,
)

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> BoundingBox3D:
"""Derive data.bbox for xtgeo.Polygons"""
logger.info("Get bbox for Polygons")

xmin, xmax, ymin, ymax, zmin, zmax = self.obj.get_boundary()
return meta.content.BoundingBox3D(
return BoundingBox3D(
xmin=float(xmin),
xmax=float(xmax),
ymin=float(ymin),
ymax=float(ymax),
zmin=float(zmin),
zmax=float(zmax),
).model_dump(
mode="json",
exclude_none=True,
)

def get_objectdata(self) -> DerivedObjectDescriptor:
Expand All @@ -133,7 +131,7 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=(fmt := self.dataio.polygons_fformat),
extension=self._validate_get_ext(fmt, "Polygons", ValidFormats().polygons),
spec=self.get_spec(),
bbox=self.get_bbox(),
bbox=self.get_bbox().model_dump(mode="json", exclude_none=True),
table_index=None,
)

Expand All @@ -160,21 +158,18 @@ def get_spec(self) -> dict[str, Any]:
exclude_none=True,
)

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> BoundingBox3D:
"""Derive data.bbox for xtgeo.Points."""
logger.info("Get bbox for Points")

df = self.obj_dataframe
return meta.content.BoundingBox3D(
return BoundingBox3D(
xmin=float(df[self.obj.xname].min()),
xmax=float(df[self.obj.xname].max()),
ymax=float(df[self.obj.yname].min()),
ymin=float(df[self.obj.yname].max()),
zmin=float(df[self.obj.zname].min()),
zmax=float(df[self.obj.zname].max()),
).model_dump(
mode="json",
exclude_none=True,
)

def get_objectdata(self) -> DerivedObjectDescriptor:
Expand All @@ -187,7 +182,7 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=(fmt := self.dataio.points_fformat),
extension=self._validate_get_ext(fmt, "Points", ValidFormats().points),
spec=self.get_spec(),
bbox=self.get_bbox(),
bbox=self.get_bbox().model_dump(mode="json", exclude_none=True),
table_index=None,
)

Expand Down Expand Up @@ -220,7 +215,7 @@ def get_spec(self) -> dict[str, Any]:
exclude_none=True,
)

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> BoundingBox3D:
"""Derive data.bbox for xtgeo.Cube."""
logger.info("Get bbox for Cube")

Expand All @@ -241,16 +236,13 @@ def get_bbox(self) -> dict[str, Any]:
ymin = min(ymin, yco)
ymax = max(ymax, yco)

return meta.content.BoundingBox3D(
return BoundingBox3D(
xmin=float(xmin),
xmax=float(xmax),
ymin=float(ymin),
ymax=float(ymax),
zmin=float(self.obj.zori),
zmax=float(self.obj.zori + self.obj.zinc * (self.obj.nlay - 1)),
).model_dump(
mode="json",
exclude_none=True,
)

def get_objectdata(self) -> DerivedObjectDescriptor:
Expand All @@ -263,7 +255,7 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=(fmt := self.dataio.cube_fformat),
extension=self._validate_get_ext(fmt, "RegularCube", ValidFormats().cube),
spec=self.get_spec(),
bbox=self.get_bbox(),
bbox=self.get_bbox().model_dump(mode="json", exclude_none=True),
table_index=None,
)

Expand Down Expand Up @@ -292,7 +284,7 @@ def get_spec(self) -> dict[str, Any]:
exclude_none=True,
)

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> BoundingBox3D:
"""Derive data.bbox for xtgeo.Grid."""
logger.info("Get bbox for Grid geometry")

Expand All @@ -301,16 +293,13 @@ def get_bbox(self) -> dict[str, Any]:
allcells=True,
return_dict=True,
)
return meta.content.BoundingBox3D(
return BoundingBox3D(
xmin=round(float(geox["xmin"]), 4),
xmax=round(float(geox["xmax"]), 4),
ymin=round(float(geox["ymin"]), 4),
ymax=round(float(geox["ymax"]), 4),
zmin=round(float(geox["zmin"]), 4),
zmax=round(float(geox["zmax"]), 4),
).model_dump(
mode="json",
exclude_none=True,
)

def get_objectdata(self) -> DerivedObjectDescriptor:
Expand All @@ -323,7 +312,7 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt=(fmt := self.dataio.grid_fformat),
extension=self._validate_get_ext(fmt, "CPGrid", ValidFormats().grid),
spec=self.get_spec(),
bbox=self.get_bbox(),
bbox=self.get_bbox().model_dump(mode="json", exclude_none=True),
table_index=None,
)

Expand All @@ -345,10 +334,8 @@ def get_spec(self) -> dict[str, Any]:
exclude_none=True,
)

def get_bbox(self) -> dict[str, Any]:
def get_bbox(self) -> None:
"""Derive data.bbox for xtgeo.GridProperty."""
logger.info("Get bbox for GridProperty")
return {}

def get_objectdata(self) -> DerivedObjectDescriptor:
"""Derive object data for xtgeo.GridProperty."""
Expand All @@ -362,6 +349,6 @@ def get_objectdata(self) -> DerivedObjectDescriptor:
fmt, "CPGridProperty", ValidFormats().grid
),
spec=self.get_spec(),
bbox=self.get_bbox() or None,
bbox=None,
table_index=None,
)
Loading

0 comments on commit fc2abed

Please sign in to comment.