0% found this document useful (0 votes)
186 views185 pages

Intro MRST

The document provides an introduction to the MATLAB Reservoir Simulation Toolbox (MRST), an open-source toolbox for reservoir modelling developed by SINTEF Digital. MRST is used widely in academia and industry and has over 10,000 unique downloads. It serves as a flexible toolbox for experimental programming and rapid prototyping of reservoir simulators and models. The toolbox is organized with modules ranging from fast diagnostics and proxies to full reservoir simulations.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
186 views185 pages

Intro MRST

The document provides an introduction to the MATLAB Reservoir Simulation Toolbox (MRST), an open-source toolbox for reservoir modelling developed by SINTEF Digital. MRST is used widely in academia and industry and has over 10,000 unique downloads. It serves as a flexible toolbox for experimental programming and rapid prototyping of reservoir simulators and models. The toolbox is organized with modules ranging from fast diagnostics and proxies to full reservoir simulations.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 185

Introduction to the MATLAB Reservoir Simulation

Toolbox (MRST)

Knut–Andreas Lie

Department of Mathematics and Cybernetics, SINTEF Digital/


Department of Mathematical Sciences, NTNU, Norway

Multiscale Methods Summer School


June 26–29, 2017, Hasselt, Belgium
Outline

1 Introduction

2 Getting started with MRST

3 Grids and petrophysical data

4 Incompressible flow

5 Multiphase flow

6 Compressible flow

7 The AD-OO framework in MRST

1 / 117
The MATLAB Reservoir Simulation Toolbox

Open-source toolbox for reservoir modelling,


developed by SINTEF Digital and used in most
of our research
Wide international user base:
academic institutions, oil and service
companies
USA, Norway, China, Brazil, United
Kingdom, Iran, Germany, Netherlands,
France, Canada, . . .
http://www.sintef.no/MRST
10 000+ unique downloads since 2013

Used in publications:
24 PhD theses and 63 master theses
110+ journal/proceedings papers by authors outside our group

2 / 117
Toolbox for experimental programming

Flexible simulators, easy to extend with new functionality, scaling with


accuracy requirement and computational budget

seconds minutes hours

Diagnostics/proxies Model reduction Full simulation

Flow diagnostics/volumetrics Grid coarsening Black-oil, EOR, thermal,


Flow-based upscaling compositional, geomechanics
Physics-based proxies
Multiscale methods Grids and discretizations
Fast optimization
Model-reduction techniques Nonlinear/linear solvers
Spill-point analysis
Vertical-equilibrium models Rapid prototyping
Adjoint formulations and
(closed-loop) optimization

3 / 117
Why in MATLAB?

Prototyping in a scripting language is much less time-consuming than in


traditional compiled languages (C, C++, Fortran, . . . )
Explore alternative algorithms/implementations close to mathematics
Gradually replace individual (or bottleneck) operations with
accelerated editions callable from MATLAB
Direct access to MATLAB environment and prototype whilst
developing replacement components
MATLAB/Octave is widely used in academic institutions

If we were to start all over, we might as well have chosen Python

4 / 117
How the software is organized . . .
fully implicit

es
flow diagnostics discretizations

ul
od
m
on
d-
Ad

grid coarsening multiscale methods

2
MRST core cells.faces = faces.nodes = faces.neighbors =
1 10 1 1 0 2
6
1 8 1 2 2 3
6 1 7 2 1 3 5
5 6 2 1 2 3 5 0
9 2 2 3 1 6 2
2 5 3 4 0 6
4 12 3 3 4 1 1 3
3 3 7 4 7 4 1
3 2 5 2 6 4
8
2 4 8 5 3 1 8
1 5 4 12 6 2 8 5
1 7 4 9 6 6 4 7
upscaling 2
7
10
14 5
5
5 11
3
4
7
7
8
3
4
3
7
0
8
7 co2lab
3 6 9 8 5
8 13 6 6 9 3
Original permeability Upscaled (x−direction) Upscaled (y−direction) 4 6 5 9 6
7 13 10 4
3 11 7 14 10 5 CO2 saturation
5 : : : : at 500 years 12%
16%
1 4 7
56%
12%

3%
Residual (traps)
Residual
Residual (plume)
Injected volume: Movable (traps)
2.185e+07 m3 Movable (plume)
50 Original Height of CO2−column x 10
7 Leaked
Upscaled (x)
14
40 2
12

30 10 1.5

8
20 1
6

4
10 0.5
2

0 0 0
−1.5 −1 −0.5 0 0.5 1 1.5 2 2.5 0 50 100 150 200 250 300 350 400 450 500

input decks
visualization

... ...

5 / 117
. . . core and add-on modules

The core module provides basic data structures and utility functions.
Add-on modules offer:
discretizations and solvers
simulators for incompressible and compressible flow
workflow tools such as coarsening, upscaling, flow diagnostics,
visualization, etc
special models like geomechanics and fractured reservoirs
analysis of large-scale CO2 storage in saline aquifers

6 / 117
Two different programming paradigms

incomp – sequential solvers for incompressible flow


Have been part of MRST since the start
Uses imperative programming: functions that operate mainly on
vectors, (sparse) matrices, structures, and a few cell arrays
Explicit assembly and linearization of flow equations

AD-OO – (fully) implicit solvers for compressible flow


More recent addition to MRST
Object-oriented framework for building simulators
Assembly and linearization performed implicitly by the use of
automatic differentiation

Both families rely on functionality from mrst-core

7 / 117
Quick overview of functionality

Basic functionality in MRST:


grid structure and grid factory routines
petrophysical data and incompressible fluid models
physical units and conversion routines between SI
and common field units
routines for setting and manipulating boundary
conditions, sources/sinks, and well models
reservoir state (pressure, fluxes, saturations,. . . )
visualization routines for cell and face data

8 / 117
Quick overview of functionality
Grid generation and coarsening:
MRST core upr coarsegrid agglom

libgeometry opm gridprocessing triangle

MRST offers a wide variety of grid factory routines and input from Eclipse, upr
generates 2D and 3D Voronoi grids with cell and face constraints
coarsegrid: data structures and simple coarsening, adapted partitions in agglom
C-accelerated: processing in libgeometry and opm processing.

8 / 117
Quick overview of functionality

Discretization and solvers for incompressible flow:


incomp mimetic mpfa ntpfa

vem adjoint

incomp implements TPFA-based flow solver and explicit/implicit transport solvers;


mimetic, mpfa, ntpfa, and vem implement consistent discretizations.

8 / 117
Quick overview of functionality

Discretization and solvers for compressible flow:


ad-core ad-blackoil ad-eor blackoil-sequential

deckreader ad-props

The AD-OO framework offers fully implicit simulators from industry-standard input
decks, including computations of adjoints

8 / 117
Quick overview of functionality

Upscaling and multiscale methods:


msrsb msmfem msfvm hfm

upscaling steady-state

msrsb is state-of-the art multiscale solver, hfm implements this for fracture models,
msmfem and msfvm are earlier developments
upscaling: flow-based single-phase upscaling, steady-state: multiphase upscaling

8 / 117
Quick overview of functionality
Fractured media:
dfm hfm dual-porosity

dfm – discrete fracture models, hfm – hierarchical/embedded fracture models

Geomechanics:
ad-mechanics vemmech fvbiot

ad-mechanics∗ – coupled flow and mechanics (R2017b), vemmech – virtual element


methods, fvbiot – multipoint stress-approximation methods
8 / 117
Quick overview of functionality

Workflow tools:
co2lab diagnostics mrst-gui enkf

optimization remso

co2lab: comprehensive tools for large-scale CO2 storage saline aquifers


diagnostics: flow diagnostics, mrst-gui: interactive visualization
optimization: solution of optimal control problems based on AD-OO
enkf and remso: third-party modules for EnKF and multiple-shooting optimization

8 / 117
Outline

1 Introduction

2 Getting started with MRST

3 Grids and petrophysical data

4 Incompressible flow

5 Multiphase flow

6 Compressible flow

7 The AD-OO framework in MRST

9 / 117
Downloading the software

MRST ­ MATLAB Reservoir Simulation Toolbox   SEARCH

MRST FAQ Forum Modules Gallery Download Documentation Contact

You are here: MRST / Download

Download
SINTEF publishes several sets of resources as part of the Matlab Reservoir Simulation Toolbox. This is a list of packages and datasets
currently available for download.

The MATLAB Reservoir Simulation Toolbox

MRST is a set of core features intended to assist the student, researcher and practitioner who analyses reservoir­type flows or develops
numerical methods for solving flow or transport problems in reservoir applications. It is the intention of the MRST developers that the package
be a solid foundation for grid handling, visalisation, and advanced discretisations.

Sources to the current as well as a few, selected previous releases of the core MRST package set are available on a separate download page.
Please fill out the accompanying form to download the package.

Public Data Sets

The SAIGUP data set is a single realisation from the Sensitivity Analysis of the Impact of Geological Uncertainties on Production project.
The data is used in a number of examples accompanying the 2011a and later releases of MRST. You may download a copy of the data
from the following web page.
The Johansen formation is a candidate site for large­scale CO2  storage offshore the south­west coast of Norway. The MatMoRA project
has developed a set of geological models based on available seismic and well data. You may download a copy of the data from the
following web page.

Published February 23, 2011

From http://www.sintef.no/MRST

10 / 117
Installing MRST

MRST is provided as self-contained archive file. The following command


untar mrst−2016b.tar.gz

will create a directory mrst-2016b in your current working directory.


Once MRST has been extracted to some directory, you must navigate MATLAB there.
On Linux/Mac OS,
cd /home/username/mrst−2016b/

or on Windows,
cd C:\Users\username\mrst−2016b\

assuming that the files were extracted to the home directory. The startup.m file must
then be run to activate MRST,
startup;

or you can call the startup script directly


run /home/username/mrst−2016b/startup

11 / 117
Getting started: welcome message
If you start MATLAB in the directory containing MRST, or run the
startup.m file, you will see the following message

12 / 117
Getting started: sources for information

the MRST book and key publications – the book gives a


comprehensive introduction to basic flow simulation as implemented
in MRST; three papers give more condensed overviews
example scripts
Jolts (just-in-time online learning tools)
module examples
manual pages for individual routines
the source code itself
FAQ webpage and MRST-users mailing list
public data sets

13 / 117
330 10 Solvers for Incompressible Immiscible Flow

Knut-Andreas Lie

An Introduction to Reservoir
Fig. 10.13. Illustration of the sloping sandbox used for the buoyancy example and
Simulation Using MATLAB how it is simulated by rotating the gravity vector. (Color: Gaussian porosity field).

R = makehgtform('yrotate',-pi*theta/180);
User Guide for the Matlab Reservoir Simulation gravity reset on
gravity( R(1:3,1:3)*gravity().' );

Toolbox (MRST) MRST defines the gravity vector as a persistent, global variable which by
default equals ~0. The second line ensures that ~g is set to the standard value
(pointing downward in the vertical direction) before we perform the rotation.
To initialize the problem, we assume that CO2 , which is lighter than the
June 12, 2017 resident brine, fills up the model from the bottom and to a prescribed height,
xr = initResSol(G, 1*barsa, 1);
d = gravity() ./ norm(gravity);
dc = G.cells.centroids * d.';
xr.s(dc>max(dc)-height) = 0;

For accuracy and stability, the time step is ramped up gradually as follows,
dT = [.5, .5, 1, 1, 1, 2, 2, 2, 5, 5, 10, 10, 15, 20, ...
repmat(25,[1,97])].*day;

to reach a final simulation time of 2500 days. The remaining code is similar
to what was discussed above; details can be found in buoyancyExample.m.
Let us consider the homogeneous case first. Initially, the buoyant CO2
plume will form a cone shape as it migrates upward and gradually drains the
resident brine. After approximately 175 days, the migrating plume starts to
accumulate as a thin layer of pure CO2 under the sloping east face of the box.
This layer will migrate quickly up towards the topmost northeast corner of
the box, which is reached after approximately 400 days, This corner forms a
structural trap that will gradually be filled as more CO2 migrates upward.
The trapped CO2 forms a diffused and curved interface (see the plots at
SINTEF ICT, Departement of Applied Mathematics 500 and 1000 days), but as time passes, the interface becomes sharper and
flatter. During the same period, brine will imbibe into the trailing edge of
Oslo, Norway the CO2 plume and gradually formed a layer of pure brine at the bottom.

Page: 1 job: mrst-book macro: svmono.cls date/time: 12-Jun-2017/20:34 Page: 330 job: mrst-book macro: svmono.cls date/time: 12-Jun-2017/22:33
Example scripts and tutorials . . .

The core module of MRST offers a number of examples that introduce


you to data structures and data sets, how to set up basic solvers, how to
visualize input data and simulation results, etc

>> mrstExamples
Module "core" has 18 examples:
flowSolverTutorial1.m
flowSolverTutorialAD.m
tutorialAD.m
tutorialBasicObjects.m
tutorialPlotting.m
datasets/showCaseB4.m
datasets/showJohansen.m
datasets/showNorne.m
datasets/showSAIGUP.m
datasets/showSPE10.m
grids/gridTutorialCornerPoint.m
grids/gridTutorialIntro.m
grids/gridTutorialStruct.m
grids/gridTutorialUnstruct.m
:

15 / 117
. . . presented in workbook format

16 / 117
Just-in-time online learning tools

Short learning modules consisting of 3-10 minute videos covering a specific topic.
Jolt1: explains what MRST is, how to download it, and how to make your first flow
solvers. Jolt2: introduction to grid and grid generation.
17 / 117
Finding more information . . .

the MRST book and key publications


example scripts
Jolts (just-in-time online learning tools)
module examples – many of the modules contain example scripts
located in the subdirectory ’examples’ of the module that outline
functionality provided in the module. Some of these examples are
available on the module overview pages
manual pages for individual routines
the source code itself
FAQ webpage and MRST-users mailing list
public data sets

18 / 117
Module examples on the web
MRST ­ MATLAB Reservoir Simulation Toolbox   SEARCH

MRST FAQ Forum Modules Gallery Download Documentation Contact

You are here: MRST / Modules / Grid Coarsening

Grid Coarsening
The module implements functionality for generating coarse partitions and turning these into MRST grids.

Tutorials

Example 1 Example 2

This example shows you how to partition We show partitions of grids representing more
rectangular 2D Cartesian grids, the complex domains: a rectangular grid with a
relationship between cell and block numbers,   semi­circular cutout, a 3D cup­formed domain,
and outlines the basics of the coarse­grid a 2D Voronoi grid of rectangular domain with a
structure, including numbering of cells, faces, quater­circle cutout, and a corner­point grid
and node. with a single fault.

 
Example 3 Example 4

The example continues the discussion of the In this example, we take a closer look at
coarse­grid structure and shows how we can partition vectors and discuss how different
 
partition the coarse faces so that there are types of partitions can be combined into one.
more than one face (connection) between
neighboring coarse blocks.

 
Example 6
Example 5
We partition the Norne field uniformly in logical
In this example, we use the function Cartesian space. Since the model contains
refineNearWell to make coarse grids with many inactive cells, the initial partition must be
 
various types of near­well refinement. The postprocessed to ensure a contigous partition
examples uses both Cartesian and 2.5 D PEBI vector. We visualize some of the coarse blocks
fine grids. and show how they are connected with their
neighbors.

 
19 / 117
Example 7
The module explorer

Start GUI with the command: mrstExploreModules


20 / 117
Example: tutorial from incomp module

K 
∇ · ~v = q, ~v = − ∇p + ρg∇z
µ
Vertical well and Dirichlet boundary
% Grid and rock parameters
nx = 20; ny = 20; nz = 10;
G = computeGeometry(cartGrid([nx, ny, nz]));
rock.perm = repmat(100 * milli*darcy, [G.cells.num, 1]);
fluid = initSingleFluid('mu', 1*centi*poise, ...
' rho ' , 1014*kilogram/meterˆ3);
gravity reset on Source term and boundary
condition
% Fluid sources and boundary conditions
c = (nx/2*ny+nx/2 : nx*ny : nx*ny*nz) .';
src = addSource([], c, ones(size(c)) ./ day());
bc = pside([], G, ' LEFT', 10*barsa());

% Compute transmissibilities
T = computeTrans(G, rock);

% Solve the system and convert to bars


rSol = initState(G, [], 0);
rSol = incompTPFA(rSol,G,T,fluid,'src',src, ' bc' ,bc);
p = convertTo(rSol.pressure, barsa());

From tutorial: incompTutorialSRCandBC.m


Pressure distribution

21 / 117
Operating modules

Graphical user interface to modules:


mrstModule('gui' )
moduleGUI

List all modules and their path


mrstPath

Load new modules


mrstModule add mimetic mpfa

Adding your own modules


mrstPath reregister distmesh ...
/home/username/mrst−2016b/utils/3rdparty/distmesh

22 / 117
Finding more information . . .

the MRST book and key publications


example scripts
Jolts (just-in-time online learning tools)
module examples
manual pages for individual routines – all routines in MRST are
documented using a style similar to standard MATLAB that describes
synopsis, input/output parameters, and how the routine works. In
most cases, the documentation also offers simple examples of usage
and list related routines
the source code itself
FAQ webpage and MRST-users mailing list
public data sets

23 / 117
Manual pages: computing transmissibility
>> help computeTrans
Compute transmissibilities.

SYNOPSIS:
T = computeTrans(G, rock)
T = computeTrans(G, rock, ’pn’, pv, ...)

PARAMETERS:
G - Grid structure as described by grid_structure.

rock - Rock data structure with valid field ’perm’. The permeability
is assumed to be in measured in units of metres squared (m^2).
Use function ’darcy’ to convert from darcies to m^2, e.g.,

perm = convertFrom(perm, milli*darcy)

if the permeability is provided in units of millidarcies.

The field rock.perm may have ONE column for a scalar


permeability in each cell, TWO/THREE columns for a diagonal
permeability in each cell (in 2/3 D) and THREE/SIX columns for a
symmetric full tensor permeability. In the latter case, each
cell gets the permeability tensor

K_i = [ k1 k2 ] in two space dimensions


[ k2 k3 ]
:
:
RETURNS:
T - half-transmissibilities for each local face of each grid cell in the grid.
The number of half-transmissibilities equals the number of rows in G.cells.faces.

COMMENTS:
PLEASE NOTE: Face normals are assumed to have length equal to the corresponding
face areas. This property is guaranteed by function ’computeGeometry’.

SEE ALSO:
computeGeometry, computeMimeticIP, darcy, permTensor.
24 / 117
Finding more information . . .

the MRST book and key publications


example scripts
Jolts (just-in-time online learning tools)
module examples
manual pages for individual routines
the source code itself – all parts of MRST are available as open
source code. However, MRST is a research tool that was developed
primary to provide a flexible development platform, and some parts of
the software may admittedly be quite hard to digest for those
unfamiliar with our way of writing efficient MATLAB
FAQ webpage and MRST-users mailing list
public data sets

25 / 117
Source code: computing transmissibility
% Vectors from cell centroids to face centroids
cellNo = rldecode(1:G.cells.num, diff(G.cells.facePos), 2)';
if ∼isempty(opt.cellCenters)
C = opt.cellCenters;
else
C = G.cells.centroids;
end
if ∼isempty(opt.cellFaceCenters)
C = opt.cellFaceCenters − C(cellNo,:);
else
C = G.faces.centroids(G.cells.faces(:,1), :) − C(cellNo,:);
end

% Normal vectors
sgn = 2*(cellNo == G.faces.neighbors(G.cells.faces(:,1), 1)) − 1;
N = bsxfun(@times, sgn, G.faces.normals(G.cells.faces(:,1),:));
clear sgn;

if strcmpi(opt.K_system, 'xyz'),
[K, i, j] = permTensor(rock, G.griddim);

assert (size(K,1) == G.cells.num, ...


[ ' Permeability must be defined in active cells only. \n', ...
' Got %d tensors, expected %d (== number of cells).' ], ...
size(K,1), G.cells.num);

% Compute T = C'*K*N / C'*C. Loop−based to limit memory use.


T = zeros(size(cellNo));
for k=1:size(i,2),
T = T + sum(C(:,i(k)) .* K(cellNo,k) .* N (:, j(k )), 2);
end
clear K i j cellNo N;
T = T./ sum(C.*C,2);
clear C;

From computeTrans.m
26 / 117
Finding more information . . .

the MRST book and key publications


example scripts
Jolts (just-in-time online learning tools)
module examples
manual pages for individual routines
the source code itself
FAQ webpage and MRST-users mailing list
public data sets

27 / 117
The MRST-users mailing list

Hosted on Google group: [email protected]

Please consider the following points before posting a question:


Search the forum to check if your question has been answered
Formulate your question carefully. If we cannot understand, we
cannot help you
For code-technical issues, prepare a complete minimal example
Please help out in answering questions from other users
Have a little patience; this is not a 24-7 emergency line

URL: https://groups.google.com/forum/#!forum/sintef-mrst

28 / 117
Finding more information . . .

the MRST book and key publications


example scripts
Jolts (just-in-time online learning tools)
module examples
manual pages for individual routines
the source code itself
FAQ webpage and MRST-users mailing list
public data sets – a number of data sets are offered alongside with
the software; these data sets are used in various examples and
tutorials of the software

29 / 117
Public data sets

SPE 1 SPE 3 SPE 9 SPE 10

BedModel2 Egg CO2 Atlas


BedModels1

Norne SAIGUP

Johansen CaseB4

30 / 117
Public data sets

Graphical user interface to download


and get information about data sets:
mrstDatasetGUI()

Information about specific data set


getDatasetInfo('norne')

Path for each known data set


getDatasetPath('norne')

Query/set path for all public data sets


mrstDataDirectory
mrstDataDirectory('/home/username/mydata/mrst/')

31 / 117
Software requirements

Minimal requirement is MATLAB version 7.4 (R2007a).


Certain modules use features that were not present in R2007a:
Automatic differentiation relies upon new-style classes (classdef) from
R2008a.
Various scripts and examples use new syntax for random numbers from
R2007b.
Some scripts in the modules may use tilde operator to ignore return values
(e.g, [∼,i]=max(X,1)) from R2009b.
Some solvers (e.g., fully implicit) are not efficient on versions older than
R2011b.
Most of MRST can be used with Octave, except for graphical user interfaces
and some functionality in the object-oriented framework for fully implicit
solvers based on automatic differentiation

More information: http://www.sintef.no/Projectweb/MRST/FAQ/

32 / 117
External dependencies

Apart from MATLAB, MRST does not rely on any third-party


software/libraries.
However, the following are useful:
AGMG – simple but efficient algebraic multigrid solver
MATLAB-BGL – MATLAB Boost Graph Library
METIS – partitioning of fully unstructured grids, etc.
Export_fig – to produce high quality figures for publications

More information: http://www.sintef.no/Projectweb/MRST/FAQ/

33 / 117
 

 Tutorials
Terms of use   All modules in MRST have a set of tutorial scripts that introduce you to the basic functionality of the module. Several of
these are also available on the module webpages. In addition, we have number of tutorials that introduce you to basic
functionality of MRST.
You are free to use the software within the GNU GPL3 license, but . . .
 

Citing MRST

If you are using MRST in any publication, we would be grateful if you cite the MRST book or one of the following three papers (possibly in
addition to a link to our webpage):

  K. Bao, K.­A. Lie, O. Møyner, and M. Liu. Fully implicit simulation of polymer flooding with MRST. Comput. Geosci.,
2017. DOI: 10.1007/s10596­017­9627­2. Also available from: Springer Nature ShareIt.
 
An earlier version was published as: K. Bao, K.­A. Lie, O. Møyner, and M. Liu Fully­implicit simulation of polymer flooding with MRST.
ECMOR XV, Amsterdam, Netherlands, 29 Aug­­1 Sept, 2016. DOI: 10.3997/2214­4609.201601880

S. Krogstad, K.­A. Lie, O. Møyner, H. M. Nilsen, X. Raynaud, and B. Skaflestad. MRST­AD ­ an open­source framework
  for rapid prototyping and evaluation of reservoir simulation problems. Paper 173317­MS presented at the 2015
Reservoir simulation Symposium, Houston, Texas, USA, 23­25 February 2015.

K.­A. Lie, S. Krogstad, I. S. Ligaarden, J. R. Natvig, H. M. Nilsen, and B. Skaflestad. Open source MATLAB
implementation of consistent discretisations on complex grids. Comput. Geosci., , Vol. 16, No. 2, pp. 297­322, 2012.
DOI: 10.1007/s10596­011­9244­4
  Complete MATLAB scripts that reproduce (almost) all the figures and examples in the paper are available for
download, see e.g., Example 5 and Example 6.

An earlier version was published as: K.­A. Lie, S. Krogstad, I. S. Ligaarden, J. R. Natvig, H. M. Nilsen, and B. Skaflestad. Discretisation on
complex grids ­­ Open source MATLAB implementation. Proceedings of ECMOR XII, Oxford, UK, 6­9 September 2010

Scientific publications utilizing MRST

MRST has been used in a large number of journal articles, conference proceedings, and master and doctoral theses. We try to collect as many
as possible of these publications and have compiled them in separate lists. If your paper is missing in the lists, if have you used MRST in your
thesis, or if have you supervised students using MRST, we are of course very happy to hear about it. If you provide us with publication details,
we will list your publication or details about the thesis. If you also provide us with an illustrateive picture and a short description, we will
highlight your work  on our gallery pages. Contact: Knut­[email protected]

Published June 14, 2011
34 / 117
Computer exercises

Download and install the software


Run flowSolverTutorial1 from the command line to verify that your
installation is working.
Load the flowSolverTutorial1 tutorial in the editor and run it in cell mode.
Use help or doc to inspect the documentation for the various functions that are
used in the script.
Run the flowSolverTutorial1 tutorial line-by-line: Set a breakpoint on the first
executable line by clicking on the small symbol next to line 27, push the ’play
button’, and then use the ’step’ button to advance a single line at the time.
Change the grid size to 10 × 10 × 25 and rerun.
Use mrstExploreModules() to locate and load the incompIntro tutorial from the
incomp module. Examine the tutorial in the same way as you did for
flowSolverTutorial1. Publish the workbook

35 / 117
Outline

1 Introduction

2 Getting started with MRST

3 Grids and petrophysical data

4 Incompressible flow

5 Multiphase flow

6 Compressible flow

7 The AD-OO framework in MRST

36 / 117
What you will learn in this section

In this section, we will discuss:


standard grids and grid factory routines in MRST
stratigraphic grids
petrophysical properties and simplified geostatistics
unstructured representation used in MRST
techniques for manipulating (and visualizing) grids
You will also get a tast of plotting routines, common tricks, etc

To learn more:
– watch the videos in Jolt2
– study tutorials called gridTutorial*.m in mrst-core
– read Lie et al. (COMG, 2012), doi: 10.1007/s10596-011-9244-4
– read Chapters 2 and 3 in the MRST book

37 / 117
Grids and physical quantities

The fundamental object in MRST is the grid:


all grids are assumed to be unstructured
data structure for geometry and topology
several grid factory routines
input of industry-standard formats

Physical quantities defined as dynamic objects in Matlab:


properties of medium: φ, K, net-to-gross, . . .
reservoir fluids: ρ, µ, kr , PVT, . . .
driving forces: wells, boundary conditions, sources
reservoir state: pressure, fluxes, saturations, . . .
we assume SI units (e.g., [K] = m2 , [µ] = Pa · s, . . . )
Functions in MRST accept these objects as input,
manipulate them, and produce them as output

38 / 117
Standard grids: Cartesian grids

Regular Cartesian grids: Rectilinear grids:


G = cartGrid([nx, ny], [Lx Ly ]); G = tensorGrid(x, y);
G = cartGrid([nx, ny, nz ], [Lx Ly Lz ]); G = tensorGrid(x, y, z);

G = cartGrid([10 20 5],[5 10 1]); G = tensorGrid(sqrt(0:.1:2),(0:.1:1).ˆ2);


plotGrid(G), view(3); axis equal plotGrid(G,'FaceColor ' ,[ .7 .7 1]);

0.9

0 0.8

0.5
0.7
1
10 0.6

9
0.5
8
7 0.4
6
0.3
5
4 5 0.2
3 4
2 3 0.1
2
1
1 0
0 0 0 0.2 0.4 0.6 0.8 1 1.2 1.4

39 / 117
Standard grids: curvilinear grids
Create a rough grid by perturbing the inner nodes randomly
nx = 12; ny=6;
G = cartGrid([nx, ny]);
plotGrid(G,' LineStyle ' , ' : ' );

I = true(G.nodes.num,1); % Logical indexing is fast in MATLAB


I( gridFaceNodes(G, boundaryFaces(G))) = false;
G.nodes.coords(I,:) = G.nodes.coords(I,:) + .6*(rand(sum(I),2)−.5);
plotGrid(G,'FaceColor ' , ' none' , ' LineWidth' ,1);

0
0 2 4 6 8 10 12

40 / 117
Standard grids: fictitious domains

Mapping a curvilinear grid to a complex shape is


generally difficult. −2

−1
Alternative approach: embed the domain within a
0
larger “fictitious” domain of simple shape, −2
1
boolean indicator value tells whether each cell is 0
2
part of the domain or not. Here, an ellipsoid 2 2
2
within a cube: 0
0
2

−2 −2
x = linspace(−2,2,21);
G = tensorGrid(x,x,x);
subplot(1,2,1); plotGrid(G);view(3); axis equal
−2

subplot(1,2,2); plotGrid(G,'FaceColor
−1
' , ' none' );

G = computeGeometry(G); 0 2

c = G.cells.centroids; 1
−2
1
r = c(:,1).ˆ2 + 0.25*c(:,2).ˆ2+0.25*c(:,3).ˆ2; 0
2
G = removeCells(G, r>1); 2 2
0
2
plotGrid(G); view(−70,70); axis equal;
0
2
1 −1
0
0
−2 −2 −1
−2 −2

41 / 117
Standard grids: Delaunay and Voronoi grids

load seamount; plot(x(:),y (:), ' o ' );


G = triangleGrid([x(:) y (:)]);
plotGrid(G,'FaceColor' ,[ .8 .8 .8 ]);

Duality: Delaunay and Voronoi grids

For 3D tetrahedral grids, MRST supplies the


function tetrahedralGrid(x,y,z). The function
pebi() has no natural counterpart in 3D, but
V = pebi(triangleGrid([x y]));
routines exist in the upr module
plotGrid(V,'FaceColor' ,[ .8 .8 .8 ]);

42 / 117
Using an external grid generator
Install DistMesh by Persson & Strang as a module
path = fullfile(ROOTDIR,'utils' , ' 3rdparty ' , ' distmesh ' );
mkdir(path)
unzip('http:// persson.berkeley.edu /distmesh/distmesh.zip ' , path);
mrstPath(' reregister ' , ' distmesh ' , path);

and use it to grid around a circular inclusion


mrstModule add distmesh;
fd=@(p) ddiff(drectangle(p,−1,1,−1,1), dcircle(p,0,0,0.5));
[p,t]=distmesh2d(fd, @huniform, 0.2, [−1,−1;1,1], [−1,−1;−1,1;1,−1;1,1]);
G = triangleGrid(p, t);

For details: see Chapter 3.2.4 of the MRST book


43 / 117
Layered and stratigraphic grids

MRST has a few simple routines for generating layered/stratigraphic grids

% Extrude a standard MATLAB dataset % Make and process simple corner−point description
load seamount grdecl = simpleGrdecl([20, 10, 5], 0.12)
*pi); g = triangleGrid([x(:) y (:)]); G = processGRDECL(grdecl);
; P = pebi(g); plotGrid(G, ' FaceAlpha',0.8);
.05 :1)); V = makeLayeredGrid(P, 5); plotFaces(G,find(G.faces.tag>0), 'FaceColor', ' red ' );
plotGrid(V), view(−40, 60), axis off view (40,40), axis off

44 / 117
Rock modelling in MRST

All flow and transport solvers in MRST require a rock structure, which by
convention is called rock, and contains two fields:
rock.poro – porosity, column vector with one entry per active cell
rock.perm – permeability in SI units

The permeability can either be a single column (isotropic), two or three


columns (diagonal tensor), or a symmetric, full tensor permeability
 
  K1 (i) K2 (i) K3 (i)
K1 (i) K2 (i)
Ki = , Ki = K2 (i) K4 (i) K5 (i)
K2 (i) K3 (i)
K3 (i) K5 (i) K6 (i)

Nonsymmetic permeabilities are currently not supported

The rock object can also hold net-to-gross, ntg, consisting of a scalar or
a single column vector with one value per active cell

45 / 117
Example: homogeneous model

Square 10 × 10 grid model with a uniform porosity of 0.2 and isotropic


permeability equal 200 mD:
G = cartGrid([10 10]);
rock = makeRock(G, 200*milli*darcy, 0.2);

Because MRST works in SI units, we must convert from the field units
’darcy’ to the SI unit ’meters2 ’. Alternative: use the conversion function
convertFrom(200,milli*darcy)

Homogeneous, anisotropic permeability can be specified in the same way:


rock = makeRock(G, [100 100 10].*milli*darcy, .2);

Warning: It is better to use makeRock instead of setting rock.poro and rock.perm directly to
avoid unintentionally copying data elements from existing rock objects

46 / 117
Example: heterogeneous model
20

15

Generate φ as a Gaussian field and then 10

compute K from the Carman–Kozeny 5

relation 0
0 5 10 15 20 25 30 35 40 45 50

1 φ3 d2p
K= , 0.2 0.22 0.24 0.26 0.28 0.3 0.32 0.34 0.36 0.38 0.4

72τ (1 − φ)2 plotCellData(G,rock.poro);


colorbar('horiz ' ); axis equal tight;
In MRST:
G = cartGrid([50 20]);
p = gaussianField(G.cartDims, ...
[0.2 0.4], [11 3], 2.5);
K = p.ˆ3.*(1e−5)ˆ2./(0.81*72*(1−p).ˆ2); 0

rock = makeRock(G, K(:), p (:)); 5


50
45
40
10 35

MRST only has very simplified support for 20


15 20
25
30

15
geostatistics. For more realistic 10
5
5
10

0 0

geostatistics, you should consider


50 100 150 200 250 300
commercial software or e.g., GSLIB
plotCellData(G,convertTo(rock.perm,milli*darcy));
colorbar('horiz ' ); axis equal tight; view(3);

47 / 117
Example: stratigraphic model

Generate a layered model with a single fault in the middle.


G = processGRDECL(simpleGrdecl([50 30 10], 0.12));
K = logNormLayers(G.cartDims, [100 400 50 350], 'indices ' , [1 2 5 7 11]);

Four layers with mean values: 100, 400, 50, and 350 mD (top to
bottom), and layer thickness: one, three, two, and four grid cells.

plotCellData(G,log10(K),'EdgeColor','k' );
view(45,30); axis tight off,
set(gca,'DataAspect',[0.5 1 1])
h = colorbar('horiz' );
ticks = 25*2.ˆ[0:5];
set(h, ' XTick',log10(ticks),'XTickLabel',ticks);

25 50 100 200 400 800

48 / 117
Example: Model 2, 10th SPE Comparative Solution Project
Separate module, spe10, for downloading and accessing this model
mrstModule add spe10; rock = SPE10_rock();

4 4
x 10 x 10
2.5 3
Ness Tarbert
Tarbert Ness
2.5
2

1.5

1.5

0.5
0.5

0 0
−4 −3 −2 −1 0 1 2 3 4 5 −8 −6 −4 −2 0 2 4

lateral permeability vertical permeability

49 / 117
Example: model from Eclipse input deck

Download the SAIGUP data set using mrstDatasetGUI. List of files:


028_A11.EDITNNC 028.MULTX 028.PERMX 028.SATNUM SAIGUP.GRDECL
028_A11.EDITNNC.001 028.MULTY 028.PERMY SAIGUP_A1.ZCORN
028_A11.TRANX 028.MULTZ 028.PERMZ SAIGUP.ACTNUM
028_A11.TRANY 028.NTG 028.PORO SAIGUP.COORD

Use deckformat module to read data


mrstModule add deckformat;
grdecl = readGRDECL(fullfile(getDatasetPath('SAIGUP'),'SAIGUP.GRDECL'))

grdecl =
cartDims: [40 120 20]
COORD: [29766x1 double]
ZCORN: [768000x1 double]
ACTNUM: [96000x1 int32]
PERMX: [96000x1 double]
PERMY: [96000x1 double]
PERMZ: [96000x1 double]
MULTX: [96000x1 double]
MULTY: [96000x1 double]
MULTZ: [96000x1 double]
PORO: [96000x1 double]
NTG: [96000x1 double]
SATNUM: [96000x1 double]
50 / 117
Example: synthetic shallow-marine model

The SAIGUP model uses the Eclipse ’METRIC’ conventions (permeability


in unit md, etc), so we first convert to SI units
usys = getUnitSystem('METRIC');
grdecl = convertInputUnits(grdecl, usys);

Then we generate a space-filling grid and extract petrophysical properties


G = processGRDECL(grdecl);
G = computeGeometry(G);
rock = grdecl2Rock(grdecl, G.cells.indexMap);

51 / 117
Example: synthetic shallow-marine model
horizontal permeability vertical permeability

net-to-gross vertical multipliers less than unity

52 / 117
Grids in MRST: fully unstructured

All grids are assumed to be unstructured. Basic representation:

cells nodes faces


Choices in grid representation are guided by utility and convenience in
low-order finite-volume methods
Available geometric information: centroids, normals, areas, and volumes
Heavy use of indirection maps
Redundant information must be constructed, e.g., using run-length encoding

53 / 117
Grid structure: cells

The cell structure, G.cells, has the mandatory fields:


num – the number Nc of cells in the global grid

facePos – indirection map into the faces array. Information of cell


i is found in submatrix faces(facePos(i):facePos(i+1)-1,:)
The number of faces of each cell may be computed using the statement diff(facePos).
Likewise, the total number of faces is given as nf = facePos(end)-1

faces – nf × 3 array of global faces connected to a given cell.


Specifically, if faces(i,1)==j, then global face number
faces(i,2) is connected to global cell number j.
The third column is optional and can for certain types of grids contain a tag used to
distinguish face directions
The first column is redundant: cell index j is simply repeated facePos(j+1)-facePos(j)
times. To conserve memory, we regenerate it using run-length encoding:
rldecode(1:G.cells.num, diff(G.cells.facePos),2).’

54 / 117
Grid structure: cells

Optional field:
indexMap – Nc × 1 array mapping internal cell indices to external
cell indices. For models with no inactive cells, indexMap equals
1 : Nc . For cases with inactive cells, indexMap contains the indices
of the active cells sorted in ascending order.
For logically Cartesian grids, a map of cell numbers to logical indices can be constructed
using the following statements in 3D:

[ijk{1:3}] = ind2sub(dims, G.cells.indexMap(:));


ijk = [ijk{:}];

Here, ijk(i:) is the global (I, J, K) index of cell i.

Additional fields, typically added by a call to computeGeometry:


volumes – an Nc × 1 (double) array of cell volumes
centroids – an Nc × d (double) array of cell centroids

55 / 117
Grid structure: faces

The face structure, G.faces, has the mandatory fields:


num – the number Nf × 1 of cells in the global grid

facePos – indirection map into the nodes array.

nodes – an Nn × 2 array of vertices. If nodes(i,1)==j, local


vertex i is part of global face number j and corresponds to global
vertex nodes(i,2). Nodes are oriented such that a right-hand rule
determines the direction of the face normal. First column is
redundant

neighbors – Nf × 2 array. Global face i is shared by global cells


neighbors(i,1) and neighbors(i,2). One of the entries in each
row can be zero, but not both, to indicate that this is an external
face belonging to only one cell (the nonzero entry).

56 / 117
Grid structure: faces and nodes

Optional field:
tag – can contain user-defined face indicators

Additional fields, typically added by a call to computeGeometry:


areas – an Nf × 1 of face areas
normals – an Nf × d of area weigthed, directed face normals,
which on face i points from cell neighbors(i,1) to cell
neighbors(i,2).
centroids – an Nf × d array of face centroids.

The vertex structure, G.nodes, consists of two fields:


num – number Nn of global nodes in the grid
coords – an Nn × d array of physical nodal coordinates. Global
node i is at physical coordinate coords(i,:).

57 / 117
Example: grid structure

G = removeCells( cartGrid([3,2]), 2)

G =
cells: [1x1 struct]
faces: [1x1 struct]
nodes: [1x1 struct]
cartDims: [3 2]
type: {’tensorGrid’ ’cartGrid’ ’removeCells’}
griddim: 2

cells.faces = faces.nodes = faces.neighbors =


9 14 10 15 11 16 12 1 1 1 (East) 1 1 0 1
1 9 3 (South) 1 5 1 0
1 2 2 (West) 2 2 0 2
1 11 4 (North) 2 6 2 0
2 3 1 (East) 3 3 0 3
5 3 6 4 7 5 8 2 10 3 (South) 3 7 3 4
2 4 2 (West) 4 4 4 5
2 13 4 (North) 4 8 5 0
3 5 1 (East) 5 5 0 1
5 11 6 12 7 13 8 3 11 3 (South) 5 9 0 2
3 6 2 (West) 6 6 1 3
3 14 4 (North) 6 10 0 4
4 6 1 (East) 7 7 2 5
4 12 3 (South) 7 11 3 0
1 1 2 3 2 4
4 7 2 (West) 8 8 4 0
4 15 4 (North) 8 12 5 0
5 7 1 (East) 9 2
5 13 3 (South) 9 1
1 9 2 3 10 4 5 8 2 (West) : :
5 16 4 (North) : :

58 / 117
Geometry computation: basic steps

Single cell Tesselation of faces

Area-weighted centroid and normal vector Triangulation of cell volume

59 / 117
Computer exercises

List all tutorials in mrst-core and go through at least one of each of the
following types:
datasets/show<name>.m grids/gridTutorial<name>.m

Make the grid below. Hint: the grid spacing in the x-direction is given by
∆x(1 − 21 cos(πx)) and the colors signify cell volumes.

Create MRST grids from the standard data set trimesh2d. How would
you assign lognormal petrophysical parameters to these grids so that the
spatial correlation is preserved?

60 / 117
Outline

1 Introduction

2 Getting started with MRST

3 Grids and petrophysical data

4 Incompressible flow

5 Multiphase flow

6 Compressible flow

7 The AD-OO framework in MRST

61 / 117
What you will learn in this section

We will go through:
discrete differential and averaging operators

finite volume methods for −∇ K∇p = q
automatic differentiation
flow solvers in the incomp family
You will also get a tast of efficient vectorization tricks in MATLAB

To learn more:
– watch the videos in Jolt1
– study the 1ph tutorials/examples in the incomp module
– read Lie et al. (COMG, 2012), doi: 10.1007/s10596-011-9244-4
– read Chapters 4 to 6 in the MRST book

62 / 117
Discrete differentiation operators
Idealized models Grid structure in MRST Industry models

c F(c) f C1 C2
1 1 1 3 1
7
8 1 2 2 1 2
8
1 3 3 1 8
3 1 4 4 9 1
7 2 5 5 4 2
6
2 6 6 2 5
9 4 1 2 7 7 2 6
2 2
2 8 8 2 7
.. .. ..
6 2 2 . . .
.. .. ..
1 5 3 1 . . .
5
.. ..
. .
.. ..
. .
3 4
Map: cell → faces Map: face → cells

Starting point: mapping F from cell to faces, and C from face to cells:
C = G.faces.neighbors; % Cells belonging to each face
C = C(all(C ∼= 0, 2), :); % Only interior faces
cn = gridCellNo(G); % Repeat cell number for all faces
F = G.cells.faces(:,1); % Faces making up each cell
[nf,nc] = deal(size(C,1), G.cells.num); % Number of faces/cells

We only consider internal faces, mapping F is represented as cn and F

63 / 117
Discrete differentiation operators
Idealized models Grid structure in MRST Industry models

c F(c) f C1 C2
1 1 1 3 1
7
8 1 2 2 1 2
8
1 3 3 1 8
3 1 4 4 9 1
7 2 5 5 4 2
6
2 6 6 2 5
9 4 1 2 7 7 2 6
2 2
2 8 8 2 7
.. .. ..
6 2 2 . . .
.. .. ..
1 5 3 1 . . .
5
.. ..
. .
.. ..
. .
3 4
Map: cell → faces Map: face → cells

The discrete div operator is a linear mapping from faces to cells:


(
X 1, if c = C1 (f ),
div(v)[c] = sgn(f )v[f ], sgn(f ) =
f ∈F (c)
−1, if c = C2 (f ).

Here, v[f ] denotes a discrete flux over face f with orientation from cell
C1 (f ) to cell C2 (f )

63 / 117
Discrete differentiation operators
Idealized models Grid structure in MRST Industry models

c F(c) f C1 C2
1 1 1 3 1
7
8 1 2 2 1 2
8
1 3 3 1 8
3 1 4 4 9 1
7 2 5 5 4 2
6
2 6 6 2 5
9 4 1 2 7 7 2 6
2 2
2 8 8 2 7
.. .. ..
6 2 2 . . .
.. .. ..
1 5 3 1 . . .
5
.. ..
. .
.. ..
. .
3 4
Map: cell → faces Map: face → cells

The discrete grad operator maps from cell pair C1 (f ), C2 (f ) to face f :

grad(p)[f ] = p[C2 (f )] − p[C1 (f )],

where p[c] is a scalar quantity associated with cell c

63 / 117
Discrete differentiation operators
Idealized models Grid structure in MRST Industry models

c F(c) f C1 C2
1 1 1 3 1
7
8 1 2 2 1 2
8
1 3 3 1 8
3 1 4 4 9 1
7 2 5 5 4 2
6
2 6 6 2 5
9 4 1 2 7 7 2 6
2 2
2 8 8 2 7
.. .. ..
6 2 2 . . .
.. .. ..
1 5 3 1 . . .
5
.. ..
. .
.. ..
. .
3 4
Map: cell → faces Map: face → cells

The div and grad operators are linear and can be represented as sparse
matrix multiplications:
D = sparse([(1:nf )'; (1:nf )'], C, ones(nf,1)*[−1 1], nf, nc);
grad = @(x) D*x;
div = @(x) −D'*x;

With no-flow boundaries, the two operators are adjoint of each other, as
in the continuous case
63 / 117
Finite-volume method: single-phase flow
Fundamental physics: Darcy’s law
Z Z
~v (x) · ~
nf ds = − K(x)∇p · ~
nf ds Ai,k
Ki Kk
Γf Γf ~ci,k ~ni,k
v[f ] = −T [f ] grad(p)[f ]
Conservation of mass:
Z Z Z
ci,k · Ki ~
~ ni,k
~v · ~
n ds = ∇ · ~v d~
x= qd~
x Ti,k = Ai,k
∂Ωc Ωc Ωc ci,k |2
|~
div(v)[c] = q[c] −1
Tik = [Ti,k + Tk,i ]
−1 −1

64 / 117
Finite-volume method: single-phase flow
Fundamental physics: Darcy’s law
Z Z
~v (x) · ~
nf ds = − K(x)∇p · ~
nf ds Ai,k
Ki Kk
Γf Γf ~ci,k ~ni,k
v[f ] = −T [f ] grad(p)[f ]
Conservation of mass:
Z Z Z
ci,k · Ki ~
~ ni,k
~v · ~
n ds = ∇ · ~v d~
x= qd~
x Ti,k = Ai,k
∂Ωc Ωc Ωc ci,k |2
|~
div(v)[c] = q[c] −1
Tik = [Ti,k + Tk,i ]
−1 −1

We start by extracting face normals and vectors from cell to face


centroids:
sgn = 2*(cn == G.faces.neighbors(F, 1)) − 1;
c = G.faces.centroids(F,:) − G.cells.centroids(cn,:);
n = bsxfun(@times, sgn, G.faces.normals(F,:));

Here, the first line determines the correct sign of the face normal

64 / 117
Finite-volume method: single-phase flow
Fundamental physics: Darcy’s law
Z Z
~v (x) · ~
nf ds = − K(x)∇p · ~
nf ds Ai,k
Ki Kk
Γf Γf ~ci,k ~ni,k
v[f ] = −T [f ] grad(p)[f ]
Conservation of mass:
Z Z Z
ci,k · Ki ~
~ ni,k
~v · ~
n ds = ∇ · ~v d~
x= qd~
x Ti,k = Ai,k
∂Ωc Ωc Ωc ci,k |2
|~
div(v)[c] = q[c] −1
Tik = [Ti,k + Tk,i ]
−1 −1

We start by extracting face normals and vectors from cell to face


centroids:
sgn = 2*(cn == G.faces.neighbors(F, 1)) − 1;
c = G.faces.centroids(F,:) − G.cells.centroids(cn,:);
n = bsxfun(@times, sgn, G.faces.normals(F,:));

Here, the first line determines the correct sign of the face normal

Extract permeability vector [Kxx , Kxy , Kyx , Kyy ] for each cell:
[K, i, j] = permTensor(rock, G.griddim);
64 / 117
Finite-volume method: single-phase flow
Fundamental physics: Darcy’s law
Z Z
~v (x) · ~
nf ds = − K(x)∇p · ~
nf ds Ai,k
Ki Kk
Γf Γf ~ci,k ~ni,k
v[f ] = −T [f ] grad(p)[f ]
Conservation of mass:
Z Z Z
ci,k · Ki ~
~ ni,k
~v · ~
n ds = ∇ · ~v d~
x= qd~
x Ti,k = Ai,k
∂Ωc Ωc Ωc ci,k |2
|~
div(v)[c] = q[c] −1
Tik = [Ti,k + Tk,i ]
−1 −1

Then, we can compute the one-sided transmissibilities Ti,k :


% In 2D: i =[1 1 2 2], j=[1 2 1 2]
hT = sum(c(:,i) .* bsxfun(@times, K(cn ,:), n (:, j )), 2);
hT = hT./ sum(c.*c,2);
Here, bsxfun applies an element-by-element multiply operation to two arrays. Compact notation
for a double for-loop

64 / 117
Finite-volume method: single-phase flow
Fundamental physics: Darcy’s law
Z Z
~v (x) · ~
nf ds = − K(x)∇p · ~
nf ds Ai,k
Ki Kk
Γf Γf ~ci,k ~ni,k
v[f ] = −T [f ] grad(p)[f ]
Conservation of mass:
Z Z Z
ci,k · Ki ~
~ ni,k
~v · ~
n ds = ∇ · ~v d~
x= qd~
x Ti,k = Ai,k
∂Ωc Ωc Ωc ci,k |2
|~
div(v)[c] = q[c] −1
Tik = [Ti,k + Tk,i ]
−1 −1

Then, we can compute the one-sided transmissibilities Ti,k :


% In 2D: i =[1 1 2 2], j=[1 2 1 2]
hT = sum(c(:,i) .* bsxfun(@times, K(cn ,:), n (:, j )), 2);
hT = hT./ sum(c.*c,2);
Here, bsxfun applies an element-by-element multiply operation to two arrays. Compact notation
for a double for-loop

One-side transmissibilities can be computed once using the function:


hT = computeTrans(G, rock);
64 / 117
Finite-volume method: single-phase flow
Fundamental physics: Darcy’s law
Z Z
~v (x) · ~
nf ds = − K(x)∇p · ~
nf ds Ai,k
Ki Kk
Γf Γf ~ci,k ~ni,k
v[f ] = −T [f ] grad(p)[f ]
Conservation of mass:
Z Z Z
ci,k · Ki ~
~ ni,k
~v · ~
n ds = ∇ · ~v d~
x= qd~
x Ti,k = Ai,k
∂Ωc Ωc Ωc ci,k |2
|~
div(v)[c] = q[c] −1
Tik = [Ti,k + Tk,i ]
−1 −1

Finally, we can compute the transmissibilities Tik :


T = 1 ./ accumarray(F, 1 ./ hT, [G.faces.num, 1]);
T = T(all(C∼=0,2),:);
Here, accumarray(p,v) collects all elements of v that have identical subscripts in p, sums them,
and stores the result in the location given by p

64 / 117
Finite-volume method: single-phase flow
Fundamental physics: Darcy’s law
Z Z
~v (x) · ~
nf ds = − K(x)∇p · ~
nf ds Ai,k
Ki Kk
Γf Γf ~ci,k ~ni,k
v[f ] = −T [f ] grad(p)[f ]
Conservation of mass:
Z Z Z
ci,k · Ki ~
~ ni,k
~v · ~
n ds = ∇ · ~v d~
x= qd~
x Ti,k = Ai,k
∂Ωc Ωc Ωc ci,k |2
|~
div(v)[c] = q[c] −1
Tik = [Ti,k + Tk,i ]
−1 −1

Usually, you would not have to implement all this, but rather call a
function that also includes various safeguards:
S = setupOperatorsTPFA(G,rock);
S =
T_all: [220x1 double]
T: [180x1 double]
C: [180x100 double]
Grad: @(x)-C*x
Div: @(x)C’*x
:
64 / 117
Automatic differentiation

Discretization of flow models leads to large system of (non)linear


equations. Can be linearized and solved with Newton’s method
∂F i i+1
F (x) = 0 ⇒ (x )(x − xi ) = −F (xi )
∂x
Coding necessary Jacobians is time-consuming and error prone

Automatic differentiation
Idea: keep track of variables and derivatives simultaneously
Any code, regardless of complexity, can be broken down to a limited
set of arithmetic operations (+, −, ∗, /,. . . ) and elementary functions
(sin, exp, power, . . . )
Derivative rules are known for these operations and functions
Combine these with the chain rule

65 / 117
Automatic differentiation

Consider a scalar primary variable x and a function f (x), whose AD


representations are the pairs hx, 1i and hf, fx i
Must define the action of elementary operations and functions on all
such pairs:
hf, fx i + hg, gx i = hf + g, fx + gx i ,
hf, fx i hg, gx i = hf g, f gx + fx gi ,
exp hhf, fx ii = hexp hf i , exp hf i fx i ,
sin hhf, fx ii = hsin hf i , cos hf i fx i ,

Use operator overloading to write a + b ∗ c rather than awkward


constructs like myPlus(a,myTimes(b,c))
Goal: make code as close as possible to mathematical description of
model

66 / 117
Implementation of AD in MRST

[x,y] = initVariablesADI(1,2);
z = 3*exp(−x*y)

x = ADI Properties: y = ADI Properties: z = ADI Properties:


val: 1 val: 2 val: 0.4060
jac: {[1] [0]} jac: {[0] [1]} jac: {[-0.8120] [-0.4060]}

∂x ∂x ∂y ∂y ∂z ∂z
∂x ∂y ∂x ∂y ∂x x=1,y=2 ∂y x=1,y=2

MRST implementation tailored to reservoir simulation and MATLAB:


designed to be efficient for vector variables more than scalars
works with sub-Jacobians rather than full Jacobians to simplify
subsequent manipulation

67 / 117
Applying AD to incompressible flow

First, we write the flow equation as a residual:



F (p) = ∇ · K∇p + q = 0

In discrete form:

F (p) = div T grad(p) + q = Ap + q = 0

Apply Newton’s method with a zero initial guess:


∂F 
(p) p − 0 = −F (0) ⇔ Ap = −q
∂p
Using AD means that we never need to form A explicitly

68 / 117
Solving the Poisson equation: −∆p = q

% Grid and grid information


G = cartGrid([5 5]);
G = computeGeometry(G);
rock = makeRock(G, 1, 1); ∂
∂x
nc = G.cells.num;
C=
% Operators
S = setupOperatorsTPFA(G,rock); ∂
spy(S.C); ∂y

% Assemble and solve equations


p = initVariablesADI(zeros(nc,1));
q = zeros(nc, 1); % source term
q([1 nc]) = [1 −1]; % quarter five −spot

eq = S.Div(S.Grad(p))+q; % equation
eq(1) = eq(1) + p(1); % make solution unique
p = −eq.jac{1}\eq.val; % solve equation
plotCellData(G,p);

69 / 117
Solving the Poisson equation: non-rectangular domain

% Grid and grid information


G = computeGeometry(cartGrid([20 20], [1 1]));
r1 = sum(bsxfun(@minus, G.cells.centroids ,[0 .5 1]) . ˆ2,2);
r2 = sum(bsxfun(@minus, G.cells.centroids ,[0 .5 0]) . ˆ2,2);
G = extractSubgrid(G, (r1>0.16) & (r2>0.16));
rock = makeRock(G, 1, 1);

nc = G.cells.num; ∂x

% Operators
S = setupOperatorsTPFA(G,rock);
spy(S.C); ∂
∂y

% Assemble and solve equations


p = initVariablesADI(zeros(nc,1));
q = zeros(nc, 1); % source term
q([1 nc]) = [1 −1]; % quarter five −spot

eq = S.Div(S.Grad(p))+q; % equation
eq(1) = eq(1) + p(1); % make solution unique
p = −eq.jac{1}\eq.val; % solve equation
plotCellData(G,p);

70 / 117
Solving the Poisson equation: unstructured grid

% Grid and grid information


load seamount
G = pebi( triangleGrid ([ x (:) y (:)]));
G = computeGeometry(G);
rock = makeRock(G, 1, 1);
nc = G.cells.num;

% Operators
S = setupOperatorsTPFA(G,rock);
spy(S.C);

% Assemble and solve equations


p = initVariablesADI(zeros(nc,1));
q = zeros(nc, 1)
q([135 282 17]) = [−1 .5 .5 ];

eq = S.Div(S.T.*S.Grad(p))+q;
eq(1) = eq(1) + p(1);
p = −eq.jac{1}\eq.val;
plotCellData(G,p);

71 / 117
Switching between different dicretization schemes

Discretization schemes: represented in terms of discrete divand gradoperators,


u · K−1~v .
R
and some discrete representation of a bilinear form, e.g., (~
u, ~v ) = ~
As example, consider: ∇·~
u = q, u = −K∇p
~

Two-point flux approximation (TPFA)


Given a vector Ttp of transmissibilities, the coded equations become

v = −T_tp.*grad(p)
←→ eq = div(T_tp.*grad(p))+q;
eq = div(v)−q;

Multi-point flux approximation (MPFA)


Given a matrix Tmp of transmissibilities, the coded equations become

v = −T_mp*grad(p)
←→ eq = div(T_mp*grad(p))+q;
eq = div(v)−q;

72 / 117
Switching between different dicretization schemes, cont’d

Same example: ∇·~


u = q, u = −K∇p
~

Lowest order mixed (or mimetic) formulation


~i · K−1 ψ
~j , one may be tempted to code the
R
Given a matrix M with mij ≈ ψ
equations as
v = −M\grad(p);
eq = div(v)−q;

... will work but involves applying M −1 to the nf × nc grad-matrix. Instead let flux v
be primary variable, and solve for both v and p:
[v,p] = initVariablesADI(zeros(nf, 1), zeros(nc, 1));
eq{1} = M*v+grad(p); % Darcy's law
eq{2} = div(v)−q; % continuity equation
eq = cat(eq{:}); % concatenate equations
x = −eq.jac{1}\eq.val; % solve, x contains both v and p

73 / 117
More advanced problems

You can continue to expand these examples with more effects:


buoyancy effects and fluid viscosity
source terms and boundary conditions
well models
multiphase mobilities
transmissibility multipliers
...
Eventually, the code will become quite involved and you will need to
encapsulate your implementation inside functions (or objects)
This is done in the incomp family of solvers:
incompTPFA, incompMimetic, incompMPFA,...

74 / 117
Assembly of linear equation in incomp solvers

Automatic differentiation and discrete operators are new ideas in MRST.


The incomp solver family uses mechanical assembly. For TPFA:
We sum the transmissibilities of all faces to create the diagnonal:
d = accumarray([C(:,1); C (:,2)], repmat(T ,[2,1]),[ nc, 1]);

Then, we construct the discrete matrix


I = [C (:,1); C (:,2); (1:nc )'];
J = [C (:,2); C (:,1); (1:nc )'];
V = [−T; −T; d]; clear d;
A = sparse(double(I), double(J), V, nc, nc);

Assuming we know the right-hand side, we can solve the flow


equation:
A(1) = 2*A(1); % Set p=0 in cell #1 if only Dirichlet b.c
p = mldivide(A, rhs);

75 / 117
Basic data structures in simulation models

Fluid properties:
fluid = initSingleFluid('mu' , 1*centi*poise, ...
' rho ' , 1014*kilogram/meterˆ3);

Reservoir states (physical variables):


state = initResSol(G, p0, s0);
state = initState(G, W, p0, s0);

Fluid sources
src = addSource(src, cells, rates);
src = addSource(src, cells, rates, 'sat' , sat);

76 / 117
Basic data structures in simulation models

Boundary conditions
bc = addBC(bc, faces, type, values);
bc = addBC(bc, faces, type, values, ' sat ' , sat);

For grids having logical IJK numbering:


bc = pside(bc, G, side, p);
bc = fluxside(bc, G, side, flux)

where side would be 1/’West’/’XMin’/’Left’, etc


Wells with Peacemann well model:
W = addWell(W, G, rock, cellInx);
W = addWell(W, G, rock, cellInx, ' pn' , pv, ... );

For convenience, we also have the functions


W = verticalWell(W, G, rock, I, J, K)
W = verticalWell(W, G, rock, I, K)

77 / 117
Incompressible flow solvers in MRST

The three main solvers available are:


The standard two-point solver:
mrstModule add incomp;
hT = computeTrans(G, rock);
state = incompTPFA(state, G, hT, fluid, ... );

Lowest-order mimetic finite-difference methods:


mrstModule add mimetic;
IP = computeMimeticIP(G, rock);
state = incompMimetic(state, G, IP, fluid, ... );

The MPFA-O multipoint flux-approximation method:


mrstModule add mpfa;
hT = computeMultiPointTrans(G, rock);
state = incompMPFA(state, G, hT, fluid)

78 / 117
Example: quarter five-spot with source terms
gravity reset off
[nx,ny] = deal(20);
G = cartGrid([nx,ny ],[500,500]);
G = computeGeometry(G);
rock = makeRock(G, 100*milli*darcy, .2);
hT = computeTrans(G, rock);

fluid = initSingleFluid('mu' , 1*centi*poise, ...


' rho ' , 1014*kilogram/meterˆ3);

pv = sum(poreVolume(G,rock));
src = addSource([], 1, pv);
src = addSource(src, G.cells.num, −pv);

state = initResSol(G, 0.0, 1.0);


state = incompTPFA(state, G, hT, fluid, ' src ' , src);
plotCellData(G, state.pressure);
plotGrid(G, src.cell, 'FaceColor ' , ' w' );

mrstModule add streamlines;


seed = (nx:nx−1:nx*ny).';
Sf = pollock(G, state, seed, ' substeps ' , 1);
Sb = pollock(G, state, seed, ' substeps ' , 1, ' reverse ' , true);
h=streamline([Sf; Sb]); set(h, ' Color ' , ' k ' );
79 / 117
Example: horizontal and vertical well
[nx,ny,nz] = deal(20,20,5);
G = cartGrid([nx,ny,nz], [500 500 25])
G = computeGeometry( );
:
hT = computeTrans(G, rock);

W = verticalWell([], G, rock, 1, 1, 1:nz, ...


' Type' , ' rate ' , ' Comp i', 1, ...

' Val ' , 3e3/day, ... .

' Radius ' , .12*meter, 'name', ' I ' );

W = addWell(W, G, rock, nx : ny : nx*ny, ...


' Type' , ' bhp' , ' Comp i', 1, ...

' Val ' , 1.0e5, ' Radius ' , .12*meter, ...

' Dir ' , ' y ' , ' name', ' P' );

gravity reset on;


state = initState(G, W, 0);
state = incompTPFA(state, G, hT, fluid, ' wells ' , W);

plotCellData(G, state.pressure,'EdgeAlpha',.01,'FaceAlpha',.4);
plotWell(G, W(1), ' radius ' , 1, ' color ' , ' r ' );
plotWell(G, W(2), ' radius ' , .5, ' color ' , ' b ' );
view(3), camproj perspective, axis tight off
80 / 117
Computer exercises

Run the quarter five-spot example with the following modifications:


(1) Replace the Cartesian grid by a curvilinear grid, e.g., use twister or a
random perturbation of internal nodes as shown in the lectures. Do you
see differences if you replace TPFA with mimetic of MPFA?
(2) Set the domain to be a single layer of the SPE 10 model. Hint: use
getSPE10rock() to sample the petrophysical parameters.
Notice that pollock may not work for non-Cartesian grids and you may wish to
compute time-of-flight instead using the diagnostics module.

Pick a bed model from BedModels1 or BedModel2. Compute flow


subject to linear pressure drop first in the x and then in the y-direction.
A unit pressure drop is the most wide-spread computational setup used
for flow-based upscaling.

Explore the many tutorial examples found in mrst-core, incomp and


mrst-book/1phase

81 / 117
Outline

1 Introduction

2 Getting started with MRST

3 Grids and petrophysical data

4 Incompressible flow

5 Multiphase flow

6 Compressible flow

7 The AD-OO framework in MRST

82 / 117
What you will learn in this section

In this section, we study incompressible, two-phase flow


You will learn about:
discretizing the transport equation on unstructured grids
nonlinear solution strategy (Newton–Raphson, time-step control)
implementation in MRST

To learn more:
– study the 2ph tutorials/examples in the incomp module
– read Chapters 8 to 10 in the MRST book

83 / 117
Two-phase, incompressible flow

The solvers of the incomp family are designed to solve two-phase models
consisting of an elliptic pressure equation

∇ · ~v = q, ~v = −λ ∇pn − fw ∇Pc − (ρw fw + ρn fn )g∇z

and a hyperbolic/parabolic transport equation

∂Sw  
φ + ∇ · fw ~v + λn (∆ρg∇z + ∇Pc ) = qw
∂t

84 / 117
Two-phase, incompressible flow

The solvers of the incomp family are designed to solve two-phase models
consisting of an elliptic pressure equation

∇ · ~v = q, ~v = −λ ∇pn − fw ∇Pc − (ρw fw + ρn fn )g∇z

and a hyperbolic/parabolic transport equation

∂Sw  
φ + ∇ · fw ~v + λn (∆ρg∇z + ∇Pc ) = qw
∂t

Standard approach – sequential solution procedure:


Compute initial state and set t = 0
While t < T
Fix Sw and solve elliptic pressure equation
Fix p and ~v and solve transport equation a time ∆t
t = t + ∆t

84 / 117
Two-phase, incompressible flow

The solvers of the incomp family are designed to solve two-phase models
consisting of an elliptic pressure equation

∇ · ~v = q, ~v = −λ ∇pn − fw ∇Pc − (ρw fw + ρn fn )g∇z

and a hyperbolic/parabolic transport equation

∂Sw  
φ + ∇ · fw ~v + λn (∆ρg∇z + ∇Pc ) = qw
∂t

For the pressure equation, we use same methods as discussed above with
obvious modifications. Solvers implemented for multiphase elliptic
pressure equation:
incompTPFA, incompMimetic, incompMPFA,...
The only changes are in how mobility and right-hand side are computed

84 / 117
Two-phase, incompressible flow

The solvers of the incomp family are designed to solve two-phase models
consisting of an elliptic pressure equation

∇ · ~v = q, ~v = −λ ∇pn − fw ∇Pc − (ρw fw + ρn fn )g∇z

and a hyperbolic/parabolic transport equation

∂Sw  
φ + ∇ · fw ~v + λn (∆ρg∇z + ∇Pc ) = qw
∂t

For the transport equation, we have two different solvers:


state = explicitTransport(state, G, tf, rock, fluid, 'mech1', obj1, ... )
state = implicitTransport(state, G, tf, rock, fluid, 'mech1', obj1, ... )

designed to work on fully unstructured grids, but only implemented for


two-phase flow

84 / 117
~
Discretization of φSt + ∇ · H(S) =0

Flux H~ incorporates effects of viscous, Γi,k


gravity, and capillary forces:
pi pk
λw λn K
~ Ωi

H(S) = f (s)~v + ∆ρ ~g + ∇Pc (S) ~
ci,k
λw + λn ~
ni,k
Ωk
= H~f (S) + H~g (S) + H
~ c (S). ~
g

85 / 117
~
Discretization of φSt + ∇ · H(S) =0

Flux H~ incorporates effects of viscous, Γi,k


gravity, and capillary forces:
pi pk
λw λn K
~ Ωi

H(S) = f (s)~v + ∆ρ ~g + ∇Pc (S) ~
ci,k
λw + λn ~
ni,k
Ωk
= H~f (S) + H~g (S) + H
~ c (S). ~
g

Integrated over cell Ωi and in time

1 X tn+1
Z Z
n+1 n ~ S(~x, t) · ~ni,k ds dt

Si − Si = H
φi |Ωi | tn Γik
k

85 / 117
~
Discretization of φSt + ∇ · H(S) =0

Flux H~ incorporates effects of viscous, Γi,k


gravity, and capillary forces:
pi pk
λw λn K
~ Ωi

H(S) = f (s)~v + ∆ρ ~g + ∇Pc (S) ~
ci,k
λw + λn ~
ni,k
Ωk
= H~f (S) + H~g (S) + H
~ c (S). ~
g

Integrated over cell Ωi and in time

1 X tn+1
Z Z
n+1 n ~ S(~x, t) · ~ni,k ds dt

Si − Si = H
φi |Ωi | tn Γik
k

For first-order methods, we can evaluate integral at end-points:


∆t
Z
n+1 n ~ S(~x, tm ) · ~ni,k ds,

Si − Si = H m = n, n + 1
φi |Ωi | Γik

85 / 117
~
Discretization of φSt + ∇ · H(S) =0

Flux H~ incorporates effects of viscous, Γi,k


gravity, and capillary forces:
pi pk
λw λn K
~ Ωi

H(S) = f (s)~v + ∆ρ ~g + ∇Pc (S) ~
ci,k
λw + λn ~
ni,k
Ωk
= H~f (S) + H~g (S) + H
~ c (S). ~
g

For first-order methods, we can evaluate integral at end-points:


∆t
Z
Sin+1 − Sin = ~ S(~x, tm ) · ~ni,k ds,

H m = n, n + 1
φi |Ωi | Γik

Capillary term is discretized using the TPFA method:


−1 −1
 −1  
Ai,k ∇Pc (S) · ~ni,k ≈ Ti,k + Tk,i Pc (Si ) − Pc (Sk ) = Pi,k (S)

85 / 117
~
Discretization of φSt + ∇ · H(S) =0

Flux H~ incorporates effects of viscous, Γi,k


gravity, and capillary forces:
pi pk
λw λn K
~ Ωi

H(S) = f (s)~v + ∆ρ ~g + ∇Pc (S) ~
ci,k
λw + λn ~
ni,k
Ωk
= H~f (S) + H~g (S) + H
~ c (S). ~
g

For first-order methods, we can evaluate integral at end-points:


∆t
Z
Sin+1 − Sin = ~ S(~x, tm ) · ~ni,k ds,

H m = n, n + 1
φi |Ωi | Γik

We define a “gravity flux” gik that is independent of saturation:


 −1 −1 −1
 gi,k = (∆ρ)|Ωi Ki~g · ~ni,k ,
gik = gi,k + gk,i ,
gk,i = (∆ρ)|Ωk Kk~g · ~nk,i

85 / 117
~
Discretization of φSt + ∇ · H(S) =0

Flux H~ incorporates effects of viscous, Γi,k


gravity, and capillary forces:
pi pk
λw λn K
~ Ωi

H(S) = f (s)~v + ∆ρ ~g + ∇Pc (S) ~
ci,k
λw + λn ~
ni,k
Ωk
= H~f (S) + H~g (S) + H
~ c (S). ~
g

Summing up, we have:


λuw λuw λun  
Hik = u u
v ik + u u
gik + Pik
λw + λn λw + λn

where λuw and λun are upstream-evaluated phase mobilities

85 / 117
~
Discretization of φSt + ∇ · H(S) =0

Flux H~ incorporates effects of viscous, Γi,k


gravity, and capillary forces:
pi pk
λw λn K
~ Ωi

H(S) = f (s)~v + ∆ρ ~g + ∇Pc (S) ~
ci,k
λw + λn ~
ni,k
Ωk
= H~f (S) + H~g (S) + H
~ c (S). ~
g

Summing up, we have:


λuw λuw λun  
Hik = u u
v ik + u u
gik + Pik
λw + λn λw + λn

where λuw and λun are upstream-evaluated phase mobilities


If sign of vik and gik + Pik is different, choose mobilities from opposite
sides. Otherwise, check sign of vik + λα (gik + Pik ) for α = w, n

85 / 117
Implementation in MRST
Explicit scheme: S n+1 = S n − F (S n , S n ). Implicit scheme: F(S n+1 , S n ) = 0
∆t X 
Fi (s, r) = si − ri + Hik (s) − max(qi , 0) − min(qi , 0)f (Si )
φi |Ωi | k

λuw (si , sk )
+ λu

Hik (s) = vik n (si , sk )(gik + Pik )]
λw (si , sk ) + λu
u
n (s i , s k )

86 / 117
Implementation in MRST
Explicit scheme: S n+1 = S n − F (S n , S n ). Implicit scheme: F(S n+1 , S n ) = 0
∆t X 
Fi (s, r) = si − ri + Hik (s) − max(qi , 0) − min(qi , 0)f (Si )
φi |Ωi | k

λuw (si , sk )
+ λu

Hik (s) = vik n (si , sk )(gik + Pik )]
λw (si , sk ) + λu
u
n (s i , s k )

To avoid code duplication, the residual form F and its Jacobian J = dF


are computed in a private helper function:
[F,Jac] = twophaseJacobian(G, state, rock, fluid, 'pn1', pv1, ... )

Code is quite complex since Jacobian is computed explicitly (this was


developed before AD was introduced in MRST)

86 / 117
Implementation in MRST
Explicit scheme: S n+1 = S n − F (S n , S n ). Implicit scheme: F(S n+1 , S n ) = 0
∆t X 
Fi (s, r) = si − ri + Hik (s) − max(qi , 0) − min(qi , 0)f (Si )
φi |Ωi | k

λuw (si , sk )
+ λu

Hik (s) = vik n (si , sk )(gik + Pik )]
λw (si , sk ) + λu
u
n (s i , s k )

Explicit transport solver:


F = twophaseJacobian(G, state, rock, fluid, 'wells ' , opt.wells, ... );
s = state.s(:,1);
t = 0;
while t < tf,
dt = min(tf−t, getdt(state));
s (:) = s − F(state, state, dt);
t = t + dt;
s = correct_saturations(s, opt.satwarn);
state.s = [s, 1−s];
end

86 / 117
Implementation in MRST
Explicit scheme: S n+1 = S n − F (S n , S n ). Implicit scheme: F(S n+1 , S n ) = 0
∆t X 
Fi (s, r) = si − ri + Hik (s) − max(qi , 0) − min(qi , 0)f (Si )
φi |Ωi | k

λuw (si , sk )
+ λu

Hik (s) = vik n (si , sk )(gik + Pik )]
λw (si , sk ) + λu
u
n (s i , s k )

Implicit solver uses a Newton method:

0 = F (s0 + δs) ≈ F (s0 ) + J (s0 )δs,

J (s` ) δs`+1 = −F (s` ), s`+1 ← s` + δs`+1

86 / 117
Implementation in MRST
Explicit scheme: S n+1 = S n − F (S n , S n ). Implicit scheme: F(S n+1 , S n ) = 0
∆t X 
Fi (s, r) = si − ri + Hik (s) − max(qi , 0) − min(qi , 0)f (Si )
φi |Ωi | k

λuw (si , sk )
+ λu

Hik (s) = vik n (si , sk )(gik + Pik )]
λw (si , sk ) + λu
u
n (s i , s k )

Implicit solver uses a Newton method:

0 = F (s0 + δs) ≈ F (s0 ) + J (s0 )δs,

J (s` ) δs`+1 = −F (s` ), s`+1 ← s` + δs`+1


To get saturation values in [0, 1], we need to introduce a line-search
method that uses p` = δs`+1 as search direction. MRST uses an inexact
method that asks for a sufficient decrease in F (s` + α p` ) and reduces α
in a geometric sequence.

86 / 117
Time-step control
mints = pow2(tf, −opt.tsref);
[t, dt] = deal(0.0, tf);
while t < tf && dt >= mints,
dt = min(dt, tf − t);
redo_newton = true;
while redo_newton,
sn_0 = resSol; sn = resSol; sn.s(:) = min(1,sn.s+0.05);
res = F(sn, sn_0, dt);
err = norm(res(:), inf);
[nwtfail, linfail, it] = deal(err>opt.nltol,false,0);
while nwtfail && ∼linfail && it < opt.maxnewt,
J = Jac(sn, sn_0, dt);
ds = −reshape(opt.LinSolve(J, reshape(res', [], 1)), ns, [])';
[sn, res, alph, linfail] = update(sn, sn_0, ds, dt, err);
it = it + 1;
err = norm(res(:), inf);
nwtfail = err > opt.nltol;
end
if nwtfail,
% Chop time step in two, or use previous successful dt
else
redo_newton = false;
t = t + dt;
% If five successful steps , increase dt by 50%
end
end
resSol = sn;
end
87 / 117
Example: Buckley–Leverett displacement
G = computeGeometry(cartGrid([100,1]));
rock = makeRock(G, 100*milli*darcy, 0.2);
fluid = initSimpleFluid('mu' , [1, 1].*centi*poise, ...
' rho ' , [1000, 1000].*kilogram/meterˆ3, 'n', [2,2]);

bc = fluxside([], G, ' Left ' , 1, ' sat ' , [1 0]);


bc = fluxside(bc, G, 'Right ' , −1, ' sat ' , [0 1]);
hT = computeTrans(G, rock);
rSol = initState(G, [], 0, [0 1]);
rSol = incompTPFA(rSol, G, hT, fluid, ' bc ' , bc);
rSole = explicitTransport(rSol, G, 10, rock, fluid, 'bc', bc, ' verbose ' ,true);

1
Expl: 199 steps
0.9 n= 4: 47 its
n= 10: 65 its
0.8 n= 20: 102 its
n= 40: 161 its
0.7 n=100: 301 its
n=200: 407 its
0.6

0.5

0.4

0.3

0.2

0.1

0
0 10 20 30 40 50 60 70 80 90 100 88 / 117
Example: inverted gravity column

gravity reset on
G = cartGrid([1, 1, 40], [1, 1, 10]);
G = computeGeometry(G);
rock = makeRock(G, 0.1*darcy, 1);
fluid = initCoreyFluid(...
' mu' , [0.30860, 0.056641]*centi*poise, ...

' rho ' , [975.86,686.54]*kilogram/meterˆ3, ...

' n ' , [2,2], ' sr ' , [.1,.2 ], ' kwm',[.2142,.85]);

hT = computeTrans(G, rock);

xr = initResSol(G, 100.0*barsa, 1.0);


xr.s(end/2+1:end) = 0.0;

xr = incompTPFA(xr, G, hT, fluid);


dt = 5*day; t=0;
for i=1:150
xr = explicitTransport(xr, G, dt, rock, fluid, 'onlygrav ' , true);
t = t+dt;
xr = incompTPFA(xr, G, hT, fluid);
end

89 / 117
Example: inverted gravity column
t

t = 0 days t = 250 days t = 500 days

t = 125 days t = 375 days t = 750 days


90 / 117
Potential pitfall: capillary-dominated flow

0
10

−1
10

−2
10

−3
10

−4
10
∆ t = 36.50 days
∆ t = 54.75 days
−5
10
0 1 2 3 4 5 6 7 8 9

91 / 117
Outline

1 Introduction

2 Getting started with MRST

3 Grids and petrophysical data

4 Incompressible flow

5 Multiphase flow

6 Compressible flow

7 The AD-OO framework in MRST

92 / 117
What you will learn in this section

In this section, we study compressible single-phase and multiphase flow


You will learn about:
rapid prototyping of new models using AD
use of discrete operators for compact implementations
the AD-OO framework

To learn more:
– study examples/tutorials in the ad-core and ad-blackoil modules
– read Chapter 9 in the MRST book
– read Krogstad et al. (SPE RSS, 2015), doi: 10.2118/173317-MS
– read Bao et al. (COMG, 2017), doi: 10.1007/s10596-017-9624-5

93 / 117
Single-phase weakly compressible flow

The governing equation is


∂p
c − ∇ · ((K/µ)∇p) = 0
∂t
Semi-discrete flow equations on residual form with implicit time
discretization and discrete operators div, grad.

1 K n+1
c(pn+1 − pn ) − div grad(p) =0
∆t µ

presEq = @(p, p0, dt) (1/dt)*c*(p−p0) − div( (T/mu).*grad(p));

current time step previous time step

94 / 117
Single-phase weakly compressible flow
load seamount
G = pebi(triangleGrid([x(:) y (:)]));
G.nodes.coords = G.nodes.coords*100;
:
c = 1e−4;
mu = 1*centi*poise;

presEq = @(p, p0, dt) ...


(1/dt)*c*(p−p0) − div( (T/mu).*grad(p));

p0 = 100*atm*ones(nc, 1); p0(r<5) = 200*atm;


p = initVariablesADI(p0);
[t,T,dt] = deal(0,10*day,hour);
while t < T,
t = t + dt;
p0 = p.val;

eq = presEq(p, p0, dt);


p.val = p.val −(eq.jac{1} \ eq.val);

clf, plotCellData(G,p.val);
caxis([100 200]*atm); drawnow;
end

95 / 117
Single-phase compressible flow

Weakly compressible model: Model with rock and fluid compressibility:


∂p ∂
c − ∇ · (K∇p) = 0 (φρ) − ∇ · (ρK∇p) = 0
∂t ∂t
% Fluid properties % Rock property
c = 1e−4; [phi0,c_r,pr] = deal(0.3, 1e−3, 1*atm);
mu = 1*centi*poise; phi = @(p) ..
phi0 + (1−phi0)*(1−exp(−c_r*(p−pr)));

% Fluid properties
rho0 = 10ˆ3; c_f = 5e−5;
rho = @(p) (rho0*exp(c_f*(p − pref)));
mu = 1*centi*poise;

% Set up equation % Set up equation


presEq = @(p, p0, dt) ... pv = @(p) (phi(p). * G.cells.volumes );
(1/dt)*c*(p−p0) − div((T/mu).*grad(p)); presEq = @(p, p0, dt) ...
(1/dt)*(pv(p). *rho(p) − pv(p0).*rho(p0)) ...
−div(avg(rho(p)).*(T/mu).*grad(p));

avg is a face-average operator: Rnc → Rnf

96 / 117
Adding effects: gravity

Semi-discrete flow equations on residual form:


1 K
[(φρ)n+1 −(φρ)n ]+div(ρv)n+1 = q,

v=− grad(p)−gρ grad(z)
∆t µ

Homogeneous equation implemented in MRST


gradz = grad(G.cells.centroids(:,3));
v = @(p) −(T/mu).*( grad(p) − g*avg(rho(p)).*gradz );

presEq = @(p, p0, dt) (1/dt)*(pv(p).*rho(p) − pv(p0).*rho(p0)) ...


+ div( avg(rho(p)).*v(p));

97 / 117
Adding effects: gravity

Semi-discrete flow equations on residual form:


1 K
[(φρ)n+1 −(φρ)n ]+div(ρv)n+1 = q,

v=− grad(p)−gρ grad(z)
∆t µ

Homogeneous equation implemented in MRST


gradz = grad(G.cells.centroids(:,3));
v = @(p) −(T/mu).*( grad(p) − g*avg(rho(p)).*gradz );

presEq = @(p, p0, dt) (1/dt)*(pv(p).*rho(p) − pv(p0).*rho(p0)) ...


+ div( avg(rho(p)).*v(p));

current time step ρ at cell face

previous time step

97 / 117
Adding effects: well model and controls
Peacemann well model, with hydrostatic pressure in well bore, and
control on bottom-hole pressure:
pc = pbh + g ∆zc ρ(pbh ),
ρ
pbh
qc = WI(pc − p),
µ
1 X qc
qS = S qc ,
ρ c
pbh = constant
Implemented in MRST:
wc = W(1).cells; % connection grid cells
WI = W(1).WI; % well−indices
dz = W(1).dZ; % connection depth relative to bottom−hole

p_conn = @(bhp) bhp + g*dz.*rho(bhp);


q_conn = @(p, bhp) WI.*(rho(p(wc))/mu).*(p_conn(bhp) − p(wc));
rateEq = @(p, bhp, qS) qS−sum(q_conn(p, bhp))/rhoS;
ctrlEq = @(bhp) bhp−100*barsa;

98 / 117
Details of simulator: time loop and assembly of equations

[p, bhp, qS] = ...


initVariablesADI(pin, pin(wc(1)), 0);
t = 0; step = 0;
while t < totTime,
t = t + dt;

% Newton loop
resNorm = 1e99;
p0 = double(p); % Previous step pressure
nit = 0;
while (resNorm > tol) && (nit < maxits)
% one Newton iteration
end

if nit > maxits,


error('Newton solves did not converge ' )
end
end

99 / 117
Details of simulator: time loop and assembly of equations

% −− ONE NEWTON ITERATION


% Add source terms to homogeneous pressure equation:
eq1 = presEq(p, p0, dt);
[p, bhp, qS] = ... eq1(wc) = eq1(wc) − q_conn(p, bhp);
initVariablesADI(pin, pin(wc(1)), 0);
t = 0; step = 0;
while t < totTime, % Collect all equations
t = t + dt; eqs = {eq1, rateEq(p, bhp, qS), ctrlEq(bhp)};

% Newton loop % Concatenate equations and solve for update:


resNorm = 1e99; eq = cat(eqs{:});
p0 = double(p); % Previous step pressure
nit = 0;
J = eq.jac{1}; % Jacobian
while (resNorm > tol) &&res(nit
= eq.val;
< maxits) % residual
% one Newton iterationupd = −(J \ res); % Newton update
end
% Update variables
if nit > maxits,
p.val = p.val + upd(pIx);
error('Newton solves did not converge ' )
end bhp.val = bhp.val + upd(bhpIx);
end qS.val = qS.val + upd(qSIx);

resNorm = norm(res);
nit = nit + 1;

99 / 117
Adding effects: pressure-dependent viscosity

Assume the following model:

µ(p) = µ0 [1 + cr (p − pr )]

100 / 117
Adding effects: pressure-dependent viscosity

Assume the following model:

µ(p) = µ0 [1 + cr (p − pr )]

Arithmetic averaging:
mu = @(p) mu0*(1+c mu*(p−pr));
v = @(p) −(T./mu(avg(p))).*(grad(p) − g*avg(rho(p)).*dz);

qcon = @(p,bhp) WI.*(rho(p(wc))./mu(p(wc))).*(pcon(bhp)−p(wc));

This is all! No need to recompute derivatives for Newton’s method


Unfortunately, this approach is only correct on Cartesian grids

100 / 117
Adding effects: pressure-dependent viscosity

Assume the following model:

µ(p) = µ0 [1 + cr (p − pr )]

Harmonic averaging:
[cn,F] = getCellNoFaces(G);
hf2f = sparse(F ,(1: numel(cn ))',1);
hf2f = hf2f( all (C∼=0,2),:);
fmob = @(mu,p) 1./( hf2f*(mu(p(cn))./hT) )

v = @(p) −fmob(mu,p).*(grad(p) − g*avg(rho(p)).*dz);

We multiply each one-sided transmissibility Ti,k by the correct µ(p) value


and then compute their harmonic average
Previously, we used accumarray to average Ti,k , but this function does not work for
AD variables. Hence, we multiply by a sparse matrix instead

100 / 117
Adding effects: thermal flow

∂     K  
φρ(p, T ) + ∇ · ρ(p, T )~v = q, ~v = − ∇p − gρ(p, T )∇z
∂t µ(p, T )
∂      
φρ(p, T )Ef (p, t) + (1 − φ)Er (p, T ) + ∇ · ρ(p, T )Hf (p, T )~v − ∇ · κ∇T = qe
∂t

Constitutive laws and operators Discrete equations

pvr = poreVolume(G, rock);


v = @(p,T) -(Tr./mu(avg(p),avg(T))) ...
pv = @(p) pvr .* exp( cr * (p - pr) );
.*( grad(p) - g*avg(rho(p,T)).*dz );
spv = @(p) G.cells.volumes - pv(p);
:
pEq = @(p,T, p0, T0, dt) ...
rho = @(p,T) rhor.*(1+(cp*(p - pr))).*exp(-ct*(T-Tr));
(1/dt)*(pv(p).*rho(p,T) - pv(p0).*rho(p0,T0)) ...
mu = @(p,T) mu0*(1+cmup*(p-p_r)).*exp(-cmut*(T-T_r));
+ div( avg(rho(p,T)).*v(p,T) );
:
Hf = @(p,T) Cw*T + (1-Tr*ct).*(p-pr)./rho(p,T);
hEq = @(p, T, p0, T0, dt) ...
Ef = @(p,T) Hf(p,T) - p./rho(p,T);
(1/dt)*( pv(p).*rho(p,T).*Ef(p,T) + spv(p).*Er(T)
Er = @(T) Cr*T;
- pv(p0).*rho(p0,T0).*Ef(p0,T0) - spv(p0).*Er(T0)) ...
:
+ div( upw(Hf(p,T),v(p,T)>0).*avg(rho(p,T)).*v(p,T) )...
upw = @(x,flag) x(N(:,1)).*double(flag) ...
+ div( -Th.*grad(T));
+ x(N(:,2)).*double(~flag);

101 / 117
Adding effects: thermal flow

∂     K  
φρ(p, T ) + ∇ · ρ(p, T )~v = q, ~v = − ∇p − gρ(p, T )∇z
∂t µ(p, T )
∂      
φρ(p, T )Ef (p, t) + (1 − φ)Er (p, T ) + ∇ · ρ(p, T )Hf (p, T )~v − ∇ · κ∇T = qe
∂t

Constitutive laws and operators Discrete equations

pvr = poreVolume(G, rock);


v = @(p,T) -(Tr./mu(avg(p),avg(T))) ...
pv = @(p) pvr .* exp( cr * (p - pr) );
.*( grad(p) - g*avg(rho(p,T)).*dz );
spv = @(p) G.cells.volumes - pv(p);
:
pEq = @(p,T, p0, T0, dt) ...
rho = @(p,T) rhor.*(1+(cp*(p - pr))).*exp(-ct*(T-Tr));
(1/dt)*(pv(p).*rho(p,T) - pv(p0).*rho(p0,T0)) ...
mu = @(p,T) mu0*(1+cmup*(p-p_r)).*exp(-cmut*(T-T_r));
+ div( avg(rho(p,T)).*v(p,T) );
:
Hf = @(p,T) Cw*T + (1-Tr*ct).*(p-pr)./rho(p,T);
hEq = @(p, T, p0, T0, dt) ...
Ef = @(p,T) Hf(p,T) - p./rho(p,T);
(1/dt)*( pv(p).*rho(p,T).*Ef(p,T) + spv(p).*Er(T)
Er = @(T) Cr*T;
- pv(p0).*rho(p0,T0).*Ef(p0,T0) - spv(p0).*Er(T0)) ...
:
+ div( upw(Hf(p,T),v(p,T)>0).*avg(rho(p,T)).*v(p,T) )...
upw = @(x,flag) x(N(:,1)).*double(flag) ...
+ div( -Th.*grad(T));
+ x(N(:,2)).*double(~flag);

Anonymous functions may lead to redundant function evaluations. To cure, move


computation of residuals inside a function and compute and store constitutive
relationships in temporary variables

101 / 117
Adding effects: multiple phases (without mass transfer)

(φS α ρα )n+1 − (φS α ρα )n


+ div(ρv)n+1
α = (ρq)n+1
α
∆tn
Kkrα
v n+1 = − n+1 grad(pn+1 ) − gρn+1
 
α α grad(z)
µα

102 / 117
Adding effects: multiple phases (without mass transfer)

(φS α ρα )n+1 − (φS α ρα )n


+ div(ρv)n+1
α = (ρq)n+1
α
∆tn
Kkrα
v n+1 = − n+1 grad(pn+1 ) − gρn+1
 
α α grad(z)
µα

We start by computing all cell-based properties:


% Densities and pore volumes
[rW,rW0,rO,rO0] = deal(rhoW(p), rhoW(p0), rhoO(p), rhoO(p0));
[vol, vol0] = deal(pv(p), pv(p0));

% Mobility: Relative permeability over constant viscosity


mobW = krW(sW)./muW;
mobO = krO(1−sW)./muO;

102 / 117
Adding effects: multiple phases (without mass transfer)

(φS α ρα )n+1 − (φS α ρα )n


+ div(ρv)n+1
α = (ρq)n+1
α
∆tn
Kkrα
v n+1 = − n+1 grad(pn+1 ) − gρn+1
 
α α grad(z)
µα

Next, we compute differences in phase pressure across cell interfaces:


dp = grad(p);
dpW = dp−g*avg(rW).*gradz;
dpO = dp−g*avg(rO).*gradz;

and use this to define upwind-weighted fluxes:


upw = @(flag, x) flag.*x(C(:, 1)) + ∼flag.*x(C(:, 2));

vW = −upw(double(dpW) <= 0, rW.*mobW).*T.*dpW;


vO = −upw(double(dpO) <= 0, rO.*mobO).*T.*dpO;

102 / 117
Adding effects: multiple phases (without mass transfer)

(φS α ρα )n+1 − (φS α ρα )n


+ div(ρv)n+1
α = (ρq)n+1
α
∆tn
Kkrα
v n+1 = − n+1 grad(pn+1 ) − gρn+1
 
α α grad(z)
µα

Now, we have all we need to compute residual equations


water = (1/dt(n)).*(vol.*rW.*sW − vol0.*rW0.*sW0) + div(vW);
oil = (1/dt(n)).*(vol.*rO.*(1−sW) − vol0.*rO0.*(1−sW0)) + div(vO);
eqs = {oil, water};
eq = cat(eqs{:});

∂O ∂O
∂p ∂Sw

∂W ∂W
∂p ∂Sw
102 / 117
Adding effects: multiple phases (without mass transfer)

(φS α ρα )n+1 − (φS α ρα )n


+ div(ρv)n+1
α = (ρq)n+1
α
∆tn
Kkrα
v n+1 = − n+1 grad(pn+1 ) − gρn+1
 
α α grad(z)
µα

To get a robust simulator, we would also need to include:


Time-step control inside the loop
A line-search algorithm rather than simple Newton
Possibly also some preconditioning method
Notice also that this code cannot be used to simulate incompressible flow.
Trick: add small rock compressibility.

102 / 117
Rapid prototyping in MRST

Use abstractions to express your ideas in a form close to the underlying


mathematics
The interactive environment offers you:
– ability to try out each operation and build program as you go
– wide range of built-in functions for numerical computations
– powerful data analysis, graphical user interface, and visualization
Easy to debug and modify/improve existing codes:
– run code line by line, inspect and change variables at any point
– step back and rerun parts of code with changed parameters
– add new behavior and data members while executing program
Later, one can, if necessary, replace bottleneck operations with accelerated
editions implemented in a compiled language

103 / 117
Outline

1 Introduction

2 Getting started with MRST

3 Grids and petrophysical data

4 Incompressible flow

5 Multiphase flow

6 Compressible flow

7 The AD-OO framework in MRST

104 / 117
Advanced simulators: motivation

So far in the lecture, we have seen how automatic differentiation can be


used to prototype simulators. Writing a single script has advantages:
fast to prototype
self-contained and easy to modify

However, there are some disadvantages as well:


mixing logic of Newton solver with definition of model equations
time-stepping and plotting will be done per script
implementing several variations of the same model will result in code
duplication

105 / 117
Advanced simulators: motivation

Code will eventually start to become complicated:


complex rock-fluid/PVT models
hysteretic behavior (post-iteration updates)
wells with advanced schedules and controls
time-step control and iteration control
CPR type preconditioners and multigrid solvers
advanced flow models that are extensions of simpler models
sub-equations with different discretizations, nested iterations, . . .

Bt
0.8

0.6

Bo
0.4

∂t (φbw Sw ) + ∇ · (bw ~
uw ) = bw q0.2
w

∂t [φ(bw So + bg rv Sg )]
pb+ ∇ · (b ~u
o o + bg r v ~
0
ug ) = bo q0o + bg rv0.2
qg 0.4 0.6 0.8 1

∂t [φ(bg Sg + bo rs So )]
+ ∇ · (bg ~
ug + bo rs ~
uo ) = bg qg + bo rs qo

106 / 117
Next step: object-orientation

Introduce object-orientation to separate:


physical models
discretizations and discrete operators
nonlinear solver and time-stepping
assembly and solution of the linear system

Only expose needed details and enable more reuse of functionality that
has already been developed

107 / 117
Next step: object-orientation

The object-oriented AD framework makes it easy to write general


simulator classes:
standardized interfaces make Newton solver independent of the
specifics of the physical model
standardized input/output makes it easy to compare and plot results
switching linear solvers or time-stepping strategy is straightforward
(Compare ad-blackoil and blackoil-sequential)

Typical workflow: build simple prototype → migrate to class-based solver

107 / 117
The AD-OO modules

MRST core mrst-gui deckformat


Basic functions/data structures: Graphical interfaces for interactive Input of ECLIPSE simulation
grid, petrophysics, wells, boundary visualization of reservoir states and decks: read, convert to SI units,
conditions, I/O, grid processing, petrophysical data and construct MRST objects for
AD library, plotting, . . . grids, fluid and rock properties,
wells and simulation schedules

ad-core ad-blackoil ad-props


General simulation framework: General 3-phase black-oil simulator Initialization of fluid models from
abstract model classes, time-step with dissolution and vaporization, ECLIPSE input decks
and iteration control, linearizations, specialized 1- and 2-phase models,
linear solvers, hooks for I/O and CPR preconditioning
plotting, . . .

core functionality
ad-eor
Fully implicit simulators for water- utility module
based EOR: polymer and surfac-
tant AD-OO module

108 / 117
Example: two-phase Buckley–Leverett

G = cartGrid([50, 1, 1], [1000, 10, 10]*meter);


G = computeGeometry(G);
rock = makeRock(1*darcy*ones, .3);
fluid = initSimpleADIFluid('phases', 'WO', 'n', [2 2]);

% Set up model and initial state.


model = TwoPhaseOilWaterModel(G, rock, fluid);
state0 = initResSol(G, 50*barsa, [0, 1]);
state0.wellSol = initWellSolAD([], model, state0);

% Set up drive mechanism: constant rate at x=0, constant pressure at x=L


injR = −sum(poreVolume(G,rock))/(500*day);
bc = fluxside([], G, ' xmin' , −injR, ' sat ' , [1, 0]);
bc = pside(bc, G, ' xmax', 0*barsa, ' sat ' , [0, 1]);

109 / 117
Example: two-phase Buckley–Leverett
G = cartGrid([50, 1, 1], [1000, 10, 10]*meter);
G = computeGeometry(G);
rock = makeRock(1*darcy*ones, .3);
fluid = initSimpleADIFluid('phases', 'WO', 'n', [2 2]);

% Set up model and initial state.


model = TwoPhaseOilWaterModel(G, rock, fluid);
state0 = initResSol(G, 50*barsa, [0, 1]);
state0.wellSol = initWellSolAD([], model, state0);

% Set up drive mechanism: constant rate at x=0, constant pressure at x=L


injR = −sum(poreVolume(G,rock))/(500*day);
bc = fluxside([], G, ' xmin' , −injR, ' sat ' , [1, 0]);
bc = pside(bc, G, ' xmax', 0*barsa, ' sat ' , [0, 1]);

Simulate 1 PVI using a manual loop:


[dT, n] = deal(20*day, 25);
states = cell(n+1, 1);
states{1} = state0;
solver = NonLinearSolver();

for i = 1:n
state = solver.solveTimestep(states{i}, dT, model, 'bc', bc);
states{i+1} = state;
end
plotToolbar(G, states, ' field ' , ' s :1 ' , ' plot1d ' , true, ...
' lockCaxis ' , true, ' startplayback ' ,true);

110 / 117
Example: two-phase Buckley–Leverett
G = cartGrid([50, 1, 1], [1000, 10, 10]*meter);
G = computeGeometry(G);
rock = makeRock(1*darcy*ones, .3);
fluid = initSimpleADIFluid('phases', 'WO', 'n', [2 2]);

% Set up model and initial state.


model = TwoPhaseOilWaterModel(G, rock, fluid);
state0 = initResSol(G, 50*barsa, [0, 1]);
state0.wellSol = initWellSolAD([], model, state0);

% Set up drive mechanism: constant rate at x=0, constant pressure at x=L


injR = −sum(poreVolume(G,rock))/(500*day);
bc = fluxside([], G, ' xmin' , −injR, ' sat ' , [1, 0]);
bc = pside(bc, G, ' xmax', 0*barsa, ' sat ' , [0, 1]);

Simulate 1 PVI using a manual loop:


[dT, n] = deal(20*day, 25);
states = cell(n+1, 1);
states{1} = state0;
solver = NonLinearSolver();

for i = 1:n
state = solver.solveTimestep(states{i}, dT, model, 'bc', bc);
states{i+1} = state;
end
plotToolbar(G, states, ' field ' , ' s :1 ' , ' plot1d ' , true, ...
' lockCaxis ' , true, ' startplayback ' ,true);

110 / 117
Example: two-phase Buckley–Leverett
G = cartGrid([50, 1, 1], [1000, 10, 10]*meter);
G = computeGeometry(G);
rock = makeRock(1*darcy*ones, .3);
fluid = initSimpleADIFluid('phases', 'WO', 'n', [2 2]);

% Set up model and initial state.


model = TwoPhaseOilWaterModel(G, rock, fluid);
state0 = initResSol(G, 50*barsa, [0, 1]);
state0.wellSol = initWellSolAD([], model, state0);

% Set up drive mechanism: constant rate at x=0, constant pressure at x=L


injR = −sum(poreVolume(G,rock))/(500*day);
bc = fluxside([], G, ' xmin' , −injR, ' sat ' , [1, 0]);
bc = pside(bc, G, ' xmax', 0*barsa, ' sat ' , [0, 1]);

Repeat simulation with general solver:


schedule = simpleSchedule(repmat(dT,1,25), 'bc', bc);
[∼,sstates] = simulateScheduleAD(state0, model, schedule);

plotToolbar(G, sstates, ' field ' , ' s :1 ' , ' lockCaxis ' ,true),
caxis([0 1]), view(10,10)
colorbar

110 / 117
Example: two-phase Buckley–Leverett
G = cartGrid([50, 1, 1], [1000, 10, 10]*meter);
G = computeGeometry(G);
rock = makeRock(1*darcy*ones, .3);
fluid = initSimpleADIFluid('phases', 'WO', 'n', [2 2]);

% Set up model and initial state.


model = TwoPhaseOilWaterModel(G, rock, fluid);
state0 = initResSol(G, 50*barsa, [0, 1]);
state0.wellSol = initWellSolAD([], model, state0);

% Set up drive mechanism: constant rate at x=0, constant pressure at x=L


injR = −sum(poreVolume(G,rock))/(500*day);
bc = fluxside([], G, ' xmin' , −injR, ' sat ' , [1, 0]);
bc = pside(bc, G, ' xmax', 0*barsa, ' sat ' , [0, 1]);

The general solver has a hook, that visualizes the progress of the
simulation, enables you to stop it and continue running in ’debug’ mode:
fn = getPlotAfterStep(state0, model, schedule, ...
' plotWell ' , false, ' plotReservoir ' , true, ' field ' , ' s :1 ' , ...
' lockCaxis ' ,true, ' plot1d ' , true);

[∼,sstates,report] = ...
simulateScheduleAD(state0, model, schedule,'afterStepFn', fn);

110 / 117
More about the nonlinear solver

Classic Newton Main loop solveMinistep


[xit, t] = initializeSolution(. . . ) [x, t] = initializeSolution(. . . ) [res, J, . . . ] = getEqs(t + τ , . . . )
while t < T while t < T xit = x
t = t + dt [∆T , ctrl]=getControl(t) while res > tol & it ≤ itmax
x = xit τ =0 lsys = assembleLinSys(res, J, . . . )
do while τ < ∆T lsol = setupLinSolver(xit, lsys, . . . )
[R,J] = computeResiduals(xit,x) do upd = solveLinSys(xit, lsys, lsol, . . . )
upd = J −1 R [∆t, . . . ]=getTimeStep(. . . ) upd = stabilizeStep(xit, upd, lsys, . . . )
xit = xit + upd [ok, τ , . . . ]=solveMinistep(t + τ , ∆t, . . . ) xit = updateIterate(upd, . . . )
while norm(R)>tol while ok=false cleanupLinSolver(lsol)
end end [res, J ] = getEqs(t + τ , . . . )
end end
if it ≤ itmax
ok = true
Context:
[τ , x, . . . ] = updateSolution(xit)
physical model and reservoir state
else
nonlinear solver and time loop
ok = false
linearization of discrete equations
end
linear solver

111 / 117
More about the nonlinear solver

Initial ministep:
Nonlinear solver ∆t Time step selector Type color legend
Solves nonlinear problems sub-divided Determines optimal time steps
into one or more mini steps using Class
Newton’s method SimpleTimeStepSelector,
Adjusted: Struct
IterationCountSelector,
∆t̃
StateChangeTimeStepSelector, ...
Input
Contains object

State Physical model Linear solver


Primary va δx
Primary variables: p, sw , sg , Rs , Rv ... rs Defines mathematical model: Resid- Solves linearized problem and returns
ual equations, Jacobians, limits on increments
Update variables: updates, convergence definition...
BackslashSolverAD, AGMGSolverAD,
p ← p + δp, s ← s + δs, ... TwoPhaseOilWaterModel, CPRSolverAD, MultiscaleSolverAD, ...
ThreePhaseBlackOilModel
[Re
s, J Assemble: Ax = b
Well solutions ac], in
fo
Well data: qW, qO, qG, bhp, ...
Well model Linearized problem
Well equations, control switch, well- Jacobians, residual equations and
bore pressure drop, ... meta-information about their types

111 / 117
The layout of the AD solvers
Initial state Physical model
Schedule

Type color legend


Simulator
Solves simulation schedule comprised Steps Controls
Class
of time steps and drive mechanisms Time step and control numbers Different wells and bc
(wells/bc) {(∆T1 , C1 ), ..., (∆Tn , Cn )}, {(W1 , BC1 ), ..., (Wm , BCm )} Struct

simulateScheduleAD Function(s)

Initial ministep:
State(Ti ), ∆Ti , Controls(Ci ) Nonlinear solver ∆t Time step selector Input
Solves nonlinear problems sub-divided Determines optimal time steps
into one or more mini steps using Contains object
State(Ti + ∆Ti ) Newton’s method SimpleTimeStepSelector,
Adjusted:
∆t̃
IterationCountSelector, Optional output
StateChangeTimeStepSelector, ...

Result handler State Physical model Linear solver


Write to storage Primary var
Stores and retrieves simulation data Primary variables: p, sw , sg , Rs , Rv ... s Defines mathematical model: Resid- δx Solves linearized problem and returns
from memory/disk in a transparent ual equations, Jacobians, limits on increments
and efficient manner. Update variables: updates, convergence definition...
BackslashSolverAD, AGMGSolverAD,
tion p ← p + δp, s ← s + δs, ...
aliza TwoPhaseOilWaterModel, CPRSolverAD, MultiscaleSolverAD, ...
visu
3D ThreePhaseBlackOilModel
[Re
s, J Assemble: Ax = b
Visualization Well solutions ac],
info
Visualize well curves, reservoir proper- Well data: qW, qO, qG, bhp, ...
ties, etc Well model Linearized problem
Well equations, control switch, well- Jacobians, residual equations and
plotCellData, plotToolbar, Well curves
bore pressure drop, ... meta-information about their types
plotWellSols, ...

The framework is designed so that you can only work on the components you
are interested in: If you want to write a flow solver, you do not need to debug a
Newton solver.

112 / 117
Functionality through inheritance

PhysicalModel
Abstract base class for all MRST models.
Contains logic related to linearization and
updates.
Primary variables: None

ReservoirModel
Extends PhysicalModel with rock, fluid,
saturations, pressures, and temperature.
Base class for all reservoir models.
Added primary variables: sα , p, T, qα , pbh

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel PhysicalModel
Abstract base class for all MRST models. Properties:
Contains logic related to linearization and
updates. operators, G
Primary variables: None nonlinearTolerance, stepFunctionIsLinear
verbose

ReservoirModel
Extends PhysicalModel with rock, fluid,
saturations, pressures, and temperature.
Base class for all reservoir models.
Added primary variables: sα , p, T, qα , pbh

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel PhysicalModel
Abstract base class for all MRST models. Properties:
Contains logic related to linearization and
updates. operators, G
Primary variables: None nonlinearTolerance, stepFunctionIsLinear
verbose

Quality assurance:
ReservoirModel
Extends PhysicalModel with rock, fluid, state = model.validateState(state)
saturations, pressures, and temperature. model = model.validateModel(...)
Base class for all reservoir models.
Added primary variables: sα , p, T, qα , pbh

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel PhysicalModel
Abstract base class for all MRST models. Properties:
Contains logic related to linearization and
updates. operators, G
Primary variables: None nonlinearTolerance, stepFunctionIsLinear
verbose

Quality assurance:
ReservoirModel
Extends PhysicalModel with rock, fluid, state = model.validateState(state)
saturations, pressures, and temperature. model = model.validateModel(...)
Base class for all reservoir models.
Added primary variables: sα , p, T, qα , pbh Querying / setting model properties:
p = model.getProp(state, 'pressure')
[p,s] = model.getProps(state, 'pressure', ' s ' )
ThreePhaseBlackOilModel [f,i] = model.getVariableField(name)
Extends ReservoirModel with optional so-
state = model.setProp(model, state, 'pressure', 5)
lution gas and vaporized oil. Base class for state = model.incrementProp(state, 'pressure', 1)
two- and single-phase versions. state = model.capProperty(state,'saturation', 0, 1)
Added primary variables: rs , rv
These are examples of syntax for derived classes and
will not work on a PhysicalModel, which has no
associated variables 113 / 117
Functionality through inheritance

PhysicalModel PhysicalModel
Abstract base class for all MRST models. Get drive mechanisms:
Contains logic related to linearization and
updates. [..,ctrl] = model.getDrivingForces(model, ctrl)
Primary variables: None

ReservoirModel
Extends PhysicalModel with rock, fluid,
saturations, pressures, and temperature.
Base class for all reservoir models.
Added primary variables: sα , p, T, qα , pbh

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel PhysicalModel
Abstract base class for all MRST models. Get drive mechanisms:
Contains logic related to linearization and
updates. [..,ctrl] = model.getDrivingForces(model, ctrl)
Primary variables: None
Linearize and assemble discrete problem:
[problem, state] = ...
ReservoirModel model.getEquations(state0, state, ...
Extends PhysicalModel with rock, fluid, dt, drivingForces, varargin)
saturations, pressures, and temperature.
Base class for all reservoir models.
Added primary variables: sα , p, T, qα , pbh

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel PhysicalModel
Abstract base class for all MRST models. Get drive mechanisms:
Contains logic related to linearization and
updates. [..,ctrl] = model.getDrivingForces(model, ctrl)
Primary variables: None
Linearize and assemble discrete problem:
[problem, state] = ...
ReservoirModel model.getEquations(state0, state, ...
Extends PhysicalModel with rock, fluid, dt, drivingForces, varargin)
saturations, pressures, and temperature.
Base class for all reservoir models. Compute a linearized time step:
Added primary variables: sα , p, T, qα , pbh
[state, report] = ...
model.stepFunction(model, state, state0, ..
dt, drivingForces, linsolve, ...
ThreePhaseBlackOilModel nonlinsolve, iteration, varargin)
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel PhysicalModel
Abstract base class for all MRST models. Update state from Newton increment:
Contains logic related to linearization and
updates. [state, report] = model.updateState(state, ...
Primary variables: None problem, dx, drivingForces)

and other utility functions:


ReservoirModel [conv, ..] = model.checkConvergence(problem, n)
Extends PhysicalModel with rock, fluid,
saturations, pressures, and temperature. [state,rep] = model.updateAferConvergence(...
Base class for all reservoir models. state0, state, dt, drivingForces)
Added primary variables: sα , p, T, qα , pbh :
:

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel ReservoirModel
Abstract base class for all MRST models. Properties:
Contains logic related to linearization and
updates. % Submodels
Primary variables: None fluid, rock, gravity
FacilityModel

% Physical properties
ReservoirModel water, gas, oil
Extends PhysicalModel with rock, fluid, saturationVarNames, componentVarNames
saturations, pressures, and temperature.
Base class for all reservoir models. % Iterations parameters
Added primary variables: sα , p, T, qα , pbh dpMaxRel, dpMaxAbs, dsMaxRel, dsMaxAbs
maximumPressure, minimumPressure
useCNVConvergence, toleranceCNV
toleranceMB
ThreePhaseBlackOilModel
Extends ReservoirModel with optional so- % Miscellaneous
lution gas and vaporized oil. Base class for :
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel ReservoirModel
Abstract base class for all MRST models. Declaration of physical variables:
Contains logic related to linearization and
updates. function [fn,ix] = getVariableField(model, name)
Primary variables: None switch(lower(name))
case { ' pressure ' , ' p ' }
ix = 1;
fn = ' pressure ' ;
ReservoirModel case { ' s ' , ' sat ' , ' saturation ' }
Extends PhysicalModel with rock, fluid, ix = ' : ' ;
saturations, pressures, and temperature. fn = 's ' ;
Base class for all reservoir models. case { ' sw' , ' water ' }
Added primary variables: sα , p, T, qα , pbh ix = model.satVarIndex('sw');
fn = 's ' ;
:
end
ThreePhaseBlackOilModel
Extends ReservoirModel with optional so- Plus a large number of utility functions to extract,
lution gas and vaporized oil. Base class for
update, and store these physical variables
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel ReservoirModel
Abstract base class for all MRST models. The class declares known drive mechanisms:
Contains logic related to linearization and
updates. function forces = getValidDrivingForces(model)
Primary variables: None forces = getValidDrivingForces
@PhysicalModel(model);
forces.W = [];
forces.bc = [];
ReservoirModel forces.src = [];
Extends PhysicalModel with rock, fluid, end
saturations, pressures, and temperature.
Base class for all reservoir models.
and define how to evaluate relative permeability,
Added primary variables: sα , p, T, qα , pbh
get surface densities, etc.
The class also specifies how to add well equations,
source terms, and boundary conditions to the
ThreePhaseBlackOilModel
equation system, but does not implement specific
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
flow equations.
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel ReservoirModel
Abstract base class for all MRST models.
Contains logic related to linearization and Default discretization is a two-point method:
updates.
Primary variables: None function model = ...
setupOperators(model,G, rock, varargin)
model.operators = ...
setupOperatorsTPFA(G, rock, varargin{:});
ReservoirModel end
Extends PhysicalModel with rock, fluid,
saturations, pressures, and temperature.
Base class for all reservoir models.
Added primary variables: sα , p, T, qα , pbh

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Functionality through inheritance

PhysicalModel ThreePhaseBlackOilModel
Abstract base class for all MRST models. Implementes specific equations, which in this case
Contains logic related to linearization and
updates. is a general black-oil model with dissolved gas and
Primary variables: None vaporized oil.
Evaluation of residual equations:
[problem, state] = ...
ReservoirModel equationsBlackOil(state0, state,...
Extends PhysicalModel with rock, fluid, model, dt, drivingForces, varargin)
saturations, pressures, and temperature.
Base class for all reservoir models.
Details of this function is as given for two-phase
Added primary variables: sα , p, T, qα , pbh
case above, but with more features and logic that
switches unknowns depending on phases present

ThreePhaseBlackOilModel
Extends ReservoirModel with optional so-
lution gas and vaporized oil. Base class for
two- and single-phase versions.
Added primary variables: rs , rv

113 / 117
Constructing a simulation model from ECLIPSE input

Input deck
Data
Input parser
Class
Reads complete simulation decks:
grid and petrophysics, fluid and rock Struct
properties, region information, well
definitions, operating schedule, con- Function
vergence control, etc
Input

Contains

Reservoir model State Schedule


Description of geology and fluid behavior as Physical variables inside Time steps and controls and
well as discrete averaging and spatial dis- the reservoir settings for wells and boundary
cretization operators p, sw , so , sg , c, rv , rs conditions

Grid Petrophysics Fluids Well state Wells


1

0.8
Physical variables inside
0.6
the wellbore
qsw , qso , qsg , qsp , pbh
0.4

0.2

0
0 0.2 0.4 0.6 0.8 1

114 / 117
ECLIPSE input decks
-- =====================================================================
-- THIS IS THE FIRST SPE COMPARISON PROBLEM,"COMPARISON OF SOLUTIONS TO A
RUNSPEC – simulation description (name of the case, grid -- THREE-DIMENSIONAL BLACK-OIL RESERVOIR SIMULATION PROBLEM", REPORTED
-- BY AZIS AND ODEH AT THE SPE SYMPOSIUM ON RESERVOIR SIMULATION ,
-- JANUARY 1981. IT IS A NON SWELLING AND SWELLING STUDY. A REGULAR
dimensions, phases and components present, number of -- GRID WITH TWO WELLS (INJECTOR AND PRODUCER)AND A IMPES SOLUTION METHOD
-- IS USED FOR THIS SIMULATION.THE PRODUCTION IS CONTROLLED BY FLOW RATE

wells, table dimensions, etc) -- AND MIN. BHP. OIL RATE, GOR, PRESSURE AND GAS SATURATION ARE TO BE REPO
-- =====================================================================
RUNSPEC
TITLE

GRID – grid geometry/topology and petrophysical properties ODEH PROBLEM - IMPLICIT OPTION - 1200 DAYS

DIMENS
(porosity, permeability, net-to-gross). 10 10 3 /

NONNC

EDIT – user-defined changes of pore volume, cell centers, OIL

transmissibilities, LGR, etc (optional) WATER

GAS

PROPS – rock-fluid and PVT properties DISGAS

FIELD

REGIONS – spatial dependence for initialization, rock-fluid EQLDIMS


1 100 10 1 1 /

and PVT properties (optional) TABDIMS


1 1 16 12 1 12 /

SOLUTION – specifies how the model is to be initialized WELLDIMS


2 1 1 2 /

NUPCOL

SUMMARY – specifies output of reservoir responses (well 4 /

START
curves, average pressure, etc) to summary file after each 19 ’OCT’ 1982 /

NSTACK
time step (optional) 24 /

--FMTOUT

SCHEDULE – defines wells and how they are to be operated, --FMTIN

time step selection and solver tolerances, controls UNIFOUT

UNIFIN
output of cell properties --NOSIM

--IMPES

Data file: SPE1 benchmark


115 / 117
ECLIPSE input decks
GRID ================================================================
-------- IN THIS SECTION , THE GEOMETRY OF THE SIMULATION GRID AND THE
RUNSPEC – simulation description (name of the case, grid -------- ROCK PERMEABILITIES AND POROSITIES ARE DEFINED.
------------------------------------------------------------------------
-- THE X AND Y DIRECTION CELL SIZES ( DX, DY ) AND THE POROSITIES ARE
dimensions, phases and components present, number of -- CONSTANT THROUGHOUT THE GRID. THESE ARE SET IN THE FIRST 3 LINES
-- AFTER THE EQUALS KEYWORD. THE CELL THICKNESSES ( DZ ) AND

wells, table dimensions, etc) -- PERMEABILITES ARE THEN SET FOR EACH LAYER. THE CELL TOP DEPTHS
-- ( TOPS ) ARE NEEDED ONLY IN THE TOP LAYER ( THOUGH THEY COULD BE.
-- SET THROUGHOUT THE GRID ). THE SPECIFIED MULTZ VALUES ACT AS
-- MULTIPLIERS ON THE TRANSMISSIBILITIES BETWEEN THE CURRENT LAYER

GRID – grid geometry/topology and petrophysical properties -- AND THE LAYER BELOW.
INIT

(porosity, permeability, net-to-gross). INCLUDE


’./SPE1.GRDECL’
/

EDIT – user-defined changes of pore volume, cell centers, PORO


300*0.3

transmissibilities, LGR, etc (optional) /

PERMX
100*500.0
PROPS – rock-fluid and PVT properties 100*50.0
100*200.0
/

REGIONS – spatial dependence for initialization, rock-fluid PERMY


100*500.0
100*50.0
and PVT properties (optional) 100*200.0
/

SOLUTION – specifies how the model is to be initialized -- Note: ignoring MULTZ!


-- layer 1-2 ’MULTZ’ 0.64 /
-- layer 2-3 ’MULTZ’ 0.265625 /
-- Reducing PERMZ a little instead
SUMMARY – specifies output of reservoir responses (well PERMZ
100*300.0
100*30.0
curves, average pressure, etc) to summary file after each 100*50.0
/

time step (optional)


SCHEDULE – defines wells and how they are to be operated,
time step selection and solver tolerances, controls
output of cell properties

Data file: SPE1 benchmark


115 / 117
ECLIPSE input decks
PROPS ===============================================================
-------- THE PROPS SECTION DEFINES THE REL. PERMEABILITIES, CAPILLARY
RUNSPEC – simulation description (name of the case, grid -------- PRESSURES, AND THE PVT PROPERTIES OF THE RESERVOIR FLUIDS
----------------------------------------------------------------------
-- WATER RELATIVE PERMEABILITY AND CAPILLARY PRESSURE ARE TABULATED AS
dimensions, phases and components present, number of -- A FUNCTION OF WATER SATURATION.
--

wells, table dimensions, etc) -- Generated with MRST’s family_1() function from the original deck.
-- SWAT
SWOF
KRW KRO PCOW

0.120000000000000 0 1.000000000000000

GRID – grid geometry/topology and petrophysical properties 0.121000000000000


0.140000000000000
0.000000011363636
0.000000227272727
1.000000000000000
0.997000000000000
0.170000000000000 0.000000568181818 0.980000000000000
(porosity, permeability, net-to-gross). 0.240000000000000
0.319999999000000
0.000001363636364
0.000002272727261
0.700000000000000
0.350000004375000
0.370000000000000 0.000002840909091 0.200000000000000
0.420000000000000 0.000003409090909 0.090000000000000
EDIT – user-defined changes of pore volume, cell centers, 0.520000000000000
0.570000000000000
0.000004545454545
0.000005113636364
0.021000000000000
0.010000000000000

transmissibilities, LGR, etc (optional) 0.620000000000000


0.720000000000000
0.000005681818182
0.000006818181818
0.001000000000000
0.000100000000000
0.820000000000000 0.000007954545455 0.000000000000000
1.000000000000000 0.000010000000000 0
PROPS – rock-fluid and PVT properties /

SGOF
REGIONS – spatial dependence for initialization, rock-fluid 0
0.001000000000000
0
0
1.000000000000000
1.000000000000000
0.020000000000000 0 0.997000000000000
and PVT properties (optional) 0.050000000000000
0.120000000000000
0.005000000000000
0.025000000000000
0.980000000000000
0.700000000000000
0.200000000000000 0.075000000000000 0.350000000000000

SOLUTION – specifies how the model is to be initialized 0.250000000000000


0.300000000000000
0.125000000000000
0.190000000000000
0.200000000000000
0.090000000000000
0.400000000000000 0.410000000000000 0.021000000000000
0.450000000000000 0.600000000000000 0.010000000000000
SUMMARY – specifies output of reservoir responses (well 0.500000000000000
0.600000000000000
0.720000000000000
0.870000000000000
0.001000000000000
0.000100000000000
0.700000000000000 0.940000000000000 0
curves, average pressure, etc) to summary file after each 0.850000000000000
0.880000000000000
0.980000000000000
0.984000000000000
0
0
/
time step (optional) -- PVT PROPERTIES OF WATER
--

SCHEDULE – defines wells and how they are to be operated, --


PVTW
REF. PRES. REF. FVF COMPRESSIBILITY REF VISCOSITY VISCOSIBILITY

4014.7 1.029 3.13E-6 0.31 0 /


time step selection and solver tolerances, controls -- ROCK COMPRESSIBILITY
--
output of cell properties --
ROCK
REF. PRES COMPRESSIBILITY

14.7 3.0E-6 /

-- SURFACE DENSITIES OF RESERVOIR FLUIDS


--
-- OIL WATER GAS
DENSITY
49.1 64.79 0.06054 /

Data file: SPE1 benchmark -- PVT PROPERTIES OF DRY GAS (NO VAPOURISED OIL)
-- WE WOULD USE PVTG TO SPECIFY THE PROPERTIES OF WET GAS
--
-- PGAS BGAS VISGAS 115 / 117
ECLIPSE input decks
SOLUTION ===============================================================
-------- THE SOLUTION SECTION DEFINES THE INITIAL STATE OF THE SOLUTION
RUNSPEC – simulation description (name of the case, grid -------- VARIABLES (PHASE PRESSURES, SATURATIONS AND GAS-OIL RATIOS)
------------------------------------------------------------------------
-- DATA FOR INITIALISING FLUIDS TO POTENTIAL EQUILIBRIUM
dimensions, phases and components present, number of --
-- DATUM DATUM OWC OWC GOC GOC RSVD RVVD SOLN

wells, table dimensions, etc) -- DEPTH PRESS DEPTH


-- EQUIL
-- 8400 4800 8500
PCOW DEPTH

0 8200
PCOG TABLE TABLE

0 1 0
METH

0 /

GRID – grid geometry/topology and petrophysical properties -- VARIATION OF INITIAL RS WITH DEPTH
--
-- DEPTH RS
(porosity, permeability, net-to-gross). -- RSVD
-- 8200 1.270
-- 8500 1.270 /

EDIT – user-defined changes of pore volume, cell centers, -- PRESSURE


-- 100*3.297832774859256e7

transmissibilities, LGR, etc (optional) -- 100*3.302313357125603e7


-- 100*3.309483500720813e7
-- /
PRESSURE
PROPS – rock-fluid and PVT properties 100*4783.10205078125
100*4789.60058593750
100*4800.00000000000
/
REGIONS – spatial dependence for initialization, rock-fluid SWAT
300*0.12
and PVT properties (optional) /

SGAS

SOLUTION – specifies how the model is to be initialized 300*0.0


/

-- RS
SUMMARY – specifies output of reservoir responses (well -- 300*226.1966570852417
-- /
RS
curves, average pressure, etc) to summary file after each 300*1.27
/

time step (optional) -- OUTPUT CONTROLS (SWITCH ON OUTPUT OF INITIAL GRID BLOCK PRESSURES)
RPTSOL
1 11*0 /

SCHEDULE – defines wells and how they are to be operated,


time step selection and solver tolerances, controls
output of cell properties

Data file: SPE1 benchmark


115 / 117
ECLIPSE input decks
SUMMARY ===============================================================
-------- THIS SECTION SPECIFIES DATA TO BE WRITTEN TO THE SUMMARY FILES
RUNSPEC – simulation description (name of the case, grid -------- AND WHICH MAY LATER BE USED WITH THE ECLIPSE GRAPHICS PACKAGE
------------------------------------------------------------------------

dimensions, phases and components present, number of EXCEL

wells, table dimensions, etc) SEPARATE

--REQUEST PRINTED OUTPUT OF SUMMARY FILE DATA

GRID – grid geometry/topology and petrophysical properties RUNSUM

-- FIELD OIL PRODUCTION


(porosity, permeability, net-to-gross). FOPR

-- WELL GAS-OIL RATIO FOR PRODUCER


WGOR
EDIT – user-defined changes of pore volume, cell centers, -- ’PRODUCER’
/

transmissibilities, LGR, etc (optional) -- WELL BOTTOM-HOLE PRESSURE


WBHP
-- ’PRODUCER’
/
PROPS – rock-fluid and PVT properties -- GAS AND OIL SATURATIONS IN INJECTION AND PRODUCTION CELL
BGSAT
10 10 3 /
REGIONS – spatial dependence for initialization, rock-fluid 1 1 1 /
/
BOSAT
and PVT properties (optional) 10 10 3 /
1 1 1 /
/

SOLUTION – specifies how the model is to be initialized -- PRESSURE IN INJECTION AND PRODUCTION CELL
BPR
10 10 3 /
SUMMARY – specifies output of reservoir responses (well 1 1 1 /
/

curves, average pressure, etc) to summary file after each


time step (optional)
SCHEDULE – defines wells and how they are to be operated,
time step selection and solver tolerances, controls
output of cell properties

Data file: SPE1 benchmark


115 / 117
ECLIPSE input decks
SCHEDULE ===============================================================
-------- THE SCHEDULE SECTION DEFINES THE OPERATIONS TO BE SIMULATED
RUNSPEC – simulation description (name of the case, grid ------------------------------------------------------------------------
-- CONTROLS ON OUTPUT AT EACH REPORT TIME
RPTSCHED
dimensions, phases and components present, number of 1
0
0
0
1
0
1
0
0
0
0
0
4
0
2
0
2
0
0
0
0
0
2
0
0
0
0
0
0
0

wells, table dimensions, etc) 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 /

--IMPES

GRID – grid geometry/topology and petrophysical properties -- 1.0 1.0 10000.0 /

-- SET ’NO RESOLUTION’ OPTION


(porosity, permeability, net-to-gross). --DRSDT
-- 0 /

-- SET INITIAL TIME STEP TO 1 DAY AND MAXIMUM TO 6 MONTHS


EDIT – user-defined changes of pore volume, cell centers, TUNING
1 182.5 /

transmissibilities, LGR, etc (optional) 1.0 0.5 1.0E-6 /


/

-- WELL SPECIFICATION DATA


PROPS – rock-fluid and PVT properties --
-- WELL GROUP LOCATION BHP PI
-- NAME NAME I J DEPTH DEFN
WELSPECS
REGIONS – spatial dependence for initialization, rock-fluid ’PRODUCER’ ’G’
’INJECTOR’ ’G’
10 10
1 1
8400 ’OIL’
8335 ’GAS’
/
/
/
and PVT properties (optional) -- COMPLETION SPECIFICATION DATA
--

SOLUTION – specifies how the model is to be initialized --


--
WELL
NAME
-LOCATION- OPEN/ SAT CONN
I J K1 K2 SHUT TAB FACT
WELL
DIAM
COMPDAT
’PRODUCER’ 10 10 3 3 ’OPEN’ 0 -1 0.5 /
SUMMARY – specifies output of reservoir responses (well /
’INJECTOR’ 1 1 1 1 ’OPEN’ 1 -1 0.5 /

curves, average pressure, etc) to summary file after each -- PRODUCTION WELL CONTROLS
--
-- WELL OPEN/ CNTL OIL WATER GAS LIQU RES BHP
time step (optional) --
WCONPROD
NAME SHUT MODE RATE RATE RATE RATE RATE

’PRODUCER’ ’OPEN’ ’ORAT’ 20000 4* 1000 /

SCHEDULE – defines wells and how they are to be operated, /


-- WCONPROD
-- ’PRODUCER’ ’OPEN’ ’BHP’ 5* 1000 /
time step selection and solver tolerances, controls -- /

-- INJECTION WELL CONTROLS


output of cell properties --
-- WELL INJ OPEN/ CNTL FLOW
-- NAME TYPE SHUT MODE RATE
-- WCONINJ
-- ’INJECTOR’ ’GAS’ ’OPEN’ ’RATE’ 100000 /
WCONINJE
’INJECTOR’ ’GAS’ ’OPEN’ ’RATE’ 100000 100000 50000/
/

-- YEAR 1
Data file: SPE1 benchmark TSTEP
--0.2343 0.1393 0.1840 0.2189 0.2235
1.0 2*2.0 2*5.0 5*10.0 11*25.0 115 / 117
Example: the SPE 9 benchmark

Grid: 24×25×15, 9000 cells


3-phase model, dissolved gas but no vaporized oil
1 water injector, rate controlled, switches to bhp
25 producers, oil-rate controlled, most switch to bhp
Appearance of free gas due to pressure drop
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark

Grid: 24×25×15, 9000 cells


3-phase model, dissolved gas but no vaporized oil
1 water injector, rate controlled, switches to bhp
25 producers, oil-rate controlled, most switch to bhp
Appearance of free gas due to pressure drop
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9

Reading input and construct basic MRST objects:


pth = fullfile(getDatasetPath('spe9'), 'BENCH SPE9.DATA');
deck = readEclipseDeck(fn);
deck = convertDeckUnits(deck);

G = initEclipseGrid(deck);
G = computeGeometry(G);

rock = initEclipseRock(deck);
rock = compressRock(rock, G.cells.indexMap);

fluid = initDeckADIFluid(deck);

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark

Grid: 24×25×15, 9000 cells


3-phase model, dissolved gas but no vaporized oil
1 water injector, rate controlled, switches to bhp
25 producers, oil-rate controlled, most switch to bhp
Appearance of free gas due to pressure drop
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9

Initialization from given state in the input file:


gravity reset on
p0 = deck.SOLUTION.PRESSURE;
sw0 = deck.SOLUTION.SWAT;
sg0 = deck.SOLUTION.SGAS;
s0 = [sw0, 1−sw0−sg0, sg0];
rs0 = deck.SOLUTION.RS;

state = struct('s', s0, ' rs ' , rs0, ' rv ' , rv0, ' pressure ' , p0);

Generally, one may have to solve an equilibrium problem to set the initial state.

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark

Grid: 24×25×15, 9000 cells


3-phase model, dissolved gas but no vaporized oil
1 water injector, rate controlled, switches to bhp
25 producers, oil-rate controlled, most switch to bhp
Appearance of free gas due to pressure drop
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9

Create model and simulation schedule:


model = selectModelFromDeck(G, rock, fluid, deck);

% Set maximum limits on changes in saturation , Rs and pressure


model.drsMaxRel = .2;
model.dpMaxRel = .2;
model.dsMaxAbs = .05;

% Convert the deck schedule into a MRST schedule


schedule = convertDeckScheduleToMRST(model, deck);

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark

Grid: 24×25×15, 9000 cells


3-phase model, dissolved gas but no vaporized oil
1 water injector, rate controlled, switches to bhp
25 producers, oil-rate controlled, most switch to bhp
Appearance of free gas due to pressure drop
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9

Select linear solver:


try
mrstModule add agmg
pressureSolver = AGMGSolverAD('tolerance', 1e−4);
catch
pressureSolver = BackslashSolverAD();
end
linsolve = CPRSolverAD(' ellipticSolver ' , pressureSolver);

We select a CPR-type solver, with AGMG as multigrid preconditioner. The CPR


preconditioner attempts to decouple the linear system into a pressure component and
a transport component. Although not necessary here, it improves CPU time

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark

Grid: 24×25×15, 9000 cells


3-phase model, dissolved gas but no vaporized oil
1 water injector, rate controlled, switches to bhp
25 producers, oil-rate controlled, most switch to bhp
Appearance of free gas due to pressure drop
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9

Inspect the rock-fluid and PVD properties:


inspectFluidModel(model)

The AD-OO framework can interactively visualize the fluid model of a


ReservoirModel instance. Once active, the user can interactively explore the different
fluid properties (viscosities, relative permeabilities, densities) as functions of saturation
and pressure.

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark
Solving timestep 01/35: -> 1 Day
Well INJE1: Control mode changed from rate to bhp.
Grid: 24×25×15, 9000 cells ==================================================
| It # | CNV_W | CNV_O | CNV_G | MB_W
3-phase model, dissolved gas but no vaporized oil ==================================================
| 1 | 2.82e-02 | 1.10e+00 | 5.00e-03 | 1.03e-05
1 water injector, rate controlled, switches to bhp | 2 | 1.14e-01 | 7.25e-02 | 8.13e-02 | 5.21e-06
Well PROD26: Control mode changed from orat to bhp
25 producers, oil-rate controlled, most switch to bhp | 3 | 7.29e-03 | 1.29e-02 | 7.41e-02 | 3.40e-06
| 4 | 1.68e-03 | 3.79e-03 | 1.85e-02 | 7.87e-06
Appearance of free gas due to pressure drop | 5 |*9.60e-04 | 6.20e-03 | 4.29e-03 | 1.64e-06
| 6 |*6.79e-04 | 1.45e-03 |*9.00e-04 | 1.19e-06
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9 | 7 |*2.66e-04 |*8.31e-04 |*5.90e-04 | 2.56e-07
| 8 |*8.83e-05 |*3.48e-04 |*8.72e-05 |*4.58e-08
| 9 |*2.08e-05 |*7.35e-05 |*4.96e-05 |*1.05e-08
==================================================
Solving timestep 02/35: 1 Day -> 2 Day
Run the schedule :
:

model.verbose = true;
fn = getPlotAfterStep(state0, model, schedule, ...
' plotWell ' , false, ' plotReservoir ' , false);

[wellsols, states, reports] =...


simulateScheduleAD(state0, model, schedule, ...
' LinearSolver ' , linsolve, ' afterStepFn ' , fn);

We give the schedule with well controls and control time steps. The simulator may use
other timesteps internally, but it will always return values at the specified control steps.
Setting model.verbose=false removes extensive reports about convergence, etc.

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark

Grid: 24×25×15, 9000 cells


3-phase model, dissolved gas but no vaporized oil
1 water injector, rate controlled, switches to bhp
25 producers, oil-rate controlled, most switch to bhp
Appearance of free gas due to pressure drop
From: ad-blackoil/examples/spe9/blackOilTutorialSPE9

Launch a viewer to inspect reservoir responses:


plotWellSols(wellsols, cumsum(schedule.step.val), 'field', 'qTr' )

Here, you can plot bottom-hole pressures, reservoir and surface rates, oil and water
cut, gas-oil ratio, etc. Plots are versus time or time step, and can be instantaneous or
cummulative.

J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Example: the SPE 9 benchmark
MRST
2.5
Grid: 24×25×15, 9000 cells ECL

3-phase model, dissolved gas but no vaporized oil 2

Gas rate (m3/s)


1 water injector, rate controlled, switches to bhp 1.5

25 producers, oil-rate controlled, most switch to bhp 1

Appearance of free gas due to pressure drop


0.5

From: ad-blackoil/examples/spe9/blackOilTutorialSPE9
0
0 0.5 1 1.5 2
Time (years)

MRST also offers functionality for processing ECLIPSE output. We can use
this to compare results from the two simulators:
compare = fullfile(mrstPath('ad−blackoil'), 'examples', ' spe9 ' , ' compare' );
smry = readEclipseSummaryUnFmt(fullfile(compare, 'SPE9'));
compd = 1:(size(smry.data, 2));
Tcomp = smry.get(':+:+:+:+', 'YEARS', compd);
comp = convertFrom(smry.get('PROD13', 'WBHP', compd), psia)';

T = convertTo(cumsum(schedule.step.val), year);
mrst = getWellOutput(wellsols, 'bhp', 'PROD13');

plot(T, mrst, Tcomp, comp);


J. E. Killough (1995). Ninth SPE comparative solution project: A reexamination of black-oil simulation, doi: 10.2118/29110-MS 116 / 117
Computer exercises

Go through some of the tutorials from the ad-blackoil module. In


particular, I recommend:
spe9/blackoilTutorialSPE9 – we only covered parts of it here
simulatorWorkflowExample – a complete example that does not
use ECLIPSE input
multisegmentWellExample – shows use of multisegment well
models
blackoilSectorModelExample – specification of boundary
conditions

117 / 117

You might also like