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

WIP: Prototyping virtual objects Realization and Iteration. #314

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
70 changes: 67 additions & 3 deletions examples/explorer.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initialize Explorer"
"### TMP prototyping Iteration and Realization virtual objects"
]
},
{
Expand All @@ -25,7 +25,44 @@
"metadata": {},
"outputs": [],
"source": [
"sumo = Explorer()"
"from fmu.sumo.explorer import Explorer\n",
"sumo = Explorer()\n",
"\n",
"# idea: From fmu-sumo, should be able to utilize the Realization and the\n",
"# Iteration concepts directly as objects. Since they don't exist as explicit\n",
"# objects in Sumo, they are virtualized. Idea is that they should look and feel\n",
"# as if they were there (similar to the Case object).\n",
"\n",
"# Pattern 1: Drilling down from the case\n",
"\n",
"mycase = sumo.get_case_by_uuid(\"1ec9bfb0-8d82-4924-a74f-0a0f25054395\")\n",
"\n",
"print(mycase.iterations) # iterations under this case\n",
"\n",
"# pick an iteration\n",
"myiteration = mycase.iterations[\"iter-0\"]\n",
"print(myiteration)\n",
"print(myiteration.uuid)\n",
"\n",
"# pick a realization\n",
"realizations = myiteration.realizations\n",
"print(realizations)\n",
"\n",
"# The indexing pattern below is too confusing. It looks like a list index,\n",
"# i.e. \"give me the 10th realization\" but in fact it is a dict, and we are\n",
"# asking for realization-10 specifically. I.e. if realization 10 is not there,\n",
"# it will give KeyError.\n",
"\n",
"myrealization = realizations[10]\n",
"print(myrealization)\n",
"print(myrealization.surfaces)\n",
"\n",
"\n",
"# Pattern 2: Direct initialization from uuid\n",
"from fmu.sumo.explorer.objects._virtual_objects import Realization, Iteration\n",
"mydirectrealization = Realization(sumo, uuid=\"bdc4deb7-c3d9-64e1-198a-6b89a03e116a\")\n",
"print(mydirectrealization.surfaces)\n",
"\n"
]
},
{
Expand All @@ -47,7 +84,7 @@
"cases = sumo.cases.filter(asset=myassetname)\n",
"\n",
"# Get available status filters\n",
"print(\"Statuses:\",cases.statuses)\n",
"print(\"Statuses:\", cases.statuses)\n",
"\n",
"# Filter on status\n",
"cases = cases.filter(status=\"keep\")\n",
Expand Down Expand Up @@ -89,6 +126,33 @@
"print(\"Tables:\", len(case.polygons))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Find Iterations (ensembles) and Realizations\n",
"_Realization_ and _iteration_ (_ensemble_) are well known concepts in the FMU context, but not explicitly represented by objects in Sumo (metadata not created by `fmu-dataio`)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"surfs = case.surfaces\n",
"print(surfs.iterations)\n",
"\n",
"case.iterations"
]
},
{
"attachments": {},
"cell_type": "markdown",
Expand Down
191 changes: 191 additions & 0 deletions src/fmu/sumo/explorer/objects/_virtual_objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
"""Module containing class for virtual objects.

Virtual objects are objects that exist conceptually, but not as specific
data objects in Sumo, such as Realization and Iteration (ensembles)."""

from sumo.wrapper import SumoClient
from fmu.sumo.explorer.objects.surface_collection import SurfaceCollection
from fmu.sumo.explorer._utils import Utils
from fmu.sumo.explorer.pit import Pit

# from fmu.sumo.explorer.objects.case import Case


class Iteration:
"""Representation of the virtual Iteration object."""

def __init__(
self,
sumo: SumoClient,
uuid: str,
case=None,
name: str = None,
pit: Pit = None,
) -> None:

self._sumo = sumo
self._case = case
self._uuid = uuid
self._name = name
self._utils = Utils(sumo)
self._realizations = None
self._pit = pit

def __repr__(self):
return str(self)

def __str__(self):
"""String representation of this instance."""
return f"{self.name} ({self.uuid})"

@property
def uuid(self):
"""The fmu.iteration.uuid for this iteration."""
return self._uuid

@property
def name(self):
"""The fmu.iteration.name for this iteration."""
if self._name is None:
pass # TODO get name
return self._name

@property
def case(self):
"""Case instance representing the case that this iter belongs to."""
if self._case is None:
pass # TODO get_case
return self._case

@property
def realizations(self):
"""The realizations of this iteration."""
if self._realizations is None:
self._realizations = self._get_realizations()
return self._realizations

def _get_realizations(self):
"""Get all realizations of this iteration/ensemble."""

must = [
{
"term": {
"_sumo.parent_object.keyword": self._case.uuid,
}
},
{
"term": {
"fmu.iteration.uuid.keyword": self.uuid,
},
},
]

print("query realizations")

query = {
"query": {
"match": {
"fmu.iteration.uuid": "447992a4-b9c4-8619-6992-5d7d65b73309"
}
},
"aggs": {
"id": {
"terms": {
"field": "fmu.realization.id",
"size": 1000, # usually (!) less than 1000
},
"aggs": {
"uuid": {
"terms": {
"field": "fmu.realization.uuid.keyword",
"size": 10, # should be only one
}
},
"name": {
"terms": {
"field": "fmu.realization.name.keyword",
"size": 10, # should be only one
}
},
},
}
},
"size": 0,
}

res = self._sumo.post("/search", json=query)
buckets = res.json()["aggregations"]["id"]["buckets"]

realizations = {}

for bucket in buckets:
_realization = Realization(
sumo=self._sumo,
id=bucket["key"],
name=bucket["name"]["buckets"][0]["key"],
uuid=bucket["uuid"]["buckets"][0]["key"],
case=self.case,
)
realizations[_realization.id] = _realization

return realizations


class Realization:
"""Representation of the virtual Realization object."""

def __init__(
self,
sumo: SumoClient,
uuid: str,
id: str = None,
name: str = None,
pit: Pit = None,
case=None,
) -> None:
self._sumo = sumo
self._uuid = uuid
self._id = id
self._name = name
self._pit = pit
self._case = case

def __repr__(self):
return str(self)

def __str__(self):
"""String representation of this instance."""
return f"Realization {self.id} ({self.uuid})"

@property
def uuid(self):
"""The fmu.realization.uuid for this realization."""
return self._uuid

@property
def id(self):
"""The fmu.realization.id for this realization."""
return self._id

@property
def case(self):
"""Case instance representing the case this realization belongs to."""
# needed for the class-specific methods, e.g. .surfaces
if self._case is None:
pass # TODO get_case
return self._case

@property
def name(self):
"""The fmu.realization.name for this realization."""
if self._name is None:
pass # TODO get_name
return self._name

@property
def surfaces(self) -> SurfaceCollection:
"""List of surfaces under this realization."""
query = {"match": {"fmu.realization.uuid": self.uuid}}
return SurfaceCollection(
self._sumo, self._uuid, pit=self._pit, query=query
)
45 changes: 29 additions & 16 deletions src/fmu/sumo/explorer/objects/case.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Module containing case class"""

from typing import Dict, List
from sumo.wrapper import SumoClient
from fmu.sumo.explorer.objects._document import Document
Expand All @@ -9,15 +10,17 @@
from fmu.sumo.explorer.objects.dictionary_collection import (
DictionaryCollection,
)
from fmu.sumo.explorer.objects._virtual_objects import Iteration
from fmu.sumo.explorer._utils import Utils
from fmu.sumo.explorer.pit import Pit


class Case(Document):
"""Class for representing a case in Sumo"""

def __init__(self, sumo: SumoClient, metadata: Dict, overview: Dict,
pit: Pit = None):
def __init__(
self, sumo: SumoClient, metadata: Dict, overview: Dict, pit: Pit = None
):
super().__init__(metadata)
self._overview = overview
self._pit = pit
Expand Down Expand Up @@ -88,17 +91,19 @@ def iterations(self) -> List[Dict]:

res = self._sumo.post("/search", json=query)
buckets = res.json()["aggregations"]["uuid"]["buckets"]
iterations = []
iterations = {}

for bucket in buckets:
iterations.append(
{
"uuid": bucket["key"],
"name": bucket["name"]["buckets"][0]["key"],
"realizations": bucket["realizations"]["value"],
}
_iteration = Iteration(
sumo=self._sumo,
case=self,
uuid=bucket["key"],
name=bucket["name"]["buckets"][0]["key"],
pit=self._pit,
)

iterations[_iteration.name] = _iteration

self._iterations = iterations

return self._iterations
Expand Down Expand Up @@ -133,17 +138,25 @@ async def iterations_async(self) -> List[Dict]:

res = await self._sumo.post_async("/search", json=query)
buckets = res.json()["aggregations"]["id"]["buckets"]
iterations = []
iterations = {}

for bucket in buckets:
iterations.append(
{
"id": bucket["key"],
"name": bucket["name"]["buckets"][0]["key"],
"realizations": len(bucket["realizations"]["buckets"]),
}
_iteration = Iteration(
sumo=self._sumo,
case=self,
uuid=bucket["key"],
name=bucket["name"]["buckets"][0]["key"],
)

iterations[_iteration.name] = _iteration
# iterations.append(
# {
# "id": bucket["key"],
# "name": bucket["name"]["buckets"][0]["key"],
# "realizations": len(bucket["realizations"]["buckets"]),
# }
# )

self._iterations = iterations

return self._iterations
Expand Down
Loading