Chapter 6: Summary, Conclusions and Suggestions for Future Work
C.2 MATLAB Scripts
C.2.1. Routine: matrix_area.m
This is the main script written for the overall calculation of extracting the area of each enclosed area in a fracture network. The fracture network can be read from an existing matrix, but in this script it is generated stochastically by the function „gen_2d_fracture_network‟. Fracture networks (represented by the variable
„coordinates‟) are inputted as n by 5 matrices, where n is the number of fractures. The five
columns are the two end points, (x1, y1), (x2, y2) of the fracture, and its aperture. Before any
calculations are carried out all, fractures are truncated so that any fractures that lie partly outside the fracture network are wholly within the network (using function „truncate_network‟), and that isolated fractures are removed (using the functions
„frac_connect_boundary‟ and „remove_isolated_fractures‟). This part of the script is
similar to the script written for the effective medium work (Appendix B).
The intersections are located using the function „set_up_interaction_matrix‟. This
function outputs a matrix that shows if a fracture crosses another fracture, as well as the coordinates of the location of each intersection and indentifies the crossing fractures.
The iteration starts with the comment „%Search for polygons‟. This is the segment
searching routine described by Figures C1-C6. The function „shape_finder‟ is used to find
the polygon that can by formed with the least number of segments from a given point. The function outputs the coordinates of each of the points on the enclosed polygon. The area, the perimeter, and the number of sides of each polygon are collected.
close all clc
clear
disp('Written by Colin Leung. Last updated: 22nd of September, 2011') tic
%% Define the fracture network boundary = 10;
%Stochastically generating a fracture network coordinates = gen_2d_fracture_network(boundary); %Remove fractures outside the boundary
coordinates = truncate_network(coordinates, boundary); [interaction_matrix] = ...
set_up_interaction_matrix(coordinates, boundary); %Remove fractures not connected to the boundary
197 coordinates= ... frac_connect_boundary(coordinates, boundary,interaction_matrix); clear('interaction_matrix') [interaction_matrix] = ... set_up_interaction_matrix(coordinates, boundary); %Remove isolated or dead-end fractures
coordinates= remove_isolated_fractures(coordinates,interaction_matrix); clear('interaction_matrix')
[interaction_matrix,node_matrix] = ...
set_up_interaction_matrix(coordinates, boundary); %Count boundary as fractures
include_boundary_as_fractures clear('interaction_matrix') construct_segment_matrix node_matrix=sortrows(node_matrix,[1,2]); node_number=1; figure(2) plot_fracture_network(coordinates,boundary) hold on remaining_nodes=node_matrix; area_of_polygons=zeros(size(node_matrix,1),1); perimeter_of_polygons=zeros(size(node_matrix,1),1); number_of_sides=zeros(size(node_matrix,1),1); segment_colour=zeros(size(segment_matrix,1),1); %Search for polygons
for n=1:size(node_matrix,1) toc
disp(['node number ',num2str(n),' out of ',...
num2str(size(node_matrix,1))])
%Polygon that includes node #n
enclosed_polygon=shape_finder(remaining_nodes,n);
remaining_nodes(n,:)=[0,0,0,0];
%Colouring in the polygons if mod(n,2)==1 fill(enclosed_polygon(:,1),enclosed_polygon(:,2),'r') else fill(enclosed_polygon(:,1),enclosed_polygon(:,2),'y') end
%find the area of each polygon area_of_polygons(n)=...
polyarea(enclosed_polygon(:,1),enclosed_polygon(:,2));
198
%find the length of each segment
segment_length=zeros(size(enclosed_polygon,1)-1,1); for m=1:size(enclosed_polygon,1)-1 segment_length(m)=... sqrt((enclosed_polygon(m,1)-enclosed_polygon(m+1,1))^2 ... +(enclosed_polygon(m,2)-enclosed_polygon(m+1,2))^2); end perimeter_of_polygons(n)=sum(segment_length);
%record the number of sides for each of the polygon number_of_sides(n)=size(enclosed_polygon,1)-1;
end
%ignore the zero areas counter=0; for n=1:size(area_of_polygons) if area_of_polygons(n)~=0 counter=counter+1; end end new_area_of_polygons=zeros(counter,1); new_perimeter_of_polygons=zeros(counter,1); new_number_of_sides=zeros(counter,1); counter=0; for n=1:size(area_of_polygons) if area_of_polygons(n)~=0 counter=counter+1; new_area_of_polygons(counter)=area_of_polygons(n); new_perimeter_of_polygons(counter)=perimeter_of_polygons(n); new_number_of_sides(counter)=number_of_sides(n); end end area_of_polygons=new_area_of_polygons; perimeter_of_polygons=new_perimeter_of_polygons; number_of_sides=new_number_of_sides;
disp(['Average matrix area of this network is ',...
num2str(mean(area_of_polygons))])
disp(['Average matrix perimeter of this network is ',...
num2str(mean(new_perimeter_of_polygons))])
disp(['Average number of sides of each polygon is ',...
num2str(mean(number_of_sides))])
clear('new_area_of_polygons','counter','m','n','node_number','p',...
'remaining_nodes')
clear('new_perimeter_of_polygons','segment_length','enclosed_polygon') clear('new_number_of_sides','node_matrix_counter','number_of_nodes',...
199 C.2.2 Function: gen_2d_fracture_network.m
This function is used to generate the random fracture networks. The properties of the random networks are inputted within the function. The input of this function is the boundary of the fracture network. This function outputs a matrix; it has a row for each fracture in the fracture network, each row contains five columns, four are used to define coordinates of the start (x1,y1) and end (x2,y2) points of the fractures, the final column records the aperture.
The variables that have to be recorded in this function are the mean fracture length, and the fracture centre density. Two length distributions are studied: the lognormal distribution and the power law distribution. If the lognormal distribution is used, the log standard deviation needs to be specified. Note that when the log standard deviation is zero, all the fractures will have the same length. A truncated form of power law distribution is used in this function. If the power law distribution is used, the „fractal dimension‟, as well as the maximum and the minimum fracture lengths need to be specified.
Three different aperture distribution cases are implemented in this function: (1) the apertures are constant, or (2) are variable and directly proportional to the length of the fractures, or (3) are variable but are independent to the length of the fractures. The third case was not considered in the thesis because it is unlikely to be realistic.
function [coordinate] = gen_2d_fracture_network(boundary)
%GEN_2D_FRACTURE_NETWORK generates a 2D fracture network for testing EMT % GEN_2D_FRACTURE_NETWORK(boundary) Create a fracture
% network within a square boundary of +/- "boundary" (m) mean = 1; %mean fracture length 'mean' (m)
mean_aperture = 65e-6; %average fracture aperture (m) rho = 10; %fracture density "rho" (fracture/m^2) aperture_distribution = 1; % 1 Uniform aperture
% 2 Directly Proportional to length
% 3 Aperture independent to length, lognormal % distribution
fracture_distribution = 1; % 1 log normal, 2 power law
switch fracture_distribution
case 1
%the log-standard deviation log_sd = 0;
%mean of the normal distribution to generate the log-normal %distribution
mu= log(mean)-0.5*log_sd^2;
case 2
d = 2.2; %fractal dimension
200
lmax = 250; % maximum fracture length, unit m
otherwise
disp('something is wrong with fracture generation')
end
%Calculate the number of fracture from fracture density and network size number_of_fractures = round(rho*(2*boundary)^2);
fracture_network = zeros(number_of_fractures,4);
%Facture files contain midpoint (x,y), angle (theta) and a fracture length
for n=1:number_of_fractures
fracture_network(n,1) = -boundary+(rand()*2*boundary); %x midpoint fracture_network(n,2) = -boundary+(rand()*2*boundary); %y midpoint fracture_network(n,3) = rand()*180; %fracture orientation in degrees switch fracture_distribution case 1 %fracture length fracture_network(n,4) = exp(log_sd*randn()+mu); case 2
%Using method in Baghbanan and Jing 2007 to generate a network %of power law distributed fractures
fracture_network(n,4) = ...
(lmin^(-d)+rand()*(lmax^(-d)-lmin^(-d)))^(-1/d);
otherwise
disp('something is wrong with fracture generation') end
end
%Express fracture files as the two end points of each fracture coordinate(:,1)= fracture_network(:,1) + ... fracture_network(:,4)./2.*cosd(fracture_network(:,3)); %x1 coordinate(:,2)= fracture_network(:,2) + ... fracture_network(:,4)./2.*sind(fracture_network(:,3)); %y1 coordinate(:,3)= fracture_network(:,1) - ... fracture_network(:,4)./2.*cosd(fracture_network(:,3)); %x2 coordinate(:,4)= fracture_network(:,2) - ... fracture_network(:,4)./2.*sind(fracture_network(:,3)); %y2 switch aperture_distribution
case 1 %Constant aperture
coordinate(:,5)= mean_aperture;
case 2 %Aperture directly proportional to length
coordinate(:,5)= fracture_network(:,4)/mean* mean_aperture; case 3 %Aperture independent to length, lognormal distribution
%the log-standard deviation log_sd = 1;
%mean of the normal distribution to generate the log-normal %distribution mu= log(mean_aperture)-0.5*log_sd^2; for n=1:number_of_fractures coordinate(n,5) = exp(log_sd*randn()+mu); end end