Thanks for develop an outstanding open-source simulation platform. Recently I was trying to construct 3D field-scale fractured geothermal model with MRST.
The fractured flow simulation was achieved successfully. However, after combining hfm and geothermal module, the built model cannot run successfully. Is MRST able to achieve
3D field-scale fractured geothermal simulation and do you have such example?
%% LOAD MRST MODULES
clc,clear
mrstModule add hfm ad-blackoil ad-core ad-props compositional geothermal mrst-gui
% path1 = 'D:\PhD_research\Multifractal_characterization\mrst2021b';
% addpath(genpath(path1));
path2 = 'D:\PhD_research\Multifractal_characterization\shale_main';
addpath(genpath(path2));
%% FRACTURE NETWORK STATISTICAL PARAMETERS
physdim=[1000 500 100]; % domain size
% Fracture sets 1 (red), 2(green), 3(yellow)
fracinput1=struct('vertices',10,...
'P32',0.0005*(1/meter),...
'normal',struct('direction',[1 0 0],'K',10),...
'size',struct('minsize',10*meter,'maxsize',50*meter,'exponent',1.5),...
'perm',1e7*milli*darcy,...
'poro',1,...
'aperture',0.001*meter,...
'circle',true);
fracinput2=fracinput1; fracinput2.normal.direction=[0 0 1];
fracinput3=fracinput1; fracinput3.normal.direction=[0 1 0];
% Exclusion zone is cylindrical with radius being (1+exclzonemult) times
% the fracture radius; height is exclzonemult times the fracture radius.
exclzonemult=0.001;
%% DFN GENERATION
tol=10^-5; % tolerance for comparison of doubles
fracplanes=[]; % empty list of fracture objects
% set 1
[fracplanes,~]=DFNgenerator(fracplanes,fracinput1,physdim,...
exclzonemult,tol);
% set 2
[fracplanes,~]=DFNgenerator(fracplanes,fracinput2,physdim,...
exclzonemult,tol);
% set 3
[fracplanes,~]=DFNgenerator(fracplanes,fracinput3,physdim,...
exclzonemult,tol);
%% SETUP GRID
celldim=[50 25 10];
G = cartGrid(celldim, physdim);
G = computeGeometry(G);
%% Make rock structure
km=10*milli*darcy;
G.rock=makeRock(G,km,0.25);
% figure; plotGrid(G,'facealpha',0);
% view(15,20);
% Add thermal props
G.rock = addThermalRockProps(G.rock, 'lambdaR', 2, 'rhoR', 2700, 'CpR', 1000);
%% PLOT DFN
colourchoice=['r','g','y'];
figure;
hold on;
plotGrid(cartGrid([1 1 1],physdim),'facealpha',0);
axis equal tight
view(45,30);
for i=1:3
index = find(vertcat(fracplanes.SetID)==i);
C=colourchoice(i);
for j=index'
X=fracplanes(j).points(:,1);
Y=fracplanes(j).points(:,2);
Z=fracplanes(j).points(:,3);
fill3(X,Y,Z,C);
end
xlabel('x','Interpreter','latex')
ylabel('y','Interpreter','latex')
zlabel('z','Interpreter','latex')
end
%% EDFM PRE-PROCESSING
tol=1e-6;
[G,fracplanes]=EDFMgrid(G,fracplanes,'Tolerance',tol);
G=fracturematrixNNC3D(G,tol);
[G,fracplanes]=fracturefractureNNCs3D(G,fracplanes,tol);
%% SETUP FLUID MODEL WITH WATER PROPERTIES
pRef = 100*barsa;
fluid = initSimpleADIFluid('phases','W',...
'mu' , 1* centi*poise , ...
'rho', 1000* kilogram/meter^3, ...
'pRef', pRef, ...
'c', 1e-5/barsa);
fluid = addThermalFluidProps(fluid, 'Cp' , 4.2e3, ...
'lambdaF', 0.6 , ...
'useEOS' , true );
%% Inititate state transient flow
state = initResSol(G, pRef); % Pressure and saturation
state.T = ones(G.cells.num,1).*(273.15+10); % Temperature
%% Define the problem - GeothermalWaterModel for pure water problem
% Define the gravity vector for a 3D x,y,z case using MRST convention
gravity reset on
% gravity([0 0 -9.81]); % gravity is downward
model = GeothermalModel(G, G.rock, fluid, [], 'extraStateOutput', true, 'outputFluxes', true);
% model.FlowDiscretization = setTimeDiscretization(model, 'fully-implicit'); % FIM
% operators = model.operators;
% model.operators = setupEDFMOperatorsTPFA(G, G.rock, tol);
% model.operators.AccDiv = operators.AccDiv;
% @(acc,flux)acc+C'*flux
% model.stepFunctionIsLinear=true;
% Define limits of temperature validity for EOS
K0 = 273.15*Kelvin;
TMin = K0; % Minimum temperature
TMax = K0 + 275*Kelvin; % Maximum temperature
pMax = 200e6*Pascal; % Maximum pressure
model.minimumTemperature = TMin;
model.maximumTemperature = TMax;
model.maximumPressure = pMax;
%% ADD INJECTOR
% totTime = 5*year;
totTime = 3000*day;
tpv = sum(model.operators.pv);
wellRadius = 0.1;
[nx, ny, nz] = deal(G.cartDims(1), G.cartDims(2), G.cartDims(3));
cellinj1 = nx/2+1:nx*ny: nz*nx*ny;
W = addWell([], G, G.rock, cellinj1, 'Type', 'rate', ...
'Val', tpv/totTime, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Injector1');
cellinj2 = nx*ny/2-nx/2+1:nx*ny: nz*nx*ny;
W = addWell(W, G, G.rock, cellinj2, 'Type', 'rate', ...
'Val', tpv/totTime, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Injector2');
cellinj3 = nx*ny/2+nx/2: nx*ny : nz*nx*ny;
W = addWell(W, G, G.rock, cellinj3, 'Type', 'rate', ...
'Val', tpv/totTime, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Injector3');
cellinj4 = nx*ny-nx/2+1 : nx*ny : nz*nx*ny;
W = addWell(W, G, G.rock, cellinj4, 'Type', 'rate', ...
'Val', tpv/totTime, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Injector4');
%% ADD PRODUCER
cellprod1 = 1 : nx*ny : nz*nx*ny;
W = addWell(W, G, G.rock, cellprod1, 'Type', 'bhp', ...
'Val', 50*barsa, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Producer1');
cellprod2 = nx : nx*ny : nz*nx*ny;
W = addWell(W, G, G.rock, cellprod2, 'Type', 'bhp', ...
'Val', 50*barsa, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Producer2');
cellprod3 = nx*ny-nx+1: nx*ny : nz*nx*ny;
W = addWell(W, G, G.rock, cellprod3, 'Type', 'bhp', ...
'Val', 50*barsa, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Producer3');
cellprod4 = nx*ny : nx*ny : nz*nx*ny;
W = addWell(W, G, G.rock, cellprod4, 'Type', 'bhp', ...
'Val', 50*barsa, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Producer4');
cellprod5 = nx*ny/2+1: nx*ny : nz*nx*ny;
W = addWell(W, G, G.rock, cellprod5, 'Type', 'bhp', ...
'Val', 50*barsa, 'Radius', wellRadius, ...
'Comp_i', [1, 0, 0], 'Name', 'Producer5');
Tinj = TMax;
W = addThermalWellProps(W, 'T', Tinj);
%% INITIAL AND BOUNDARY CONDITIONS
nt = 30;
t_nday=100;
bc = [];
timesteps = ones(nt,1)*t_nday*day;
schedule = simpleSchedule(timesteps, 'bc', bc);
schedule.control.W =W;
%% SIMULATE
[~, states,~] = simulateScheduleAD(state, model, schedule);
%% PLOT RESULTS
figure;
plotCellData(G,states{10}.pressure,1:G.Matrix.cells.num,...
'FaceAlpha',0.5,'EdgeAlpha',0.1);
plotCellData(G,states{10}.pressure,G.Matrix.cells.num+1:G.cells.num);
view(15,20);
% caxis([100 150]*barsa);
colorbar('EastOutside');
colormap(jet)
axis equal tight
box on
figure;
plotToolbar(G,states, 1:G.Matrix.cells.num,...
'FaceAlpha',0.3,'EdgeAlpha',0.9);
plotWell(G,W,'color','r');
plotToolbar(G,states, G.Matrix.cells.num+1:G.cells.num,...
'FaceAlpha',0.7,'EdgeAlpha',0.9);
view(15,40);
colorbar('EastOutside');
colormap(jet)
axis equal tight
box on
%% PLOT FRACTURE RESULTS
figure;
Gplot = createGplot(G,1,fracplanes);
plotToolbar(Gplot,states,1:G.Matrix.cells.num,...
'field', 'pressure', 'FaceAlpha',0.5,'EdgeAlpha',0.1);
plotToolbar(Gplot,states,1+G.Matrix.cells.num:G.cells.num,...
'field', 'pressure', 'FaceAlpha',0.5,'EdgeAlpha',0.1);
% colorbar('EastOutside');
colormap(jet)
hold on;
% plotGrid(G,'facealpha',0.1,'EdgeAlpha',0.1);
% xlabel('x [m]')
% ylabel('y [m]')
% caxis([1e7 1.5e8]*barsa);
view(15,40);
axis equal tight
box on
% c = cell2struct([struct2cell(a)];struct2cell(b),[fieldnames(a);])
Error using *
Incorrect dimensions for matrix multiplication. Check that the number of columns in the first matrix matches the number of rows in the
second matrix. To perform elementwise multiplication, use '.*'.
Error in * (line 188)
h.val = u*h.val;
Error in .* (line 217)
h = mtimes(u,v);
Error in RockInternalEnergy/evaluateOnDomain (line 18)
uR = model.rock.CpR.*T;
Error in StateFunctionGrouping/evaluateStateFunction (line 212)
props_struct.(name) = prop.evaluateOnDomain(model, state);
Error in StateFunctionGrouping/evaluateStateFunctionWithDependencies (line 237)
state = props.evaluateStateFunction(model, state, name);
Error in StateFunctionGrouping/evaluateDependencies (line 286)
state = props.evaluateStateFunctionWithDependencies(model, state, name);
Error in StateFunctionGrouping/evaluateStateFunctionWithDependencies (line 235)
state = props.evaluateDependencies(model, state, prop.dependencies);
Error in StateFunctionGrouping/evaluateDependencies (line 286)
state = props.evaluateStateFunctionWithDependencies(model, state, name);
Error in StateFunctionGrouping/evaluateStateFunctionWithDependencies (line 235)
state = props.evaluateDependencies(model, state, prop.dependencies);
Error in StateFunctionGrouping/get (line 189)
state = props.evaluateStateFunctionWithDependencies(model, state, name);
Error in PhysicalModel/getProp (line 969)
[p, state] = c.get(model, state, nms{sub});
Error in PhysicalModel>@(x)model.getProp(state,x) (line 1136)
varargout = cellfun(@(x) model.getProp(state, x), ...
Error in PhysicalModel/getProps (line 1136)
varargout = cellfun(@(x) model.getProp(state, x), ...
Error in GeothermalFlowDiscretization/energyConservationEquation (line 42)
energy = model.getProps(state, 'TotalThermalEnergy');
Error in GeothermalModel/getModelEquations (line 234)
[eeqs, eflux, enames, etypes] = model.FlowDiscretization.energyConservationEquation(model, state, state0, dt);
Error in PhysicalModel/getEquations (line 186)
[eqs, names, types, state] = model.getModelEquations(state0, state, dt, forces);
Error in PhysicalModel/stepFunction (line 686)
[problem, state] = model.getEquations(state0, state, dt, drivingForces, ...
Error in ReservoirModel/stepFunction (line 307)
[state, report] = stepFunction@PhysicalModel(model, state, state0, dt, drivingForces, linsolver, nonlinsolver, iteration,
varargin{:});
Error in NonLinearSolver/solveMinistep (line 374)
model.stepFunction(state, state0, dt, drivingForces, ...
Error in NonLinearSolver/solveTimestep (line 210)
solveMinistep(solver, model, state, state0_inner, dt, drivingForces);
Error in simulateScheduleAD (line 286)
[state, report] = solver.solveTimestep(state0, dt, model,...
Error in Fractured_geothermal_flow (line 185)
[~, states,~] = simulateScheduleAD(state, model, schedule);