Skip to main content

Reservoir simulation with JutulDarcy in Python.

Project description

PyJutulDarcy

Python wrapper for JutulDarcy.jl, a fully differentiable reservoir simulator written in Julia. Key features:

  • Immiscible, black-oil and compositional multiphase flow
  • Geothermal simulation and simulation of CO2 sequestration
  • Can read standard input files and corner-point grids, or make your own

This package facilitates automatic installation of JutulDarcy from Python, as well as a minimal interface that allows fast simulation of .DATA files in pure Python. For more details about JutulDarcy.jl, please see the Julia Documentation. If you want to run MPI or CUDA accelerated simulations we recommend working either in Julia or the standalone compiled version.

The package also provides access to all the functions of the Julia version under jutuldarcy.jl.JutulDarcy, jutuldarcy.jl.GeoEnergyIO and jutuldarcy.jl.Jutul. These functions are directly wrapped using JuliaCall. For more details, see the JuliaCall Documentation on converting of types.

Installation

The package can be installed with pip:

pip install jutuldarcy

On first time usage of the package JuliaCall will automatically install Julia and manage all dependency packages.

Activating plotting

There is highly experimental support for 3D and 2D visualization. To enable, you can either add GLMakie to your environment manually, or run the following:

import jutuldarcy as jd
jd.install_plotting()

Note that this requires that you are running in an environment that supports plotting (OpenGL capable, i.e. not at a SSH remote without forwarding).

Examples

Copies of these examples can be found in the examples directory.

A minimal example: Running a benchmark file

import jutuldarcy as jd
# Load SPE9 dataset to disk
pth = jd.test_file_path("SPE9", "SPE9.DATA")
# Simulate the model and convert to Python dicts
res = jd.simulate_data_file(pth, convert = True)
# Get field quantities and plot
import matplotlib.pyplot as plt
fopr = res["FIELD"]["FOPR"]
days = res["DAYS"]
plt.plot(days, fopr)
plt.ylabel("Field oil production")
plt.xlabel("Days")
plt.show()
pyplot_fopr

Here, res is a standard dict containing the following fields:

  • "FIELD": Field quantities (average pressure, total water injection, etc) as numpy arrays.
  • "WELLS": Well quantities (bottom hole pressures, injection rates, production rates, etc)
  • "STATES": Reservoir states for all active cells, given as a list with a dict for each timestep. For example, res["STATES"][10]["Rs"] will give you an array of the solution gas-oil-ratio at step 10.
  • "DAYS": Array of the number of days elapsed for each step.

Optionally, if the keyword argument convert to simulate_data_file is set to False or left defaulted, the "full" output as seen in Julia will be returned, where it is possible to get access to grid geometry, model parameters, and so on.

Setting up a simulation without input file

This example is a port of the first JutulDarcy.jl documentation example. If you want to understand a bit more about what is going on, please refer to that page.

Note that only a subset of the full set of routines are available directly in the wrapper. PRs that add more wrapping functionality is welcome.

import importlib
import jutuldarcy as jd
import numpy as np
importlib.reload(jd)
# Grab some unit conversion factors
day = jd.si_unit("day")
Darcy = jd.si_unit("darcy")
kg = jd.si_unit("kilogram")
meter = jd.si_unit("meter")
bar = jd.si_unit("bar")
# Set up mesh
nx = ny = 25
nz = 10
cart_dims = (nx, ny, nz)
physical_dims = (1000.0*meter, 1000.0*meter, 100.0*meter)
g = jd.CartesianMesh(cart_dims, physical_dims)
domain = jd.reservoir_domain(g, permeability = 0.3*Darcy, porosity = 0.2)
Injector = jd.setup_vertical_well(domain, 1, 1, name = "Injector")
Producer = jd.setup_well(domain, (nx, ny, 1), name = "Producer")
# Show the properties in the domain
phases = (jd.LiquidPhase(), jd.VaporPhase())
rhoLS = 1000.0*kg/meter**3
rhoGS = 100.0*kg/meter**3
reference_densities = [rhoLS, rhoGS]
sys = jd.ImmiscibleSystem(phases, reference_densities = reference_densities)
model, parameters = jd.setup_reservoir_model(domain, sys, wells = [Injector, Producer])
# Replace dynamic functions with custom ones
c = np.array([1e-6/bar, 1e-4/bar])
density = jd.jl.ConstantCompressibilityDensities(
    p_ref = 100*bar,
    density_ref = reference_densities,
    compressibility = c
)
kr = jd.jl.BrooksCoreyRelativePermeabilities(sys, np.array([2.0, 3.0]))
jd.replace_variables(model, PhaseMassDensities = density, RelativePermeabilities = kr)
# Set the initial conditions
state0 = jd.setup_reservoir_state(model,
    Pressure = 120*bar,
    Saturations = np.array([1.0, 0.0])
)
# Set up reporting steps
nstep = 25
dt = np.repeat(365.0*day, nstep)
# Set up timestepping and well controls
pv = jd.pore_volume(model, parameters)
inj_rate = 1.5*np.sum(pv)/sum(dt)
I_ctrl = jd.setup_injector_control(inj_rate, "rate", np.array([0.0, 1.0]), density = rhoGS)
P_ctrl = jd.setup_producer_control(100*bar, "bhp")
controls = dict(Injector = I_ctrl, Producer = P_ctrl)
forces = jd.setup_reservoir_forces(model, control = controls)
result = jd.simulate_reservoir(state0, model, dt, parameters = parameters, forces = forces)

Converting to Python dict

Plotting results (experimental)

We can also plot the results if the plotting has been installed:

plt = jd.plot_reservoir(model, result.states)
jd.make_interactive()

Paper and citing

The main paper describing JutulDarcy.jl is JutulDarcy.jl - a Fully Differentiable High-Performance Reservoir Simulator Based on Automatic Differentiation:

@article{jutuldarcy_ecmor_2024,
   author = "M{\o}yner, O.",
   title = "JutulDarcy.jl - a Fully Differentiable High-Performance Reservoir Simulator Based on Automatic Differentiation", 
   year = "2024",
   volume = "2024",
   number = "1",
   pages = "1-9",
   doi = "https://doi.org/10.3997/2214-4609.202437111",
   publisher = "European Association of Geoscientists \& Engineers",
   issn = "2214-4609",
}

Contributing

Contributions that expose additional functionality is welcome.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jutuldarcy-1.1.0.tar.gz (14.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jutuldarcy-1.1.0-py3-none-any.whl (12.4 kB view details)

Uploaded Python 3

File details

Details for the file jutuldarcy-1.1.0.tar.gz.

File metadata

  • Download URL: jutuldarcy-1.1.0.tar.gz
  • Upload date:
  • Size: 14.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.12

File hashes

Hashes for jutuldarcy-1.1.0.tar.gz
Algorithm Hash digest
SHA256 3a0ccb15e1a711194e0305407dae4b0713045031ed1549e731899b6ca6cbc3f6
MD5 12c12b771e780ea0d6b00b7973a9a70b
BLAKE2b-256 2d99456e3c871abb708e2dae44b7d5ced9fc51055b5efbbe381da6258bf9a8b8

See more details on using hashes here.

File details

Details for the file jutuldarcy-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: jutuldarcy-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.12

File hashes

Hashes for jutuldarcy-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8b6caa3fc0ebe748208cbdf7c3d8a382c87ebbd4329e8b95cff01744536731a4
MD5 234f5e811e3ea2f163a069c8eacacf7b
BLAKE2b-256 597ea4cad4485811012324a1ca9378a6345b6632904472da670d1082b7ac6e67

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page