mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-24 22:27:55 -05:00
Add grid data from Sumo using ri-cloud-api Load Eclipse grid data (roff) from Sumo as RimReservoirGridEnsemble, one case per realization, with async fetch of grid properties per timestep. - New: RiaSumoGrid (transport), RifReaderSumoGridProperty (lazy property reader), RimReservoirGridEnsembleSumo, RimRoffCaseSumo, and a "Create Reservoir Grid Ensemble" command. - Shared grid: IJK dimensions compared before download; one RigMainGrid is reused across the ensemble when they match, each realization still parses its own ACTNUM before releasing geometry. - Rename folders: Summary/Sumo -> Summary/Cloud, RimSumoDataSource -> Cloud/ (PDM keywords unchanged, old project files still load). - UI: cloud data sources also shown in the 3D window's Data Sources dock. - Fix: realizations no longer lost on project reload; realizations missing data are now reported instead of silently skipped.
7.6 KiB
7.6 KiB
Cloud Data Architecture
How ResInsight retrieves ensemble grid and summary data from SUMO. Three tiers are involved:
SUMO itself (Equinor's cloud store for FMU results), the local ri-cloud-api service that
ResInsight launches as its own ri-cloud-api process (a separate OS process from ResInsight
itself, running a uvicorn FastAPI service), and the C++ code in ResInsight that talks to it and
turns the results into grid cases and summary ensembles.
See also cloud-service-api.md for how the Python service is installed and launched.
Overview
architecture-beta
group local(server)[ResInsight Process]
group localServer(server)[ri cloud api Process]
group sumo(cloud)[SUMO python packages]
group azure(cloud)[Azure]
service connector(server)[RiaSumoConnector] in local
service riCore(disk)[ResInsight Case and Summary Data] in local
service cloudApi(server)[uvicorn FastAPI service] in localServer
service sumoPythonWrapper(internet)[sumo python wrapper Server Auth and SAS] in sumo
service fmuSumoExplorer(database)[SUMO Explorer Search Indexed FMU Metadata] in sumo
service blobStore(disk)[Blob Storage] in azure
junction gaplocalServer
junction gapSumoPythonWrapper
junction gapFmuSumoExplorer
junction gapBlobStore
connector:R -- L:gaplocalServer
gaplocalServer:R -- L:cloudApi
cloudApi:T -- L:gapSumoPythonWrapper
gapSumoPythonWrapper:R -- L:sumoPythonWrapper
cloudApi:R -- L:gapFmuSumoExplorer
gapFmuSumoExplorer:R -- L:fmuSumoExplorer
connector:T -- B:blobStore
connector:B --> T:riCore
Components
SUMO (Equinor cloud store)
- Stores FMU (Fast Model Update) ensemble results: case/ensemble/realization metadata, grid geometry and grid property blobs (roff), summary vectors and ensemble parameters (parquet).
- Sumo core is the backend proper: it owns the ElasticSearch index (case/ensemble/realization/ object metadata and search) and exposes the API in front of it — including authentication and issuing the short-lived SAS (Shared Access Signature) tokens used to download blobs. It is written in Node.js and is self-hosted on Azure; ElasticSearch is not a separate system reached independently, it lives behind this one API.
sumo-wrapper-pythonis a thin Python wrapper around that API: it makes the Sumo API easier to call from Python and provides the basic plumbing — authentication and retry handling — without adding any FMU domain knowledge of its own.fmu-sumo'sExploreris built on top ofsumo-wrapper-python. It is an FMU-aware Python library for reading FMU results out of Sumo, offering an intuitive, domain-level interface (assets, cases, ensembles, realizations, grid/summary objects) instead of raw API/ElasticSearch calls, and is whatri-cloud-apiactually calls to look things up.- The blob bytes themselves are not served by the Sumo core API in the current solution — a
lookup returns a SAS token and a blob-store base URI, and
RiaSumoConnectordownloads the blob directly from Azure Blob Storage.fmu-sumo'sExplorerobjects can also hand back blob bytes/dataframes directly (e.g..blob,.valueson a search result), which would letri-cloud-apiserve the bytes itself instead of a SAS token — that path is not used today, but is a possible future option if there is a reason to route the data through the service rather than fetching it directly from Azure. - Authentication to SUMO is Azure AD (Entra ID) OAuth2 Authorization Code Flow, handled in
ResInsight by
RiaCloudConnector/RiaSumoConnector(opens a browser once for sign-in, then reuses the token).
ri-cloud-api (local Python service, submodule scripts/ri-cloud-api)
- A FastAPI app (
ri_cloud_api.main:app) that ResInsight starts on demand as a local subprocess (RiaCloudApiService, viauvicornon127.0.0.1:<free port>) once the user signs in. - Bridges ResInsight's simple REST calls to the SUMO client libraries:
fmu-sumo— the Explorer, an FMU-aware library for reading FMU results/metadata from Sumo (case/ensemble/realization/object search), built on top ofsumo-wrapper-python.sumo-wrapper-python— the thin Python wrapper for the Sumo API thatfmu-sumo(andri-cloud-api, where needed directly) uses underneath: authentication, retries, and SAS-token/blob-access-info retrieval.ri-cloud-core-utilsandri-cloud-services— the two workspace libraries underlibs/core_utilsandlibs/servicesthat implement the service logic on top of those.
- Routers exposed (
ri_cloud_api/primary/routers):explore(assets/cases/ensembles/ realizations),grids(grid + grid property blob ids),timeseries(summary vector blob ids, aggregated on demand),parameters(ensemble parameters),surfaces,polygons,blob_access(SAS token + blob-store base URI lookup),health(/alive). - Runs entirely on
127.0.0.1; nothing outside the local machine can reach it.
ResInsight (C++ client side)
RiaCloudApiService— starts/stops the localuvicornprocess, finds a free port, and polls/aliveuntil the service is ready.RiaSumoConnector— owns the HTTP transport (OAuth2 token, a dedicated transfer thread, blocking and async request helpers) and three data-specific delegates:RiaSumoExplore— assets, cases, ensembles, realizations.RiaSumoGrid— grid names/dimensions, grid geometry (roff), grid property blobs, sync and async batched property time steps.RiaSumoSummary— summary vector names/values, ensemble parameters, sync and async.
- Blob retrieval is always two round trips, done through the connector:
GET .../blobs/{id}/sas_token_and_blob_base_urion the localri-cloud-apiservice →{ sasToken, blobStoreBaseUri }.GET {blobStoreBaseUri}/{id}?{sasToken}directly against Azure Blob Storage → the blob bytes (roff grid/property data, or parquet summary/parameter data).
- Consumers:
RimRoffCaseSumo+RifReaderSumoGridProperty— one Sumo grid realization becomes aRimEclipseCase. The grid geometry is downloaded and parsed up front; grid properties are fetched lazily/asynchronously the first time a time step is displayed, decoded straight intoRigCaseCellResultsData(no long-lived copy of the downloaded bytes is kept).RimSummaryEnsembleSumo— a Sumo ensemble becomes aRimSummaryEnsemble. Vector data and ensemble parameters are fetched asynchronously (parquet, one blob per vector/parameter set) and decoded into the summary case's readers.
RimRoffCaseSumo (grid case)
flowchart LR
Ensemble[RimReservoirGridEnsembleSumo] --> Case[RimRoffCaseSumo]
Case -- "requests grid blob (sync)" --> Connector[RiaSumoConnector]
Connector -- "roff blobs" --> Case
Case -- "parses roff blob, creates" --> CaseData[RigEclipseCaseData]
Case -- attaches reader --> Reader[RifReaderSumoGridProperty]
Reader -- "fetches property time steps (async)" --> Connector
Reader -- registered as reader for --> Results[RigCaseCellResultsData]
CaseData --> Results
Connector -- "downloads blob (SAS token)" --> Sumo[(ri-cloud-api / Azure Blob Storage)]
RimSummaryEnsembleSumo (summary ensemble)
flowchart LR
Ensemble[RimSummaryEnsembleSumo] -- "requests vectors / parameters (async)" --> Connector[RiaSumoConnector]
Connector -- "downloads blob (SAS token)" --> Sumo[(ri-cloud-api / Azure Blob Storage)]
Connector -- parquet blobs --> Ensemble
Ensemble -- "decodes via Arrow, distributes" --> Realizations[Per-realization summary readers]
Realizations --> Plots[Summary Plots]