High-level API
Setup
Meshes
Reservoir
JutulDarcy.reservoir_domain — Functionreservoir_domain(g; permeability = convert_to_si(0.1, :darcy), porosity = 0.1, kwarg...)Set up a DataDomain instance for given mesh or other representation g. permeability and porosity are then added to the domain. If scalars are passed, they are expanded to cover all cells. Arrays are asserted to match all cells. Permeability is either one value per cell (diagonal scalar), one value per dimension given in each row (for a diagonal tensor) or a vector that represents a compact full tensor representation (6 elements in 3D, 3 in 2D).
Default data and their values
| Name | Explanation | Unit | Default |
|---|---|---|---|
permeability | Rock ability to conduct fluid flow | $m^2$ | 100 mD |
porosity | Rock void fraction open to flow (0 to 1) | - | 0.3 |
rock_density | Mass density of rock | $kg^3/m^3$ | 2000.0 |
rock_heat_capacity | Specific heat capacity of rock | $J/(kg K)$ | 900.0 |
rock_thermal_conductivity | Heat conductivity of rock | $W/m K$ | 3.0 |
fluid_thermal_conductivity | Heat conductivity of fluid phases | $W/m K$ | 0.6 |
component_heat_capacity | Specific heat capacity of fluid components | $J/(kg K)$ | 4184.0 |
Note that the default values are taken to be roughly those of water for fluid phases and sandstone for those of rock. Choice of values can severely impact your simulation results - take care to check the values that your physical system makes use of!
reservoir_domain(m::Union{SimulationModel, MultiModel})Get reservoir domain embedded in model.
reservoir_domain(case::JutulCase)Get reservoir domain from a reservoir simulation case.
Wells
JutulDarcy.setup_well — Functionsetup_well(D::DataDomain, reservoir_cells; skin = 0.0, Kh = nothing, radius = 0.1, dir = :z)Set up a well in reservoir_cells with given skin factor and radius. The order of cells matter as it is treated as a trajectory.
JutulDarcy.setup_vertical_well — Functionsetup_vertical_well(D::DataDomain, i, j; <kwarg>)Set up a vertical well with a DataDomain input that represents the porous medium / reservoir where the wells it to be placed.
setup_vertical_well(g, K, i, j; heel = 1, toe = grid_dims_ijk(g)[3], kwarg...)Set up a vertical well for given grid g and permeability K at logical indices i, j perforating all cells starting at k-logical index heel to toe.
Model
JutulDarcy.setup_reservoir_model — Functionsetup_reservoir_model(reservoir, system; wells = [], <keyword arguments>)
setup_reservoir_model(reservoir, system; wells = [], context = DefaultContext(), reservoir_context = nothing, backend = :csc, <keyword arguments>)Set up a reservoir MultiModel for a given reservoir DataDomain typically set up from reservoir_domain and an optional vector of wells that are created using setup_vertical_well and setup_well.
The routine automatically sets up a facility and couples the wells with the reservoir and that facility.
Initial state
JutulDarcy.setup_reservoir_state — Functionsetup_reservoir_state(model, <keyword arguments>)
# Ex: For immiscible two-phase
setup_reservoir_state(model, Pressure = 1e5, Saturations = [0.2, 0.8])Convenience constructor that initializes a state for a MultiModel set up using setup_reservoir_model. The main convenience over setup_state is only the reservoir initialization values need be provided: wells are automatically initialized from the connected reservoir cells.
As an alternative to passing keyword arguments, a Dict{Symbol, Any} instance can be sent in as a second, non-keyword argument.
Why is initialization needed?
Simple initialization
Hydrostatic equilibriation
Simulation
JutulDarcy.simulate_reservoir — Functionsimulate_reservoir(state0, model, dt;
parameters = setup_parameters(model),
restart = false,
forces = setup_forces(model),
kwarg...
)
simulate_reservoir(case;
kwarg...
)Convenience function for simulating a reservoir model. This function internally calls setup_reservoir_simulator, simulates the problem and returns a ReservoirSimResult. Keyword arguments are passed onto setup_reservoir_simulator and are documented in that function.
You can optionally unpack this result into the most typical desired outputs:
wellsols, states = simulate_reservoir(...)
where wellsols contains the well results and states the reservoir results (pressure, saturations and so on, in each cell of the reservoir domain).
Examples
You can restart/resume simulations by both providing the output_path argument and the restart argument:
# Automatically restart from last solved step and returning the outputs if the simulation was already solved.
result = simulate_reservoir(state0, model, dt, output_path = "/some/path", restart = true)
# Restart from step 5
result = simulate_reservoir(state0, model, dt, output_path = "/some/path", restart = 5)
# Start from the beginning (default)
result = simulate_reservoir(state0, model, dt, output_path = "/some/path", restart = false)JutulDarcy.setup_reservoir_simulator — Functionsetup_reservoir_simulator(models, initializer, parameters = nothing; <keyword arguments>)Arguments
models: either a single model or a Dict with the key :Reservoir for multimodelsinitializer: used to setup state0, must be compatible withmodelparameters: initialized parameters, must be compatible withmodelif provided
Keyword arguments
split_wells: Add facility model to each well (needed for domain decomposition and MPI solves)assemble_wells_together: Option to split wells into multiple sparse matrices (false argument experimental)specialize=false: use deep specialization of storage for faster execution, but significantly more compile time
Additional keyword arguments are documented in the version of this function that uses JutulCase as the input.
setup_reservoir_simulator(case::JutulCase; <keyword arguments>)Keyword arguments
Linear solver options
linear_solver=:bicgstab: iterative solver to use (provided model supports it). Typical options are:bicgstabor:gmresCan alternatively pass a linear solver instance.precond=:cpr: preconditioner for iterative solver: Either :cpr or :ilu0.rtol=1e-3: relative tolerance for linear solver
Timestepping options
initial_dt=3600*24.0: initial time-step in seconds (one day by default)target_ds=Inf: target saturation change over a timestep used by timestepper.target_its=8: target number of nonlinear iterations per time stepoffset_its=1: dampening parameter for time step selector where larger values lead to more pessimistic estimates.timesteps=:auto: Set to:autoto use automatic timestepping,:nonefor no autoamtic timestepping (i.e. try to solve exact report steps)
Convergence criterions
tol_cnv=1e-3: maximum allowable point-wise error (volume-balance)tol_mb=1e-7: maximum alllowable integrated error (mass-balance)tol_cnv_well=10*tol_cnv: maximum allowable point-wise error for well node (volume-balance)tol_mb_well=1e4*tol_mb: maximum alllowable integrated error for well node (mass-balance)
Inherited keyword arguments
Additional keyword arguments come from the base Jutul simulation framework. We list a few of the most relevant entries here for convenience:
info_level =0: Output level. Set to 0 for minimal output, -1 for no output and 1 or more for increasing verbosity.output_path: Path to write output to.
Additional keyword arguments are passed onto simulator_config.