MRST - MATLAB Reservoir Simulation Toolbox

Investigation of Structural Trapping

The purpose of the example is to demonstrate some of the functionality we have available for studying migration patterns and finding structural trapping. As an example, we consider the Utsira formation for which we will trace gravity lines, identify structural traps, and investigate how they are connected.


Load data

Make top-surface grid from a coarsened version of the Utsira formation

[grdecl,m] = getAtlasGrid('Utsirafm','coarsening',3);
G    = processGRDECL(grdecl{1});
Gt   = topSurfaceGrid(G(1));
meta = m{2}.meta;
data = abs(m{2}.data)';
data(data==0) = NaN;

Trace gravity lines on the top surface

To show the potential migration paths, we trace 'gravity' lines in the upward direction using a flux defined on a standard TPFA type connection

% Define flux
internal = all(Gt.faces.neighbors>0,2);
n1   = Gt.faces.neighbors(internal,1);
n2   = Gt.faces.neighbors(internal,2);
flux = zeros(Gt.faces.num,1);
flux(internal)= Gt.cells.z(n2) - Gt.cells.z(n1);
state = struct('flux',flux);
clear internal n1 n2 flux;

% Pick approximately five hundred cells and trace streamlines backward
% using the Pollock routine from MRST's streamlines module
mrstModule add streamlines
seeds = (1:ceil(Gt.cells.num/500):Gt.cells.num)';
S = pollock(Gt, state, [seeds, repmat([.5,.5],numel(seeds),1)], 'reverse', true);

% Make Cartesian grid for fast interpolation to surface
y = linspace(0,meta.cellsize*(meta.ncols-1),meta.ncols) + meta.yllcorner;
x = linspace(0,meta.cellsize*(meta.nrows-1),meta.nrows) + meta.xllcorner;
[X,Y] = meshgrid(x,y); clear x y;

% Collect streamlines in a long array separated by zeros and calculate the
% corresponding z-value by interpolating in the original meta data set.
% Afterwards, replace zeros by NaN's for use in plotting.
c = zeros(sum([cellfun(@length,S); numel(S)]),3);
i = 1;
for k=1:numel(S)
   nsl = length(S{k});
   c(i:i+nsl-1,1:2) = S{k};
   i = i+nsl+1;
c(:,3) = interp2(X,Y,data, c(:,1), c(:,2));

% Use the original meta data to surf make the surface, but offset the plots
% slightly to distinguish the surface and the gravity lines
surf(X,Y,data+1),shading interp
hold on
plot3(c(:,1),c(:,2),c(:,3)-1, 'k-', 'LineWidth', 1);
hold off
view(70,50), axis tight, set(gca,'ZDir','reverse');

Find trapping structure

We find all traps corresponding to local maxima on the top surface. The traps are categorized as different levels. A level-1 trap contains one local maximum point; a level-2 trap contains at least two level-1 traps and hence at least one spill point; a level-3 trap contains at least two level-2 traps; and so on. As part of finding the trapping structure, we construct a new top-surface grid for which the topography inside the level-1 traps have been replaced by a flat surface at the depth of the corresponding spill point.

% Check for existence of the MATLAB graph library


% Plot the new top-surface grid on top of the old one to show the location
% of traps
clf, subplot('position',[.025 .025 .95 .95]);
plotGrid(Gt,      'FaceColor','r','EdgeAlpha',.1)
plotGrid(ts.Gtop, 'FaceColor','y','EdgeColor','none');
view(92,40), axis tight off, set(gca,'ZDir','reverse');
Trap level 1: 102 traps identified
Trap level 2: 13 traps identified
Trap level 3: 1 traps identified

Show the flat parts of the grid

plotGrid(ts.Gtop, ts.z_spill_loc>0, 'EdgeAlpha', .1)

Show the traps on different levels in different colors

nt  = numel(ts.trap_level);
col = hsv(nt);
for k=nt:-1:1
   cell_list = [];
   for i=1:size(ts.trap_level{k},2)
      cell_list = [cell_list; find(ts.trap_level{k}(:,i)>0)]; %#ok
   plotGrid(Gt, cell_list, 'FaceColor', col(k,:),  'EdgeAlpha',.1);
colormap(col); cbh=colorbar('horiz'); caxis([0 nt]+.5);set(cbh,'XTick',1:nt);

All the CO2 that accumulates in a trap must come from the trap's drainage area that consists of all cells that have an updip connection to the trap. We show the drainage/accumlation area of the different traps defined as the cells whose spill paths lead into the corresponding local top point. A spill path is the path that the CO2 will follow in its upward migration when injected infinitesimally slow from a given point

clf, subplot('position',[.025 .025 .95 .95]);

% To find the drainage area, we construct a directed graph from the gravity
% flux, make this graph bi-directional along each edge, and then compute
% the connected components.
C       = maxTPFAGravityMatrix(Gt);
[ci,ss] = components(C+C');  assert(max(ci)==numel(

% Set a unique random color for each trap
p  = zeros(length(,1);
nt =  sum(ts.istrap);
p(ci( = randperm(nt)';

% Plot grid, drainage areas for traps, and the local top points
plotGrid(Gt, 'FaceColor','none', 'EdgeAlpha', .05)
plotCellData(Gt,p(ci), p(ci)>0, 'EdgeColor', 'none');
plotGrid(Gt,, 'FaceColor',[.45 .45 .45],'EdgeAlpha',.1);
axis tight off, view(85,50), colormap(jet(nt));

Find trap connections (river system)

The CO2 is typically injected low in the formation and if we disregard all other trapping mechanisms, the CO2 will migrate upward until it encounters a structural trap. Once a trap is filled, the CO2 will spill over and start to migrate upward along a spill path and either reach the top of the formation or start to accumulate in a more shallow trap until this trap spills over, and so on. We start by computing the connections between the traps.

mrstModule add coarsegrid

trap_con    = findTrapConnections(Gt, ts.z_spill_loc);
cell_lines  = trap_con.cell_lines;
traps       = trap_con.traps;
leaf_lines  = trap_con.leaf_lines;
leaf_traps  = trap_con.leaf_traps;
trap_matrix = trap_con.trap_matrix;
Start find rivers

If we invert the axis, the structural trapping may be thought of as water flowing down in a terrain consisting of impermeable soil. The water will collect in ponds and small lakes that are possibly connected by natural watercourses (rivers).

% Find connection stucture of the river network
comp = components(trap_matrix+trap_matrix');

% Make vectors representing each independent waterway
p = randperm(max(comp));  % to avoid the proximity of similar colors
for i=1:numel(comp)
[x,y,z] = deal([]);
for i=1:numel(cell_lines);
   x = [x; cc(double(cell_lines{i}),1); NaN]; %#ok
   y = [y; cc(double(cell_lines{i}),2); NaN]; %#ok
   z = [z; cc(double(cell_lines{i}),3); NaN]; %#ok

% Plot the 'lakes' and the watercourses
clf, subplot('position', [.025 .025 .95 .95]);
hold on
plot3(x,y,z, 'k', 'LineWidth', 2)
hold off
view(280,40), axis tight off; set(gca,'ZDir', 'normal');

As our last example, we will look at leaf nodes in our trapping system, i.e., traps that only have outgoing 'rivers'. The leaf traps are shown in white color. The drainage areas and the resulting migration path are given a unique color so that one can trace the migration of CO2 upward until it either leaves the formation or reaches a higher trap that accumulates CO2 from multiple leaf traps. All traps that are not leaf traps are shown in dark gray.

% Plot traps and grid
plotGrid(ts.Gtop, ts.z_spill_loc>0, 'EdgeColor', 'none', 'FaceColor',[.25 .25 .25])
plotGrid(ts.Gtop, 'FaceColor', 'none', 'EdgeAlpha', .1)

% Find leaves and the corresponding traps
[ll, tc, dc] = deal([]);
C    = maxTPFAGravityMatrix(ts.Gtop);
nll  = numel(leaf_lines);
p    = randperm(nll);
lvol = zeros(nll,1);
for k=nll:-1:1
   % extract the leaf line out of the trap
   ll  = [ll; leaf_lines{k}', p(k)*ones(length(leaf_lines{k}),1)]; %#ok

   % find all cells in the given trap
   t_cells = find(traps ==leaf_traps{k});
   tc = [tc; t_cells]; %#ok

   % find all cells in the drainage region of the leaf
   cc = find( dfs(C', double(t_cells(1))) >0);
   dc  = [dc; cc, p(k)*ones(length(cc),1)]; %#ok

   % calculate the leaf volume
   cc = find( dfs(C, double(t_cells(1)))>0 );
   lvol(k) = sum((ts.Gtop.cells.z(cc) - Gt.cells.z(cc)).*Gt.cells.volumes(cc));
   disp(['Leaf volume : ', num2str(lvol(k))]);

% Plot leaves and the deepest traps
plotCellData(ts.Gtop, [ll(:,2); dc(:,2)], [ll(:,1); dc(:,1)], 'EdgeColor', 'none');
plotGrid(ts.Gtop, tc, 'EdgeColor', 'none', 'FaceColor', 'w');
view(95,20), axis tight off; set(gca,'ZDir', 'reverse');
Leaf volume : 618782.3458
Leaf volume : 1920205.7847
Leaf volume : 0
Leaf volume : 33295634.1306
Leaf volume : 34577258.0053
Leaf volume : 28458992.5049
Leaf volume : 136488585.5204
Leaf volume : 820247394.6633
Leaf volume : 381407666.5635
Leaf volume : 975677262.5204
Leaf volume : 812477042.3271
Leaf volume : 13273947.4493
Leaf volume : 812032999.8997
Leaf volume : 921435649.9908
Leaf volume : 849094847.046
Leaf volume : 361006825.2235
Leaf volume : 9101232.1556
Leaf volume : 509961.9253
Leaf volume : 36649535.63
Leaf volume : 15594.5838
Leaf volume : 496026164.2495
Leaf volume : 7022319093.149
Leaf volume : 1468444523.9203
Leaf volume : 99286419.5772
Leaf volume : 1469819977.0619
Leaf volume : 2572532.6835
Leaf volume : 228483848.0456
Leaf volume : 1469819977.0619
Leaf volume : 7519927861.7073
Leaf volume : 1009105.2054
Leaf volume : 18805622.7009
Leaf volume : 2621476253.2478
Leaf volume : 1686896.3595
Leaf volume : 1207744737.7059
Leaf volume : 3862613.6834
Leaf volume : 270895768.0561
Leaf volume : 1505263255.3188
Leaf volume : 1505263255.3188
Leaf volume : 582974.0581
Leaf volume : 581524995.8565
Leaf volume : 1218254059.2199
Leaf volume : 34567037.3357
Leaf volume : 1220898307.2355
Leaf volume : 581336917.8887
Leaf volume : 745338740.1382
Leaf volume : 40227970.7599

Published February 12, 2013