Skip to content

Commit

Permalink
Moved surface intersection functionality out of SurfaceAccess class (e…
Browse files Browse the repository at this point in the history
  • Loading branch information
sigurdp authored Jun 12, 2024
1 parent 2ee8203 commit c67869c
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 86 deletions.
3 changes: 2 additions & 1 deletion backend_py/primary/primary/routers/surface/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

from primary.services.smda_access.types import StratigraphicSurface
from primary.services.sumo_access.surface_types import SurfaceMeta as SumoSurfaceMeta
from primary.services.sumo_access.surface_types import XtgeoSurfaceIntersectionPolyline, XtgeoSurfaceIntersectionResult
from primary.services.utils.surface_intersect_with_polyline import XtgeoSurfaceIntersectionPolyline
from primary.services.utils.surface_intersect_with_polyline import XtgeoSurfaceIntersectionResult
from primary.services.utils.surface_to_float32 import surface_to_float32_numpy_array

from . import schemas
Expand Down
19 changes: 11 additions & 8 deletions backend_py/primary/primary/routers/surface/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from primary.services.smda_access.stratigraphy_utils import sort_stratigraphic_names_by_hierarchy
from primary.services.smda_access.mocked_drogon_smda_access import _mocked_stratigraphy_access
from primary.services.utils.statistic_function import StatisticFunction
from primary.services.utils.surface_intersect_with_polyline import intersect_surface_with_polyline
from primary.services.utils.authenticated_user import AuthenticatedUser
from primary.auth.auth_helper import AuthHelper
from primary.utils.response_perf_metrics import ResponsePerfMetrics
Expand Down Expand Up @@ -236,15 +237,17 @@ async def post_get_surface_intersection(
authenticated_user.get_sumo_access_token(), case_uuid, ensemble_name
)

intersection_polyline = converters.from_api_cumulative_length_polyline_to_xtgeo_polyline(cumulative_length_polyline)

surface_intersection = await access.get_realization_surface_intersection_async(
real_num=realization_num,
name=name,
attribute=attribute,
polyline=intersection_polyline,
time_or_interval_str=time_or_interval_str,
surface = await access.get_realization_surface_data_async(
real_num=realization_num, name=name, attribute=attribute, time_or_interval_str=time_or_interval_str
)
if surface is None:
raise HTTPException(status_code=404, detail="Surface '{name}' not found")

# Ensure name is applied
surface.name = name

intersection_polyline = converters.from_api_cumulative_length_polyline_to_xtgeo_polyline(cumulative_length_polyline)
surface_intersection = intersect_surface_with_polyline(surface, intersection_polyline)

surface_intersection_response = converters.to_api_surface_intersection(surface_intersection)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing import List, Optional

import xtgeo
import numpy as np

from fmu.sumo.explorer import TimeFilter, TimeType
from fmu.sumo.explorer.objects import Case, SurfaceCollection, Surface
Expand All @@ -12,7 +11,7 @@
from primary.services.utils.statistic_function import StatisticFunction

from ._helpers import create_sumo_client, create_sumo_case_async
from .surface_types import SurfaceMeta, XtgeoSurfaceIntersectionResult, XtgeoSurfaceIntersectionPolyline
from .surface_types import SurfaceMeta
from .generic_types import SumoContent


Expand Down Expand Up @@ -82,34 +81,6 @@ async def get_surface_directory_async(self) -> List[SurfaceMeta]:

return surfs

async def get_realization_surface_intersection_async(
self,
real_num: int,
name: str,
attribute: str,
polyline: XtgeoSurfaceIntersectionPolyline,
time_or_interval_str: Optional[str] = None,
) -> xtgeo.RegularSurface:
"""
Get intersection of realization surface for requested surface name
"""
surface = await self.get_realization_surface_data_async(
real_num=real_num, name=name, attribute=attribute, time_or_interval_str=time_or_interval_str
)

if surface is None:
raise ValueError(f'Surface "{name}" not found in sumo')

# Ensure name is applied
surface.name = name

# The input fencespec is a 2D numpy where each row is X, Y, Z, HLEN,
# where X, Y are UTM coordinates, Z is depth/time, and HLEN is a
# length along the fence.
xtgeo_fencespec = np.array([polyline.X, polyline.Y, polyline.Z, polyline.HLEN]).T

return _make_intersection(surface, xtgeo_fencespec)

async def get_realization_surface_data_async(
self, real_num: int, name: str, attribute: str, time_or_interval_str: Optional[str] = None
) -> Optional[xtgeo.RegularSurface]:
Expand Down Expand Up @@ -276,13 +247,3 @@ async def _compute_statistical_surface_async(
raise ValueError("Unhandled statistic function")

return xtgeo_surf


def _make_intersection(surface: xtgeo.RegularSurface, xtgeo_fencespec: np.ndarray) -> XtgeoSurfaceIntersectionResult:
line = surface.get_randomline(xtgeo_fencespec)
intersection = XtgeoSurfaceIntersectionResult(
name=f"{surface.name}",
distance=line[:, 0].tolist(),
zval=line[:, 1].tolist(),
)
return intersection
40 changes: 3 additions & 37 deletions backend_py/primary/primary/services/sumo_access/surface_types.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,13 @@
from __future__ import annotations

from typing import List, Optional

from pydantic import BaseModel
from .generic_types import SumoContent


class SurfaceMeta(BaseModel):
name: str
tagname: str
iso_date_or_interval: Optional[str] = None
iso_date_or_interval: str | None = None
content: SumoContent
is_observation: bool
is_stratigraphic: bool
zmin: Optional[float] = None
zmax: Optional[float] = None


class XtgeoSurfaceIntersectionPolyline(BaseModel):
"""
Type definition for surface intersection polyline data needed as `fencespec` argument
for the xtgeo.get_randomline() function
The polyline is defined by the `X`, `Y`, `Z` and `HLEN` fields, and is provided to
the `get_randomline()` function as a list of `XtgeoSurfaceIntersectionPolyline` objects
"""

X: List[float]
Y: List[float]
Z: List[float]
HLEN: List[float]


class XtgeoSurfaceIntersectionResult(BaseModel):
"""
Type definition for surface intersection data from xtgeo.get_randomline() function
The `name` field is in addition to the fields returned by the `get_randomline()` function
`zval` are the z values of the intersection points (depth values for each (x,y) point in polyline.
`dist` are the distance at each z value (accumulated).
"""

name: str
distance: List[float]
zval: List[float]
zmin: float | None = None
zmax: float | None = None
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from pydantic import BaseModel
import xtgeo
import numpy as np


class XtgeoSurfaceIntersectionPolyline(BaseModel):
"""
Type definition for surface intersection polyline data needed as `fencespec` argument
for the xtgeo.get_randomline() function
The polyline is defined by the `X`, `Y`, `Z` and `HLEN` fields, and is provided to
the `get_randomline()` function as a list of `XtgeoSurfaceIntersectionPolyline` objects
"""

X: list[float]
Y: list[float]
Z: list[float]
HLEN: list[float]


class XtgeoSurfaceIntersectionResult(BaseModel):
"""
Type definition for surface intersection data from xtgeo.get_randomline() function
The `name` field is in addition to the fields returned by the `get_randomline()` function
`zval` are the z values of the intersection points (depth values for each (x,y) point in polyline.
`dist` are the distance at each z value (accumulated).
"""

name: str
distance: list[float]
zval: list[float]


def intersect_surface_with_polyline(
surface: xtgeo.RegularSurface,
polyline: XtgeoSurfaceIntersectionPolyline,
) -> XtgeoSurfaceIntersectionResult:
"""
Get intersection of realization surface for requested surface name
"""
# The input fencespec is a 2D numpy where each row is X, Y, Z, HLEN,
# where X, Y are UTM coordinates, Z is depth/time, and HLEN is a
# length along the fence.
xtgeo_fencespec = np.array([polyline.X, polyline.Y, polyline.Z, polyline.HLEN]).T

line = surface.get_randomline(xtgeo_fencespec)

intersection = XtgeoSurfaceIntersectionResult(
name=f"{surface.name}",
distance=line[:, 0].tolist(),
zval=line[:, 1].tolist(),
)

return intersection

0 comments on commit c67869c

Please sign in to comment.