Live demo · Reservoir simulation

Flood a reservoir.
Watch it on a GPU.

GEOS, the open-source multiphysics simulator, pushes water through the channelized sands of the SPE10 benchmark while four wells produce oil. Change the injection rate, producer pressure or permeability and re-run it on an NVIDIA L4. Chalk deploys the CUDA build of GEOS behind an API from one Python file.

A five-spot waterflood, solved on the GPU

Water goes in at the centre; oil comes out at the four corners. The front races ahead along the high-permeability channels and leaves tight rock behind, which is why heterogeneity decides how much oil a flood recovers. Scrub through the recorded run, switch between saturation, pressure and the permeability that shapes them, then change the inputs and run GEOS yourself.

Recorded run
Loading the recorded run…
—
Cumulative production Oil Water
Oil produced—
Recovery—of oil in place
Water cut—
Avg pressure—
Re-run it on the GPU
Water injection
Producer pressure
Permeability
Simulated time

The recorded run is the same stream the button produces, saved from the deployed API. Production is a mass balance over GEOS's cell outputs (the producers are held at a fixed bottom-hole pressure), reported at surface conditions. The SPE10 data is the two-layer extract that ships with GEOS. Times are wall-clock for the whole run, including GEOS start-up and writing output.

How it works

An unmodified simulator, a CUDA image and a thin Python API. Chalk supplies the GPU, the endpoint and the readiness checks.

A real heterogeneous reservoir

Layers 84 and 85 of the SPE10 benchmark: channelized sands from the Upper Ness formation, with permeability spanning six orders of magnitude across 26,400 cells.

Your parameters, a new deck

The API rewrites GEOS's own SPE10 input deck: injection rate, producer pressure, a permeability multiplier, simulated time and grid resolution.

Fully implicit, on the GPU

GEOS assembles the two-phase dead-oil system with RAJA kernels on the GPU and solves each Newton step with hypre's multigrid-reduction preconditioner, also on the GPU.

Streamed as it solves

Each report step is read the moment GEOS writes it and streamed to this page: pressure and saturation maps, plus cumulative oil and water from a mass balance.

Measured wall time, GPU vs CPU
26,400 cells, 1,500 days (the recorded run)
One NVIDIA L4, on Chalk102 s
One NVIDIA H10089 s
1 CPU core116 s
4 CPU cores (MPI)35 s
8 CPU cores (MPI)22 s
422,400 cells (each cell split 4 × 4), 300 days
One NVIDIA H1001,286 s
4 CPU cores (MPI)979 s

Same deck, same GEOS commit, same answer: every run recovers 47% of the oil by day 1,500. On this case one GPU runs about as fast as one CPU core. GEOS's GPU solver uses GPU-friendly multigrid settings that need two to six times more Krylov iterations per Newton step than its CPU solver, and on grids this small that cancels out the faster iterations. The demo runs on an L4 to show a CUDA build of GEOS served from Chalk, not to claim a speedup.

Getting started

Put your simulator behind an API

GEOS has no Python wheel to pip install: it is C++ with MPI, CUDA, RAJA and hypre. The example compiles it once on top of the geosx third-party-library image, ships the binary in a slim CUDA runtime image, and deploys that image as a Chalk ScalingGroup on an L4.

The same pattern runs any batch code that needs a GPU: OpenFOAM, a molecular dynamics engine, or your in-house reservoir model. GEOS is developed by researchers at Lawrence Livermore National Laboratory, Stanford University, TotalEnergies and Chevron, and licensed under the LGPL-2.1.

GEOS-DEV/GEOS on GitHub
import json, httpx

params = {
    "injection_bbl_per_day": 400,    # water injector at the centre
    "producer_bhp_mpa": 27.58,       # four corner producers, 4,000 psi
    "perm_multiplier": 1.0,          # scale the SPE10 permeability field
    "days": 1500, "frames": 40,
}
with httpx.stream("POST", f"{URL}/api/run", json=params, timeout=None) as r:
    for line in r.iter_lines():
        msg = json.loads(line)
        if msg["type"] == "frame":
            print(f"day {msg['t_days']:6.0f}  oil {msg['oil_bbl']:9,.0f} bbl"
                  f"  recovery {msg['recovery']:.1%}  wall {msg['wall_s']:.1f}s")

# day    375  oil   110,046 bbl  recovery 29.4%  wall 60.2s
# day    750  oil   143,556 bbl  recovery 38.4%  wall 76.8s
# day   1125  oil   162,917 bbl  recovery 43.5%  wall 90.7s
# day   1500  oil   176,611 bbl  recovery 47.2%  wall 101.8s

What Chalk handles

The GPU, the image, the endpoint and the scaling, so the simulator is the only thing you maintain.

Any CUDA binary, as a service

GEOS is a C++/MPI code with a CUDA build. Chalk runs the image you give it on a GPU and puts an HTTPS endpoint in front of it.

Hardware in one argument

An L4 here; a bigger card, or a CPU build on more cores, when the model calls for it. Chalk provisions the node and schedules the replica.

Ready means ready

The replica runs a short warm-up simulation before its readiness probe passes, so traffic only reaches a GPU that has already solved a case.

Fan out the ensemble

History matching and uncertainty studies need hundreds of runs. Scale the group out and send each parameter set to its own GPU.

Python around the solver

Deck generation, output parsing and the API are about 300 lines of Python next to an unmodified simulator.

Runs in your cloud

Chalk deploys into your own AWS, GCP or Azure account, so proprietary reservoir models never leave it.

Bring your simulator

Reservoir models, CFD or seismic imaging: talk to an engineer about running your scientific codes on GPUs in your own cloud.