diff --git a/schema/definitions/0.8.0/schema/fmu_meta.json b/schema/definitions/0.8.0/schema/fmu_meta.json index 250d31d0b..3425cc27f 100644 --- a/schema/definitions/0.8.0/schema/fmu_meta.json +++ b/schema/definitions/0.8.0/schema/fmu_meta.json @@ -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", @@ -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", diff --git a/src/fmu/dataio/datastructure/meta/content.py b/src/fmu/dataio/datastructure/meta/content.py index e5a1ca5b8..207475b6c 100644 --- a/src/fmu/dataio/datastructure/meta/content.py +++ b/src/fmu/dataio/datastructure/meta/content.py @@ -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, @@ -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 " diff --git a/src/fmu/dataio/providers/objectdata/_base.py b/src/fmu/dataio/providers/objectdata/_base.py index beb1c181b..432b0045f 100644 --- a/src/fmu/dataio/providers/objectdata/_base.py +++ b/src/fmu/dataio/providers/objectdata/_base.py @@ -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__) @@ -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 diff --git a/src/fmu/dataio/providers/objectdata/_faultroom.py b/src/fmu/dataio/providers/objectdata/_faultroom.py index 096d69322..2309ea39f 100644 --- a/src/fmu/dataio/providers/objectdata/_faultroom.py +++ b/src/fmu/dataio/providers/objectdata/_faultroom.py @@ -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 ( @@ -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]: @@ -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, ) diff --git a/src/fmu/dataio/providers/objectdata/_provider.py b/src/fmu/dataio/providers/objectdata/_provider.py index b32720163..9e1b018bc 100644 --- a/src/fmu/dataio/providers/objectdata/_provider.py +++ b/src/fmu/dataio/providers/objectdata/_provider.py @@ -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.""" @@ -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 @@ -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.""" @@ -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, ) diff --git a/src/fmu/dataio/providers/objectdata/_tables.py b/src/fmu/dataio/providers/objectdata/_tables.py index 55e7da71f..69ce649cc 100644 --- a/src/fmu/dataio/providers/objectdata/_tables.py +++ b/src/fmu/dataio/providers/objectdata/_tables.py @@ -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.""" @@ -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, ) @@ -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.""" @@ -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, ) diff --git a/src/fmu/dataio/providers/objectdata/_xtgeo.py b/src/fmu/dataio/providers/objectdata/_xtgeo.py index cd7f34a9d..4cf75e6ac 100644 --- a/src/fmu/dataio/providers/objectdata/_xtgeo.py +++ b/src/fmu/dataio/providers/objectdata/_xtgeo.py @@ -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, @@ -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 @@ -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.""" @@ -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 ), @@ -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: @@ -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, ) @@ -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: @@ -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, ) @@ -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") @@ -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: @@ -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, ) @@ -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") @@ -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: @@ -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, ) @@ -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.""" @@ -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, ) diff --git a/tests/test_units/test_objectdataprovider_class.py b/tests/test_units/test_objectdataprovider_class.py index 099b82261..92ffe8986 100644 --- a/tests/test_units/test_objectdataprovider_class.py +++ b/tests/test_units/test_objectdataprovider_class.py @@ -97,8 +97,8 @@ def test_objectdata_regularsurface_spec_bbox(regsurf, edataobj1): bbox = objdata.get_bbox() assert specs["ncol"] == regsurf.ncol - assert bbox["xmin"] == 0.0 - assert bbox["zmin"] == 1234.0 + assert bbox.xmin == 0.0 + assert bbox.zmin == 1234.0 def test_objectdata_regularsurface_derive_objectdata(regsurf, edataobj1):