Skip to content

Commit

Permalink
Fetch and store ensemble metadata in workbench (#178)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigurdp authored Jun 19, 2023
1 parent 29f0092 commit 76bc5cf
Show file tree
Hide file tree
Showing 52 changed files with 876 additions and 494 deletions.
52 changes: 32 additions & 20 deletions backend/src/backend/primary/routers/explore.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,43 @@
from pydantic import BaseModel

from src.services.sumo_access.sumo_explore import SumoExplore
from src.services.sumo_access.iteration_inspector import IterationInspector
from src.services.utils.authenticated_user import AuthenticatedUser
from src.backend.auth.auth_helper import AuthHelper

router = APIRouter()


class Field(BaseModel):
class FieldInfo(BaseModel):
field_identifier: str


class Case(BaseModel):
class CaseInfo(BaseModel):
uuid: str
name: str


class Ensemble(BaseModel):
class EnsembleInfo(BaseModel):
name: str
realization_count: int


class EnsembleDetails(BaseModel):
name: str
case_name: str
case_uuid: str
realizations: List[int]


@router.get("/fields")
def get_fields() -> List[Field]:
def get_fields() -> List[FieldInfo]:
"""
Get list of fields
"""
ret_arr = [
Field(field_identifier="DROGON"),
Field(field_identifier="JOHAN SVERDRUP"),
Field(field_identifier="DUMMY_FIELD"),
FieldInfo(field_identifier="DROGON"),
FieldInfo(field_identifier="JOHAN SVERDRUP"),
FieldInfo(field_identifier="DUMMY_FIELD"),
]
return ret_arr

Expand All @@ -40,7 +49,7 @@ def get_fields() -> List[Field]:
def get_cases(
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
field_identifier: str = Query(description="Field identifier"),
) -> List[Case]:
) -> List[CaseInfo]:
"""Get list of cases for specified field"""
print(authenticated_user.get_sumo_access_token())
sumo_discovery = SumoExplore(authenticated_user.get_sumo_access_token())
Expand All @@ -51,15 +60,15 @@ def get_cases(
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Sumo Explorer + Drogon + SMRY data is still a work in progress!
# Present the single DROGON case that we know to be good as the first item, also prefixing it with "GOOD"
ret_arr: List[Case] = []
ret_arr: List[CaseInfo] = []
if field_identifier == "DROGON":
for case_info in case_info_arr:
if case_info.uuid == "10f41041-2c17-4374-a735-bb0de62e29dc":
ret_arr.insert(0, Case(uuid=case_info.uuid, name=f"GOOD -- {case_info.name}"))
ret_arr.insert(0, CaseInfo(uuid=case_info.uuid, name=f"GOOD -- {case_info.name}"))
else:
ret_arr.append(Case(uuid=case_info.uuid, name=case_info.name))
ret_arr.append(CaseInfo(uuid=case_info.uuid, name=case_info.name))
else:
ret_arr = [Case(uuid=ci.uuid, name=ci.name) for ci in case_info_arr]
ret_arr = [CaseInfo(uuid=ci.uuid, name=ci.name) for ci in case_info_arr]

return ret_arr

Expand All @@ -68,22 +77,25 @@ def get_cases(
def get_ensembles(
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Path(description="Sumo case uuid"),
) -> List[Ensemble]:
) -> List[EnsembleInfo]:
"""Get list of ensembles for a case"""
sumo_discovery = SumoExplore(authenticated_user.get_sumo_access_token())
iteration_info_arr = sumo_discovery.get_iterations(case_uuid=case_uuid)

print(iteration_info_arr)

return [Ensemble(name=it.name) for it in iteration_info_arr]
return [EnsembleInfo(name=it.name, realization_count=it.realization_count) for it in iteration_info_arr]


@router.get("/cases/{case_uuid}/ensembles/{ensemble_name}/realizations")
def get_realizations(
@router.get("/cases/{case_uuid}/ensembles/{ensemble_name}")
def get_ensemble_details(
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Path(description="Sumo case uuid"),
ensemble_name: str = Path(description="Ensemble name"),
) -> Sequence[int]:
"""Get list of realizations for an ensemble"""
sumo_discovery = SumoExplore(authenticated_user.get_sumo_access_token())
return sumo_discovery.get_realizations(case_uuid=case_uuid, ensemble_name=ensemble_name)
) -> EnsembleDetails:
"""Get more detailed information for an ensemble"""
iteration_inspector = IterationInspector(authenticated_user.get_sumo_access_token(), case_uuid, ensemble_name)
case_name = iteration_inspector.get_case_name()
realizations = iteration_inspector.get_realizations()

return EnsembleDetails(name=ensemble_name, case_name=case_name, case_uuid=case_uuid, realizations=realizations)
8 changes: 4 additions & 4 deletions backend/src/backend/primary/routers/parameters/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@


@router.get("/parameter_names_and_description/")
async def get_parameter_names_and_description(
def get_parameter_names_and_description(
# fmt:off
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Query(description="Sumo case uuid"),
Expand Down Expand Up @@ -51,7 +51,7 @@ async def get_parameter_names_and_description(


@router.get("/parameter/")
async def get_parameter(
def get_parameter(
# fmt:off
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Query(description="Sumo case uuid"),
Expand All @@ -70,7 +70,7 @@ async def get_parameter(


@router.get("/is_sensitivity_run/")
async def is_sensitivity_run(
def is_sensitivity_run(
# fmt:off
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Query(description="Sumo case uuid"),
Expand All @@ -84,7 +84,7 @@ async def is_sensitivity_run(


@router.get("/sensitivities/")
async def get_sensitivities(
def get_sensitivities(
# fmt:off
authenticated_user: AuthenticatedUser = Depends(AuthHelper.get_authenticated_user),
case_uuid: str = Query(description="Sumo case uuid"),
Expand Down
28 changes: 28 additions & 0 deletions backend/src/services/sumo_access/iteration_inspector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Sequence
from fmu.sumo.explorer.explorer import CaseCollection, Case, SumoClient

from ._helpers import create_sumo_client_instance


class IterationInspector:
"""
Class for inspecting and retrieving iteration (ensemble) information
"""

def __init__(self, access_token: str, case_uuid: str, iteration_name: str):
sumo_client: SumoClient = create_sumo_client_instance(access_token)
case_collection = CaseCollection(sumo_client).filter(uuid=case_uuid)
if len(case_collection) != 1:
raise ValueError(f"None or multiple sumo cases found {case_uuid=}")

self._case: Case = case_collection[0]
self._iteration_name: str = iteration_name

def get_case_name(self) -> str:
"""Get name of case to which this iteration belongs"""
return self._case.name

def get_realizations(self) -> Sequence[int]:
"""Get list of realizations for this iteration"""
realizations = self._case.get_realizations(self._iteration_name)
return sorted([int(real) for real in realizations])
16 changes: 6 additions & 10 deletions backend/src/services/sumo_access/sumo_explore.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import List, Sequence
from typing import List
from pydantic import BaseModel

from fmu.sumo.explorer.explorer import CaseCollection, SumoClient
from fmu.sumo.explorer.explorer import CaseCollection, Case, SumoClient

from ._helpers import create_sumo_client_instance

Expand All @@ -13,6 +13,7 @@ class CaseInfo(BaseModel):

class IterationInfo(BaseModel):
name: str
realization_count: int


class SumoExplore:
Expand All @@ -36,18 +37,13 @@ def get_iterations(self, case_uuid: str) -> List[IterationInfo]:
if len(case_collection) != 1:
raise ValueError(f"Sumo case not found {case_uuid=}")

case = case_collection[0]
case: Case = case_collection[0]
iter_info_arr: List[IterationInfo] = [
IterationInfo(name=iteration.get("name")) for iteration in case.iterations
IterationInfo(name=iteration.get("name"), realization_count=iteration.get("realizations"))
for iteration in case.iterations
]

# Sort on iteration name before returning
iter_info_arr.sort(key=lambda iter_info: iter_info.name)

return iter_info_arr

def get_realizations(self, case_uuid: str, ensemble_name: str) -> Sequence[int]:
"""Get list of realizations for a case and ensemble"""
case_collection = CaseCollection(self._sumo_client).filter(uuid=case_uuid)
realizations = case_collection[0].get_realizations(ensemble_name)
return sorted([int(real) for real in realizations])
7 changes: 4 additions & 3 deletions frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ export type { OpenAPIConfig } from './core/OpenAPI';

export type { B64EncodedNumpyArray } from './models/B64EncodedNumpyArray';
export type { Body_get_realizations_response } from './models/Body_get_realizations_response';
export type { Case } from './models/Case';
export type { CaseInfo } from './models/CaseInfo';
export type { DynamicSurfaceDirectory } from './models/DynamicSurfaceDirectory';
export type { Ensemble } from './models/Ensemble';
export type { EnsembleCorrelations } from './models/EnsembleCorrelations';
export type { EnsembleDetails } from './models/EnsembleDetails';
export type { EnsembleInfo } from './models/EnsembleInfo';
export type { EnsembleParameter } from './models/EnsembleParameter';
export type { EnsembleParameterDescription } from './models/EnsembleParameterDescription';
export type { EnsembleScalarResponse } from './models/EnsembleScalarResponse';
export type { EnsembleSensitivity } from './models/EnsembleSensitivity';
export type { EnsembleSensitivityCase } from './models/EnsembleSensitivityCase';
export type { Field } from './models/Field';
export type { FieldInfo } from './models/FieldInfo';
export { Frequency } from './models/Frequency';
export type { GridIntersection } from './models/GridIntersection';
export type { GridSurface } from './models/GridSurface';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* tslint:disable */
/* eslint-disable */

export type Case = {
export type CaseInfo = {
uuid: string;
name: string;
};
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/api/models/EnsembleDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */

export type EnsembleDetails = {
name: string;
case_name: string;
case_uuid: string;
realizations: Array<number>;
};

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
/* tslint:disable */
/* eslint-disable */

export type Ensemble = {
export type EnsembleInfo = {
name: string;
realization_count: number;
};

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* tslint:disable */
/* eslint-disable */

export type Field = {
export type FieldInfo = {
field_identifier: string;
};

31 changes: 16 additions & 15 deletions frontend/src/api/services/ExploreService.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { Case } from '../models/Case';
import type { Ensemble } from '../models/Ensemble';
import type { Field } from '../models/Field';
import type { CaseInfo } from '../models/CaseInfo';
import type { EnsembleDetails } from '../models/EnsembleDetails';
import type { EnsembleInfo } from '../models/EnsembleInfo';
import type { FieldInfo } from '../models/FieldInfo';

import type { CancelablePromise } from '../core/CancelablePromise';
import type { BaseHttpRequest } from '../core/BaseHttpRequest';
Expand All @@ -15,10 +16,10 @@ export class ExploreService {
/**
* Get Fields
* Get list of fields
* @returns Field Successful Response
* @returns FieldInfo Successful Response
* @throws ApiError
*/
public getFields(): CancelablePromise<Array<Field>> {
public getFields(): CancelablePromise<Array<FieldInfo>> {
return this.httpRequest.request({
method: 'GET',
url: '/fields',
Expand All @@ -29,12 +30,12 @@ export class ExploreService {
* Get Cases
* Get list of cases for specified field
* @param fieldIdentifier Field identifier
* @returns Case Successful Response
* @returns CaseInfo Successful Response
* @throws ApiError
*/
public getCases(
fieldIdentifier: string,
): CancelablePromise<Array<Case>> {
): CancelablePromise<Array<CaseInfo>> {
return this.httpRequest.request({
method: 'GET',
url: '/cases',
Expand All @@ -51,12 +52,12 @@ export class ExploreService {
* Get Ensembles
* Get list of ensembles for a case
* @param caseUuid Sumo case uuid
* @returns Ensemble Successful Response
* @returns EnsembleInfo Successful Response
* @throws ApiError
*/
public getEnsembles(
caseUuid: string,
): CancelablePromise<Array<Ensemble>> {
): CancelablePromise<Array<EnsembleInfo>> {
return this.httpRequest.request({
method: 'GET',
url: '/cases/{case_uuid}/ensembles',
Expand All @@ -70,20 +71,20 @@ export class ExploreService {
}

/**
* Get Realizations
* Get list of realizations for an ensemble
* Get Ensemble Details
* Get more detailed information for an ensemble
* @param caseUuid Sumo case uuid
* @param ensembleName Ensemble name
* @returns number Successful Response
* @returns EnsembleDetails Successful Response
* @throws ApiError
*/
public getRealizations(
public getEnsembleDetails(
caseUuid: string,
ensembleName: string,
): CancelablePromise<Array<number>> {
): CancelablePromise<EnsembleDetails> {
return this.httpRequest.request({
method: 'GET',
url: '/cases/{case_uuid}/ensembles/{ensemble_name}/realizations',
url: '/cases/{case_uuid}/ensembles/{ensemble_name}',
path: {
'case_uuid': caseUuid,
'ensemble_name': ensembleName,
Expand Down
Loading

0 comments on commit 76bc5cf

Please sign in to comment.