Contents

Multiscale Pressure Solver: Flow Driven by Horizontal and Vertical Well

Compare the fine-grid and the multiscale pressure solver by solving the single-phase pressure equation

$$\nabla\cdot v = q, \qquad v=\textbf{--}\frac{K}{\mu}\nabla p,$$

for a Cartesian grid with isotropic, homogeneous permeability. This example is built upon the flow-solver tutorial "Using Peacemann well models".

require mimetic coarsegrid

Define the model and set data

We construct the Cartesian grid, set the permeability to 100 mD, and use the default single-phase fluid with density 1000 kg/m^3 and viscosity 1 cP.

nx = 20; ny = 20; nz = 8;
Nx =  5; Ny =  5; Nz = 2;
verbose   = false;
G         = cartGrid([nx ny nz]);
G         = computeGeometry(G);
rock.perm = repmat(100*milli*darcy, [G.cells.num, 1]);
fluid     = initSingleFluid('mu' ,    1*centi*poise     , ...
                            'rho', 1014*kilogram/meter^3);

Set two wells, one vertical and one horizontal. Note that a vertical well can be constructed by both addWell and verticalWell, so the appropriate choice depends on whether you know the well cells or the I, J, K position of the well.

W = verticalWell([], G, rock, nx, ny, 1:nz,            ...
                'Type', 'rate', 'Val', 1*meter^3/day, ...
                'Radius', .1, 'Name', 'I', 'Comp_i', [1, 0]);
W = addWell(W, G, rock, 1:nx, 'Type','bhp', ...
           'Val', 1*barsa, 'Radius', .1, 'Dir', 'x', ...
           'Name', 'P', 'Comp_i', [0, 1]);

Set up solution structures

Here we need four solution structures, two for each simulator to hold the solutions on the grid and in the wells, respectively.

xRef = initState(G, W, 0, [0, 1]);
xMs  = xRef;

Partition the grid

We partition the fine grid into a regular Nx-by-Ny-by-Nz coarse grid in index space so that each coarse block holds (nx/Nx)-by-(ny/Ny)-by-(nz/Nz) fine cells. The resulting vector p has one entry per fine-grid cell giving the index of the corresponding coarse block. After the grid is partitioned in index space, we postprocess it to make sure that all blocks consist of a connected set of fine cells. This step is superfluous for Cartesian grids, but is required for grids that are only logically Cartesian (e.g., corner-point and other mapped grids that may contain inactive or degenerate cells).

p = partitionUI(G, [Nx, Ny, Nz]);
p = processPartition(G, p, 'Verbose', verbose);

% Generate the coarse-grid structure
CG = generateCoarseGrid(G, p, 'Verbose', verbose);

Plot the partition and the well placement

clf
plotCellData(G, mod(p,2),'EdgeColor','k','FaceAlpha',0.5,'EdgeAlpha', 0.5);
plotWell(G, W, 'radius', 0.1, 'color', 'k');
view(3), axis equal tight off

Assemble linear systems

First we compute the inner product to be used in the fine-scale and coarse-scale linear systems. Then we generate the coarse-scale system

gravity off
S  = computeMimeticIP(G, rock, 'Verbose', verbose);

mu  = fluid.properties(xMs);
kr  = fluid.relperm(ones([G.cells.num, 1]), xMs);
mob = kr ./ mu;
CS  = generateCoarseSystem(G, rock, S, CG, mob, 'Verbose', verbose);

Then, we assemble the well systems for the fine and the coarse scale.

W = generateCoarseWellSystem(G, S, CG, CS, mob, rock, W);
disp('W(1):'); display(W(1));
disp('W(2):'); display(W(2));
W(1):
       cells: [8x1 double]
        type: 'rate'
         val: 1.1574e-05
           r: 0.1000
         dir: [8x1 char]
          WI: [8x1 double]
          dZ: [8x1 double]
        name: 'I'
       compi: [1 0]
    refDepth: 0
        sign: 1
          CS: [1x1 struct]

W(2):
       cells: [20x1 double]
        type: 'bhp'
         val: 100000
           r: 0.1000
         dir: [20x1 char]
          WI: [20x1 double]
          dZ: [20x1 double]
        name: 'P'
       compi: [0 1]
    refDepth: 0
        sign: []
          CS: [1x1 struct]

Solve the global flow problems

xRef = solveIncompFlow  (xRef, G, S, fluid, 'wells', W, ...
                         'Solver', S.type, 'MatrixOutput', true);
xMs  = solveIncompFlowMS(xMs , G, CG, p, S, CS, fluid, 'wells', W, ...
                         'Solver', S.type, 'MatrixOutput', true);

% Report pressure in wells.
dp = @(x) num2str(convertTo(x.wellSol(1).pressure, barsa));
disp(['DeltaP, Fine: ', dp(xRef)])
disp(['DeltaP, Ms:   ', dp(xMs )])
DeltaP, Fine: 1.2093
DeltaP, Ms:   1.2115

Plot Schur complement matrices

clf
   subplot(1,2,1); spy(xRef.A); title('Schur complement matrix, fine scale');
   subplot(1,2,2); spy(xMs.A);  title('Schur complement matrix, coarse scale');

Plot solution

clf
subplot('Position', [0.02 0.52 0.46 0.42]),
   plotGrid(G, 'FaceColor', 'none', 'EdgeColor', [.6, .6, .6]);
   plotGrid(G, W(1).cells, 'FaceColor', 'b', 'EdgeColor', 'b');
   plotGrid(G, W(2).cells, 'FaceColor', 'r', 'EdgeColor', 'r');
   title('Well cells')
   view(3), camproj perspective, axis tight equal off, camlight headlight

subplot('Position', [0.54 0.52 0.42 0.40]),
   plot(convertTo(xRef.wellSol(2).flux, meter^3/day), '-ob'); hold on
   plot(convertTo(xMs .wellSol(2).flux, meter^3/day), '-xr');
   legend('Fine', 'Multiscale')
   title('Producer inflow profile')

subplot('Position', [0.02 0.02 0.46 0.42]),
   plotCellData(G, convertTo(xRef.pressure(1:G.cells.num), barsa))
   title('Pressure, fine [bar]')
   view(3), camproj perspective, axis tight equal off, camlight headlight
   cax = caxis; colorbar

subplot('Position', [0.52 0.02 0.46 0.42]),
   plotCellData(G, convertTo(xMs.pressure(1:G.cells.num), barsa));
   title('Pressure, coarse [bar]')
   view(3), camproj perspective, axis tight equal off, camlight headlight
   caxis(cax); colorbar