Alternative way of coding
Show older comments
I'm trying to create an application that, based on a simple assumption of water flow, results in flooded area's on a DTM. The principle works, but the way it is done now the tool is extremely slow. I think there should be an alternative way to speed things up using the matrix functionalities in Matlab a bit better, but I don't know how. Any idea anyone?
dbstop if error
[FileName,PathName] = uigetfile('*.asc;*.txt','Selecteer ASCII gridfile');
fid = fopen([PathName FileName], 'r');
Heading = cell(6,1);
for ii = 1:6
AsciiLine = fgetl(fid);
Heading{ii,1} = AsciiLine;
end
ii = 1;
AsciiLine = fgetl(fid);
while ischar(AsciiLine)
CellLine = textscan(AsciiLine,'%f');
Grid(ii,:) = CellLine{1,1}';
ii = ii + 1;
AsciiLine = fgetl(fid);
end
fclose(fid);
TestGrid = Grid;
NoData = -9999;
TestGrid(logical(TestGrid==NoData)) = NaN;
[y x] = ndgrid(1:size(TestGrid,1),1:size(TestGrid,2));
CellSize = char(Heading(5,1));
CellSize = str2double(CellSize(max(regexp(Heading{5,1}, '\s'))+1:end));
Rainfall = 19.8;
InitialDepth = (ones(size(TestGrid))*(Rainfall/1000)).*logical(~isnan(TestGrid));
TotalVolume = sum(sum(InitialDepth))*(CellSize^2);
Waterlevel = TestGrid+InitialDepth;
WaterlevelTemp = TestGrid+InitialDepth;
Stabiel =0;
LoopTeller = 0;
[WetCellsRow WetCellsColumn WetCellsVector] = find(InitialDepth);
while Stabiel == 0
LoopTeller = LoopTeller + 1;
WaterlevelChange = zeros(size(Waterlevel));
tic
for ii = 1:size(WetCellsVector,1)
if ~isnan(TestGrid(WetCellsRow(ii),WetCellsColumn(ii))) && (Waterlevel(WetCellsRow(ii),WetCellsColumn(ii))-TestGrid(WetCellsRow(ii),WetCellsColumn(ii))) > 0
out = min(max(abs(bsxfun(@minus,x,reshape(WetCellsColumn(ii),1,1,[]))),abs(bsxfun(@minus,y,reshape(WetCellsRow(ii),1,1,[])))),[],3);
dist = min(hypot(bsxfun(@minus,y,permute(WetCellsRow(ii),[3 2 1])),bsxfun(@minus,x,permute(WetCellsColumn(ii),[3 2 1]))),[],3);
MinSurroundLevel = Waterlevel(logical(out==1));
MinSurroundLevel = MinSurroundLevel(logical(((Waterlevel(out==1)-Waterlevel(WetCellsRow(ii),WetCellsColumn(ii)))./dist(out==1))==min(((Waterlevel(out==1)-Waterlevel(WetCellsRow(ii),WetCellsColumn(ii)))./dist(out==1)))));
if Waterlevel(WetCellsRow(ii),WetCellsColumn(ii)) >= MinSurroundLevel(1,1)
MeanLevel = (sum(Waterlevel((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1)) + Waterlevel(WetCellsRow(ii),WetCellsColumn(ii)))/(size(Waterlevel((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1),1)+1);
if ((Waterlevel(WetCellsRow(ii),WetCellsColumn(ii))-TestGrid(WetCellsRow(ii),WetCellsColumn(ii)))/sum(sum(sum(logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1)))))+(Waterlevel((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1)) > MeanLevel;
WaterlevelChange(WetCellsRow(ii),WetCellsColumn(ii)) = WaterlevelChange(WetCellsRow(ii),WetCellsColumn(ii))+(MeanLevel-Waterlevel(WetCellsRow(ii),WetCellsColumn(ii)));
WaterlevelChange((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1) = WaterlevelChange(((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1))+(MeanLevel-Waterlevel(((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1)));
else
WaterlevelChange((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1) = WaterlevelChange((logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1))==1)+((Waterlevel(WetCellsRow(ii),WetCellsColumn(ii))-TestGrid(WetCellsRow(ii),WetCellsColumn(ii)))/sum(sum(sum(logical(Waterlevel == MinSurroundLevel(1,1)).*logical(out==1)))));
WaterlevelChange(WetCellsRow(ii),WetCellsColumn(ii)) = WaterlevelChange(WetCellsRow(ii),WetCellsColumn(ii))+(TestGrid(WetCellsRow(ii),WetCellsColumn(ii)) - Waterlevel(WetCellsRow(ii),WetCellsColumn(ii)));
end
end
end
end
Waterlevel = Waterlevel + WaterlevelChange;
Waterdepth = Waterlevel-TestGrid;
Waterdepth(isnan(Waterdepth)) = 0;
[WetCellsRow WetCellsColumn WetCellsVector] = find(Waterdepth);
TimerResult(LoopTeller) = toc;
if round(WaterlevelTemp(~isnan(Waterlevel))*1000) == round(Waterlevel(~isnan(Waterlevel))*1000)
Stabiel = 1;
CheckVolume = sum(sum(Waterdepth(~isnan(Waterdepth))))*(CellSize^2);
Waterlevel(isnan(Waterlevel)) = NoData;
Waterdepth(isnan(Waterdepth)) = NoData;
Files = ['Waterlevel' 'Waterdepth'];
for ii = 1:2
fid = fopen([PathName Files(ii) datestr(now,'yyyymmdd')], 'wt');
for jj = 1:6
fprintf(fid,'%s\r',char(Heading{jj,1}));
end
GridSize = size(Grid);
fprintf(fid,[repmat('%g\t',1,GridSize(2)-1) '%g\n'],Grid.');
fclose(fid);
end
fid = fopen([PathName 'TimerResult'], 'wt');
for ii = 1:size(TimerResult,1)
fprintf(fid,'%s\r',TimerResult(ii,1));
end
close(fid);
else
WaterlevelTemp = Waterlevel;
end
end
Answers (3)
Jan
on 15 Oct 2012
I'd start with cleaning the code. Examples:
- You can omit the "logical" in logical(out==1), because "out==1" replies a logical already. But instead of creating this value again and again, it would be more efficient and much nicer to do this once only and store the rsult in a new variable.
- The repeated calculation of "~isnan(Waterlevel)" wastes time also.
- Files = ['Waterlevel' 'Waterdepth']; fid = fopen([PathName Files(ii)... will most likely not do what you expect, because "Files" is one string and "Files(ii)" is the ii.th character. You need Files = {'Waterlevel' 'Waterdepth'} with curly braces.
- It is not a good idea to ask a forum to improve lines like these, when there is not even a single comment about the meaning:
dist = min(hypot(bsxfun(@minus,y,permute(WetCellsRow(ii),[3 2 1])), ...
bsxfun(@minus,x,permute(WetCellsColumn(ii),[3 2 1]))),[],3);
- Finally I strongly suggest to use the PROFILEr to find out, which lines consumes the most time.
M.J. Glasbergen
on 15 Oct 2012
0 votes
M.J. Glasbergen
on 22 Nov 2012
Categories
Find more on Spreadsheets in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!