Contents

function [G, Gt, rock, rock2D, bcIxVE] = makeJohansenVEgrid()
%Make an VE model based upon a data set of the Johansen formation
%
% SYNOPSIS:
%  [G, Gt, bcIx, bcIxVE, rock, rock2D] = makeJohansenVEgrid()
%
% PARAMETERS:
%   G      - Data structure for 3D grid
%   Gt     - Data structure for topsurface grid
%   rock   - Data structure for 3D rock parameters
%   rock2D - Data structure for rock parameters for topsurface grid
%   bcIxVE - Index for pressure boundary conditions in topsurface grid
%
% DESCRIPTION:
%  The Johansen formation is a candidate site for large-scale CO2 storage
%  offshore the south-west coast of Norway. We consider a sector model that
%  has been constructed based on available seismic and well data and stored
%  in the Eclipse input format (GRDECL). The model has five vertical layers
%  in the Johansen formation and five shale layers above and one below in
%  the Dunhil and Amundsen formations. The shale layers are removed and we
%  construct a 2D grid of the top surface, assuming that the major
%  fault is sealing. Moreover, we identify all outer boundaries that are
%  open to flow. A more thorough presentation of the geological model can be
%  found in the script <matlab:edit('showJohansen.m') showJohansen.m>
%
%  The grid and rock structured constructed in the following can be used for
%  subsequent 3D and/or VE simulations of CO2 injection and migration and
%  are therefore stored to file to avoid time-consuming processing.
%
%  The data files necessary to run the example can be downloaded from the
%  <http://www.sintef.no/Projectweb/MatMorA/Downloads/Johansen/ MatMoRA
%  website>.
%
% SEE ALSO:
%   runJohansenVE

%{
Copyright 2009, 2010, 2011, 2012, 2013 SINTEF ICT, Applied Mathematics.

This file is part of The MATLAB Reservoir Simulation Toolbox (MRST).

MRST is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

MRST is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with MRST.  If not, see <http://www.gnu.org/licenses/>.
%}

try
   disp(' -> Reading Johansen.mat');
   datadir = fullfile(VEROOTDIR,'data','mat');
   load(fullfile(datadir,'Johansen'));
   return;
catch %#ok<*CTCH>
   disp(' -> Reading failed, constructing grid models');
end
 -> Reading Johansen.mat

ans = 

       nodes: [1x1 struct]
       faces: [1x1 struct]
       cells: [1x1 struct]
    cartDims: [100 100 11]
        type: {1x5 cell}
     griddim: 3

Load model and construct VE grid

Load grid geometry - you will most likely have to change the path, depending upon where you have stored the Johansen data-set

try
   jdir = fullfile(VEROOTDIR, 'data', 'johansen');
   sector = 'NPD5';
   fprintf('    Reading %s\n', sector);
   sector = fullfile(jdir, sector);
   grdecl = readGRDECL([sector '.grdecl']);
catch
   disp(' -> Download data from: http://www.sintef.no/Projectweb/MatMoRA/')
   disp(['    Putting data in ', jdir]);
   unzip('http://www.sintef.no/project/MatMoRA/Johansen/NPD5.zip', jdir);
   grdecl = readGRDECL([sector '.grdecl']);
end

% Load permeability and porosity
K = reshape(load([sector, '_Permeability.txt'])', [], 1);
p = reshape(load([sector, '_Porosity.txt'])',     [], 1);
grdecl.PERMX=K;grdecl.PERMY=K;grdecl.PERMZ=0.1*K;
grdecl.PORO=p;
clear sector;

% Remove shale layers Dunhil and Amundsen
disp(' -> Constructing grids ...');
grdecl.ACTNUM(K.*milli*darcy<0.11 *milli*darcy) = 0;

% Construct grid structure. By removing Dunhil and Amundsen, the grid will
% consist of multiple components. We choose the largest one as our
% reservoir.
G = processGRDECL(grdecl);
G = computeGeometry(G(1));
clear grdecl

% Construct VE grid
[Gt, G] = topSurfaceGrid(G,'AddFaults',false);

% Construct structure with petrophyiscal data. Vertical permeability is set
% to 0.1 times the horizontal permeability. NB!
rock.perm = bsxfun(@times, [1 1 0.1], K(G.cells.indexMap)).*milli*darcy;
rock.poro = p(G.cells.indexMap);
rock2D    = averageRock(rock, Gt);
clear p K;

FIND FAULT - set inner boundary

The main fault is assumed to be sealing and must therefore be represented as an inner boundary in the 2D grid. Start by locating cells on each side of fault, which is defined to be between cells with index i=43 and i=44 for j<44.

cells2D_1 = find(Gt.cells.ij(:,1) == 43 & Gt.cells.ij(:,2) <= 44);
cells2D_2 = find(Gt.cells.ij(:,1) == 44 & Gt.cells.ij(:,2) <= 44);

% Plot the cells on opposite sides
figure;
plotGrid(Gt, 'faceColor', 'none');
plotGrid(Gt, cells2D_1, 'faceColor', 'r')
plotGrid(Gt, cells2D_2, 'faceColor', 'g')
axis tight off,
title('Cells on opposite sides of sealing fault'),

% Find the faces at the fault. Construct a mapping facesMat defined such
% that facesMat(i,j)=k if face <k> is shared by cells <i> and <j>.
facesMat = sparse(double(Gt.faces.neighbors(:,1))+1, ...
    double(Gt.faces.neighbors(:,2))+1, 1:Gt.faces.num);
facesMat = facesMat + facesMat';
faultFaces2D = diag( facesMat(cells2D_1+1, cells2D_2+1) );

% Make internal boundary and compute the geometry of the resulting grid
Gt = makeInternalBoundary(Gt, faultFaces2D);
Gt = computeGeometryVE(Gt);

% The function 'topSurfaceGrid' does not handle faults correctly when the
% cells on opposite sides are not phyiscally in contact with each other.
% Instead of producing a discontinuity in the 'z' value, an average value
% is used.  Hence, we need to manually reset the 'z' value of these cells
% (marked in red and green in the plot) to avoid an incorrect flow
Gt.cells.z([cells2D_1; cells2D_2]) = ...
    G.faces.centroids(Gt.cells.map3DFace([cells2D_1; cells2D_2]), 3);
clear cells2D_1 cells2D_2 % facesMat faultFaces2D

FIND PRESSURE BOUNDARY

Setting boundary conditions is unfortunately a manual process and may require some fiddling with indices, as shown in the code below. Here, we identify the part of the outer boundary that is open, i.e., not in contact with one of the shales (Dunhil or Amundsen).

% boundary 3D
nx = G.cartDims(1); ny=G.cartDims(2); nz=G.cartDims(3);
ix1 = boundaryFaceIndices(G, 'BACK', 1:nx-6, 1:4, 1:nz);
ix2 = boundaryFaceIndices(G, 'LEFT', 1:20,   1:ny, 1:nz);
ix3 = boundaryFaceIndices(G, 'RIGHT', 1:nx, ny-10:ny, 1:nz);
ix4 = boundaryFaceIndices(G, 'FRONT', 1:nx/2-8, ny/2:ny, 1:nz);

figure;
subplot(1,2,1)
plotGrid(G, 'faceColor', 'none', 'EdgeAlpha', 0.1)
plotFaces(G, ix1, 'r');
plotFaces(G, ix2, 'g');
plotFaces(G, ix3, 'y')
plotFaces(G, ix4, 'm');
view(-7,60), axis tight off;
title('3D grid');

% boundary 2D
nx = Gt.cartDims(1); ny=Gt.cartDims(2);
ix1 = boundaryFaceIndices(Gt, 'BACK',  1:nx-6, 1:4, []);
ix2 = boundaryFaceIndices(Gt, 'LEFT',  1:20, 1:ny,  []);
ix3 = boundaryFaceIndices(Gt, 'RIGHT', 1:nx, ny-10:ny, []);
ix4 = boundaryFaceIndices(Gt, 'FRONT', 1:nx/2-8, ny/2:ny, []);

%remove faces connected to main fault
ix1 = ix1(Gt.faces.centroids(ix1,2)>6.714*1e6);
ix2 = ix2(Gt.faces.centroids(ix2,1)>5.4*1e5);
%
subplot(1,2,2)
plotGrid(Gt, 'faceColor', 'none', 'EdgeAlpha', 0.1)
plotGrid(Gt, sum(Gt.faces.neighbors(ix1,:),2), 'faceColor', 'r')
plotGrid(Gt, sum(Gt.faces.neighbors(ix2,:),2), 'faceColor', 'g')
plotGrid(Gt, sum(Gt.faces.neighbors(ix3,:),2), 'faceColor', 'y')
plotGrid(Gt, sum(Gt.faces.neighbors(ix4,:),2), 'faceColor', 'm')
axis tight off
title('2D grid of top surface');

bcIxVE = [ix1; ix2; ix3; ix4];
clear ix1 ix2 ix3 ix4 nx ny nz

figure
internal=all(Gt.faces.neighbors>0,2);
bcells=sum(Gt.faces.neighbors(~internal,:),2);

plotFaces(G,Gt.cells.map3DFace(bcells));
plotFaces(G,Gt.cells.map3DFace,'FaceColor','none','edgea',0.1);
plotFaces(G,find(G.faces.tag>0),'FaceColor','r');

Store data

disp(' -> Writing Johansen.mat')

if ~isdir(datadir)
   mkdir(datadir);
end

save(fullfile(datadir,'Johansen'), 'G', 'Gt', 'rock', 'rock2D', 'bcIxVE');
end