Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for grids and grid properties #355

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/fmu/sumo/explorer/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from fmu.sumo.explorer.objects.surface import Surface
from fmu.sumo.explorer.objects.polygons import Polygons
from fmu.sumo.explorer.objects.table import Table
from fmu.sumo.explorer.objects.cpgrid import CPGrid
from fmu.sumo.explorer.objects.cpgrid_property import CPGridProperty
from fmu.sumo.explorer.objects.iteration import Iteration
from fmu.sumo.explorer.objects.iterations import Iterations
from fmu.sumo.explorer.objects.realization import Realization
Expand Down
45 changes: 38 additions & 7 deletions src/fmu/sumo/explorer/objects/_search_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,12 @@ def _to_sumo(self, obj, blob=None):
"polygons": objects.Polygons,
"surface": objects.Surface,
"table": objects.Table,
"cpgrid": objects.CPGrid,
"cpgrid_property": objects.CPGridProperty
}.get(cls)
if constructor is None:
warnings.warn(f"No constructor for class {cls}")
constructor = objects.Child
warnings.warn(f"No constructor for class {cls}")
constructor = objects.Child
return constructor(self._sumo, obj, blob)

def __len__(self):
Expand Down Expand Up @@ -557,7 +559,7 @@ def _maybe_prefetch(self, index):
uuid = self._hits[index]
if self._cache.has(uuid):
return
uuids = self._hits[index : min(index + 100, len(self._hits))]
uuids = self._hits[index:min(index + 100, len(self._hits))]
uuids = [uuid for uuid in uuids if not self._cache.has(uuid)]
hits = self.__search_all(
{"ids": {"values": uuids}},
Expand All @@ -575,7 +577,7 @@ async def _maybe_prefetch_async(self, index):
uuid = self._hits[index]
if self._cache.has(uuid):
return
uuids = self._hits[index : min(index + 100, len(self._hits))]
uuids = self._hits[index:min(index + 100, len(self._hits))]
uuids = [uuid for uuid in uuids if not self._cache.has(uuid)]
hits = await self.__search_all_async(
{"ids": {"values": uuids}},
Expand Down Expand Up @@ -809,17 +811,38 @@ def all(self):
@property
def cases(self):
"""Cases from current selection."""
return objects.Cases(self)
uuids = self._get_field_values("fmu.case.uuid.keyword")
return objects.Cases(self, uuids)

@property
async def cases_async(self):
"""Cases from current selection."""
uuids = await self._get_field_values_async("fmu.case.uuid.keyword")
return objects.Cases(self, uuids)

@property
def iterations(self):
"""Iterations from current selection."""
return objects.Iterations(self)
uuids = self._get_field_values("fmu.iteration.uuid.keyword")
return objects.Iterations(self, uuids)

@property
async def iterations_async(self):
"""Iterations from current selection."""
uuids = await self._get_field_values_async("fmu.iteration.uuid.keyword")
return objects.Iterations(self, uuids)

@property
def realizations(self):
"""Realizations from current selection."""
return objects.Realizations(self)
uuids = self._get_field_values("fmu.realization.uuid.keyword")
return objects.Realizations(self, uuids)

@property
async def realizations_async(self):
"""Realizations from current selection."""
uuids = await self._get_field_values_async("fmu.realization.uuid.keyword")
return objects.Realizations(self, uuids)

@property
def template_paths(sc):
Expand Down Expand Up @@ -958,6 +981,14 @@ def polygons(self):
def dictionaries(self):
return self._context_for_class("dictionary")

@property
def grids(self):
return self._context_for_class("cpgrid")

@property
def grid_properties(self):
return self._context_for_class("cpgrid_property")

def _get_object_by_class_and_uuid(self, cls, uuid):
obj = self.get_object(uuid)
if obj.metadata["class"] != cls:
Expand Down
37 changes: 3 additions & 34 deletions src/fmu/sumo/explorer/objects/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,11 @@
from fmu.sumo.explorer.objects._search_context import SearchContext

class Cases(SearchContext):
def __init__(self, sc):
super().__init__(sc._sumo, sc._must, sc._must_not)
def __init__(self, sc, uuids):
super().__init__(sc._sumo, must=[{"terms": {"fmu.case.uuid.keyword": uuids}}])
self._hits = uuids
return

def __len__(self):
if self._length is None:
if self._hits is None:
self._hits = self._search_all(select=False)
pass
self._length = len(self._hits)
pass
return self._length

async def length_async(self):
if self._length is None:
if self._hits is None:
self._hits = self._search_all(select=False)
pass
self._length = len(self._hits)
pass
return self._length

def _search_all(self, select=False):
uuids = self._get_field_values("fmu.case.uuid.keyword")
if select is False:
return uuids
# ELSE
return SearchContext(must=[{"ids": {"values": uuids}}])._search_all(select=select)

async def _search_all_async(self, select=False):
uuids = await self._get_field_values_async("fmu.case.uuid.keyword")
if select is False:
return uuids
# ELSE
return await SearchContext(must=[{"ids": {"values": uuids}}])._search_all_async(select=select)

def _maybe_prefetch(self, index):
return

Expand Down
46 changes: 46 additions & 0 deletions src/fmu/sumo/explorer/objects/cpgrid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Module containing class for cpgrid"""

from typing import Dict
from sumo.wrapper import SumoClient
from fmu.sumo.explorer.objects._child import Child

class CPGrid(Child):
"""Class representing a cpgrid object in Sumo."""

def __init__(self, sumo: SumoClient, metadata: Dict, blob=None) -> None:
"""
Args:
sumo (SumoClient): connection to Sumo
metadata (dict): dictionary metadata
blob: data object
"""
super().__init__(sumo, metadata, blob)

def to_cpgrid(self):
"""Get cpgrid object as a Grid
Returns:
Grid: A Grid object
"""
try:
from xtgeo import grid_from_file
except ModuleNotFoundError:
raise RuntimeError("Unable to import xtgeo; probably not installed.")
try:
return grid_from_file(self.blob)
except TypeError as type_err:
raise TypeError(f"Unknown format: {self.format}") from type_err

async def to_cpgrid_async(self):
"""Get cpgrid object as a Grid
Returns:
Grid: A Grid object
"""
try:
from xtgeo import grid_from_file
except ModuleNotFoundError:
raise RuntimeError("Unable to import xtgeo; probably not installed.")

try:
return grid_from_file(await self.blob_async)
except TypeError as type_err:
raise TypeError(f"Unknown format: {self.format}") from type_err
46 changes: 46 additions & 0 deletions src/fmu/sumo/explorer/objects/cpgrid_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Module containing class for cpgrid_property"""

from typing import Dict
from sumo.wrapper import SumoClient
from fmu.sumo.explorer.objects._child import Child

class CPGridProperty(Child):
"""Class representing a cpgrid_property object in Sumo."""

def __init__(self, sumo: SumoClient, metadata: Dict, blob=None) -> None:
"""
Args:
sumo (SumoClient): connection to Sumo
metadata (dict): dictionary metadata
blob: data object
"""
super().__init__(sumo, metadata, blob)

def to_cpgrid_property(self):
"""Get cpgrid_property object as a GridProperty
Returns:
GridProperty: A GridProperty object
"""
try:
from xtgeo import gridproperty_from_file
except ModuleNotFoundError:
raise RuntimeError("Unable to import xtgeo; probably not installed.")
try:
return gridproperty_from_file(self.blob)
except TypeError as type_err:
raise TypeError(f"Unknown format: {self.format}") from type_err

async def to_cpgrid_property_async(self):
"""Get cpgrid_property object as a GridProperty
Returns:
GridProperty: A GridProperty object
"""
try:
from xtgeo import gridproperty_from_file
except ModuleNotFoundError:
raise RuntimeError("Unable to import xtgeo; probably not installed.")

try:
return gridproperty_from_file(await self.blob_async)
except TypeError as type_err:
raise TypeError(f"Unknown format: {self.format}") from type_err
29 changes: 3 additions & 26 deletions src/fmu/sumo/explorer/objects/iterations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,11 @@
from fmu.sumo.explorer.objects._search_context import SearchContext

class Iterations(SearchContext):
def __init__(self, _search_context):
super().__init__(_search_context._sumo, _search_context._must, _search_context._must_not)
def __init__(self, sc, uuids):
super().__init__(sc._sumo, must=[{"terms": {"fmu.iteration.uuid.keyword": uuids}}])
self._hits = uuids
return

def __len__(self):
if self._length is None:
if self._hits is None:
self._hits = self._search_all(select=False)
pass
self._length = len(self._hits)
pass
return self._length

async def length_async(self):
if self._length is None:
if self._hits is None:
self._hits = self._search_all(select=False)
pass
self._length = len(self._hits)
pass
return self._length

def _search_all(self, select=False):
return self._get_field_values("fmu.iteration.uuid.keyword")

async def _search_all_async(self, select=False):
return await self._get_field_values_async("fmu.iteration.uuid.keyword")

def _maybe_prefetch(self, index):
return

Expand Down
28 changes: 3 additions & 25 deletions src/fmu/sumo/explorer/objects/realizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,11 @@
from fmu.sumo.explorer.objects._search_context import SearchContext

class Realizations(SearchContext):
def __init__(self, sc):
super().__init__(sc._sumo, sc._must, sc._must_not)
def __init__(self, sc, uuids):
super().__init__(sc._sumo, must=[{"terms": {"fmu.realization.uuid.keyword": uuids}}])
self._hits = uuids
return

def __len__(self):
if self._length is None:
if self._hits is None:
self._hits = self._search_all(select=False)
pass
self._length = len(self._hits)
pass
return self._length

async def length_async(self):
if self._length is None:
if self._hits is None:
self._hits = self._search_all(select=False)
pass
self._length = len(self._hits)
pass
return self._length

def _search_all(self, select=False):
return self._get_field_values("fmu.realization.uuid.keyword")

async def _search_all_async(self, select=False):
return await self._get_field_values_async("fmu.realization.uuid.keyword")
def _maybe_prefetch(self, index):
return

Expand Down
19 changes: 19 additions & 0 deletions tests/test_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,4 +327,23 @@ def test_seismic_case_by_uuid(explorer: Explorer, seismic_case_uuid: str):
assert "Trace" in channel_list
assert "SEGYTraceHeader" in channel_list

def test_grids_and_properties(explorer: Explorer):
cases_with_grids = explorer.grids.cases.filter(status="keep").cases
cases_with_gridprops = explorer.grid_properties.cases.filter(status="keep").cases
cgs=set([case.uuid for case in cases_with_grids])
cgps=set([case.uuid for case in cases_with_gridprops])
assert cgs==cgps
case=cases_with_grids[0]
grids=case.grids
gridprops=case.grid_properties
xtgrid=grids[0].to_cpgrid()
gridspec=grids[0].metadata["data"]["spec"]
assert xtgrid.nlay == gridspec["nlay"]
assert xtgrid.nrow == gridspec["nrow"]
assert xtgrid.ncol == gridspec["ncol"]
xtgridprop=gridprops[0].to_cpgrid_property()
gridpropspec = gridprops[0].metadata["data"]["spec"]
assert xtgridprop.nlay == gridpropspec["nlay"]
assert xtgridprop.nrow == gridpropspec["nrow"]
assert xtgridprop.ncol == gridpropspec["ncol"]