Skip to content

Commit

Permalink
Refactor surface directory
Browse files Browse the repository at this point in the history
  • Loading branch information
HansKallekleiv committed Sep 11, 2023
1 parent e0419b3 commit 285606e
Show file tree
Hide file tree
Showing 20 changed files with 658 additions and 865 deletions.
49 changes: 12 additions & 37 deletions backend/src/backend/primary/routers/surface/router.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import logging
from typing import List

from fastapi import APIRouter, Depends, HTTPException, Query
import numpy as np
from fastapi import APIRouter, Depends, HTTPException, Query, Body
import json

from src.services.sumo_access.surface_access import SurfaceAccess
from src.services.sumo_access.iteration_inspector import IterationInspector
from src.services.sumo_access.case_inspector import CaseInspector
from src.services.utils.statistic_function import StatisticFunction
from src.services.utils.authenticated_user import AuthenticatedUser
from src.services.utils.perf_timer import PerfTimer
Expand All @@ -12,54 +15,26 @@

from . import converters
from . import schemas
from src.services.sumo_access.generic_types import SumoContent

LOGGER = logging.getLogger(__name__)

router = APIRouter()


@router.get("/dynamic_surface_directory/")
def get_dynamic_surface_directory(
@router.get("/surface_directory/")
def get_surface_directory(
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Query(description="Sumo case uuid"),
ensemble_name: str = Query(description="Ensemble name"),
) -> schemas.DynamicSurfaceDirectory:
) -> List[schemas.SurfaceMeta]:
"""
Get a directory of surface names, attributes and time/interval strings for simulated dynamic surfaces.
Get a directory of surfaces in a Sumo ensemble
"""
access = SurfaceAccess(authenticated_user.get_sumo_access_token(), case_uuid, ensemble_name)
surf_dir = access.get_dynamic_surf_dir()

ret_dir = schemas.DynamicSurfaceDirectory(
names=surf_dir.names,
attributes=surf_dir.attributes,
time_or_interval_strings=surf_dir.date_strings,
)

return ret_dir


@router.get("/static_surface_directory/")
def get_static_surface_directory(
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Query(description="Sumo case uuid"),
ensemble_name: str = Query(description="Ensemble name"),
sumo_content_filter: List[SumoContent] = Query(default=None, description="Optional filter by Sumo content type"),
) -> schemas.StaticSurfaceDirectory:
"""
Get a directory of surface names and attributes for static surfaces.
These are the non-observed surfaces that do NOT have time stamps
"""
access = SurfaceAccess(authenticated_user.get_sumo_access_token(), case_uuid, ensemble_name)
surf_dir = access.get_static_surf_dir(content_filter=sumo_content_filter)

ret_dir = schemas.StaticSurfaceDirectory(
names=surf_dir.names,
attributes=surf_dir.attributes,
valid_attributes_for_name=surf_dir.valid_attributes_for_name,
)
surf_dir = access.get_surface_directory()

return ret_dir
return [schemas.SurfaceMeta(**surf_meta.__dict__) for surf_meta in surf_dir]


@router.get("/static_surface_data/")
Expand Down
22 changes: 11 additions & 11 deletions backend/src/backend/primary/routers/surface/schemas.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from enum import Enum
from typing import List
from typing import Optional

from pydantic import BaseModel

Expand All @@ -14,16 +14,16 @@ class SurfaceStatisticFunction(str, Enum):
P50 = "P50"


class DynamicSurfaceDirectory(BaseModel):
names: List[str]
attributes: List[str]
time_or_interval_strings: List[str]


class StaticSurfaceDirectory(BaseModel):
names: List[str]
attributes: List[str]
valid_attributes_for_name: List[List[int]]
class SurfaceMeta(BaseModel):
name: str
tagname: str
t_start: Optional[str]
t_end: Optional[str]
content: str
is_observation: bool
is_stratigraphic: bool
zmin: float
zmax: float


class SurfaceData(BaseModel):
Expand Down
131 changes: 30 additions & 101 deletions backend/src/services/sumo_access/surface_access.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from io import BytesIO
from typing import List, Optional, Tuple
from typing import List, Optional

import xtgeo
from fmu.sumo.explorer import TimeFilter, TimeType
Expand All @@ -11,8 +11,8 @@
from src.services.utils.statistic_function import StatisticFunction

from ._helpers import create_sumo_client_instance
from .surface_types import DynamicSurfaceDirectory, StaticSurfaceDirectory
from .generic_types import SumoContent
from .surface_types import SurfaceMeta


LOGGER = logging.getLogger(__name__)

Expand All @@ -24,111 +24,40 @@ def __init__(self, access_token: str, case_uuid: str, iteration_name: str):
self._iteration_name = iteration_name
self._sumo_case_obj: Optional[Case] = None

def get_dynamic_surf_dir(self) -> DynamicSurfaceDirectory:
"""
Get a directory of surface names, attributes and date strings for simulated dynamic surfaces.
These are the non-observed surfaces that DO have time stamps or time intervals
"""
timer = PerfTimer()

LOGGER.debug("Getting data for dynamic surface directory...")

case = self._get_my_sumo_case_obj()

filter_with_timestamp_or_interval = TimeFilter(TimeType.ALL)
surface_collection: SurfaceCollection = case.surfaces.filter(
iteration=self._iteration_name,
aggregation=False,
time=filter_with_timestamp_or_interval,
)

names = sorted(surface_collection.names)
attributes = sorted(surface_collection.tagnames)
timestamps: List[str] = surface_collection.timestamps
intervals: List[Tuple[str, str]] = surface_collection.intervals
available_contents = list(set(surf["data"]["content"] for surf in surface_collection))

LOGGER.debug(f"available surface contents: {available_contents}")

# ISO 8601 recommends '/' as separator, alternatively '--'
# https://en.wikipedia.org/wiki/ISO_8601#Time_intervals
intervals_as_strings: List[str] = [f"{interval[0]}--{interval[1]}" for interval in intervals]

date_strings: List[str] = []
date_strings.extend(timestamps)
date_strings.extend(intervals_as_strings)

surf_dir = DynamicSurfaceDirectory(names=names, attributes=attributes, date_strings=date_strings)

LOGGER.debug(f"Downloaded and built dynamic surface directory in: {timer.elapsed_ms():}ms")

return surf_dir

def get_static_surf_dir(self, content_filter: Optional[List[SumoContent]] = None) -> StaticSurfaceDirectory:
"""
Get a directory of surface names and attributes for static surfaces.
These are the non-observed surfaces that do NOT have time stamps
"""
timer = PerfTimer()

LOGGER.debug("Getting data for static surface directory...")

def get_surface_directory(self) -> List[SurfaceMeta]:
case = self._get_my_sumo_case_obj()

filter_no_time_data = TimeFilter(TimeType.NONE)
surface_collection: SurfaceCollection = case.surfaces.filter(
iteration=self._iteration_name,
aggregation=False,
time=filter_no_time_data,
realization=0,
)

names = sorted(surface_collection.names)
attributes = sorted(surface_collection.tagnames)
available_contents = list(set(surf["data"]["content"] for surf in surface_collection))

LOGGER.debug(f"available surface contents: {available_contents}")

if content_filter is not None:
if not any(SumoContent.has(content) for content in content_filter):
raise ValueError(f"Invalid content filter: {content_filter}")
surfaces_with_filtered_content = [
surf for surf in surface_collection if surf["data"]["content"] in content_filter
]

names = sorted(list(set(surf.name for surf in surfaces_with_filtered_content)))
attributes = sorted(list(set(surf.tagname for surf in surfaces_with_filtered_content)))

else:
names = sorted(surface_collection.names)
attributes = sorted(surface_collection.tagnames)

LOGGER.debug(
f"Build valid name/attribute combinations for static surface directory "
f"(num names={len(names)}, num attributes={len(attributes)})..."
)

valid_attributes_for_name: List[List[int]] = []

for name in names:
filtered_coll = surface_collection.filter(name=name)
filtered_attributes = [tagname for tagname in filtered_coll.tagnames if tagname in attributes]
attribute_indices: List[int] = []
for attr in filtered_attributes:
attr_idx = attributes.index(attr)
attribute_indices.append(attr_idx)

valid_attributes_for_name.append(attribute_indices)

surf_dir = StaticSurfaceDirectory(
names=names,
attributes=attributes,
valid_attributes_for_name=valid_attributes_for_name,
)

LOGGER.debug(f"Downloaded and built static surface directory in: {timer.elapsed_ms():}ms")

return surf_dir
surfs: List[SurfaceMeta] = []
for s in surface_collection:
name = s["data"]["name"]
tagname = s["data"]["tagname"]
t_start = s["data"].get("time", {}).get("t0", {}).get("value", None)
t_end = s["data"].get("time", {}).get("t1", {}).get("value", None)
content = s["data"]["content"]
is_observation = s["data"]["is_observation"]
is_stratigraphic = s["data"]["stratigraphic"]
zmin = s["data"]["bbox"]["zmin"]
zmax = s["data"]["bbox"]["zmax"]

surfs.append(
SurfaceMeta(
name=name,
tagname=tagname,
t_start=t_start,
t_end=t_end,
content=content,
is_observation=is_observation,
is_stratigraphic=is_stratigraphic,
zmin=zmin,
zmax=zmax,
)
)
return surfs

def get_dynamic_surf(
self, real_num: int, name: str, attribute: str, time_or_interval_str: str
Expand Down
30 changes: 11 additions & 19 deletions backend/src/services/sumo_access/surface_types.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
from __future__ import annotations

from typing import List
from typing import Optional

from pydantic import BaseModel


class DynamicSurfaceDirectory(BaseModel):
names: List[str]
attributes: List[str]
date_strings: List[str]

@classmethod
def create_empty(cls) -> DynamicSurfaceDirectory:
return cls(attributes=[], names=[], date_strings=[])


class StaticSurfaceDirectory(BaseModel):
names: List[str]
attributes: List[str]
valid_attributes_for_name: List[List[int]]

@classmethod
def create_empty(cls) -> StaticSurfaceDirectory:
return cls(attributes=[], names=[])
class SurfaceMeta(BaseModel):
name: str
tagname: str
t_start: Optional[str]
t_end: Optional[str]
content: str
is_observation: bool
is_stratigraphic: bool
zmin: float
zmax: float
4 changes: 1 addition & 3 deletions frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export type { B64EncodedNumpyArray as B64EncodedNumpyArray_api } from './models/
export type { Body_get_realizations_response as Body_get_realizations_response_api } from './models/Body_get_realizations_response';
export type { CaseInfo as CaseInfo_api } from './models/CaseInfo';
export type { Completions as Completions_api } from './models/Completions';
export type { DynamicSurfaceDirectory as DynamicSurfaceDirectory_api } from './models/DynamicSurfaceDirectory';
export type { EnsembleDetails as EnsembleDetails_api } from './models/EnsembleDetails';
export type { EnsembleInfo as EnsembleInfo_api } from './models/EnsembleInfo';
export type { EnsembleParameter as EnsembleParameter_api } from './models/EnsembleParameter';
Expand All @@ -31,11 +30,10 @@ export type { InplaceVolumetricsTableMetaData as InplaceVolumetricsTableMetaData
export type { PolygonData as PolygonData_api } from './models/PolygonData';
export type { PvtData as PvtData_api } from './models/PvtData';
export { SensitivityType as SensitivityType_api } from './models/SensitivityType';
export type { StaticSurfaceDirectory as StaticSurfaceDirectory_api } from './models/StaticSurfaceDirectory';
export { StatisticFunction as StatisticFunction_api } from './models/StatisticFunction';
export type { StatisticValueObject as StatisticValueObject_api } from './models/StatisticValueObject';
export { SumoContent as SumoContent_api } from './models/SumoContent';
export type { SurfaceData as SurfaceData_api } from './models/SurfaceData';
export type { SurfaceMeta as SurfaceMeta_api } from './models/SurfaceMeta';
export type { SurfacePolygonDirectory as SurfacePolygonDirectory_api } from './models/SurfacePolygonDirectory';
export { SurfaceStatisticFunction as SurfaceStatisticFunction_api } from './models/SurfaceStatisticFunction';
export type { UserInfo as UserInfo_api } from './models/UserInfo';
Expand Down
10 changes: 0 additions & 10 deletions frontend/src/api/models/DynamicSurfaceDirectory.ts

This file was deleted.

10 changes: 0 additions & 10 deletions frontend/src/api/models/StaticSurfaceDirectory.ts

This file was deleted.

13 changes: 0 additions & 13 deletions frontend/src/api/models/SumoContent.ts

This file was deleted.

16 changes: 16 additions & 0 deletions frontend/src/api/models/SurfaceMeta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */

export type SurfaceMeta = {
name: string;
tagname: string;
t_start?: string;
t_end?: string;
content: string;
is_observation: boolean;
is_stratigraphic: boolean;
zmin: number;
zmax: number;
};

Loading

0 comments on commit 285606e

Please sign in to comment.