0

我编写了这段代码,它运行良好,但对于我的目的来说太慢了:

%%% load nodal data %%% 
path = sprintf('%sfile.dat',directory);
fid = fopen(path);

num_nodes = textscan(fid,'%s %s %s %s %d',1,'delimiter', ' ');
num_nodes = num_nodes{5};
header = textscan(fid,'%s',7,'delimiter', '\t');

k = 0;
while ~feof(fid)

    line        = fgetl(fid);
    [head,rem]  = strtok(line,[' ',char(9)]); 

    if head == '#'
        k = k+1;
        j = 1;
        time_steps(k)  = sscanf(rem, [' Output at t = %d']);        
    end

    if ~isempty(head)
        if head ~= '#'
            data(j,:,k)  = str2num([head rem]); 
            j = j+1;
        end
    end

end
fclose(fid);

nodal_data = struct('header',header,'num_nodes',num_nodes,'time_steps',time_steps,'data',data);

我正在读到 Matlab 的 ascii 看起来像这样:

# Number of Nodes: 120453
#X                  Y                   Z                   depth               vel_x               vel_y               wse             
# Output at t = 0
       76456.003              184726             3815.75                   0                   0                   0             3815.75
       76636.003              184726             3728.25                   0                   0                   0             3728.25
       76816.003              184726                3627                   0                   0                   0                3627
       76996.003              184726             3527.75                   0                   0                   0             3527.75
       77176.003              184726              3371.5                   0                   0                   0              3371.5
# Output at t = 36000.788
       76456.003              184726             3815.75                   0                   0                   0             3815.75
       76636.003              184726             3728.25                   0                   0                   0             3728.25
       76816.003              184726                3627                   0                   0                   0                3627
       76996.003              184726             3527.75                   0                   0                   0             3527.75
       77176.003              184726              3371.5                   0                   0                   0              3371.5

虽然我编写的代码适用于非常小的文件,但对于较大的 ascii 文件,它却让我大吃一惊。我已经不得不中止加载 ~25mb ascii(大约 240k 行),这只是一个测试文件。该文件的更高版本将约为 500mb。有没有一种方法可以加快加载文件的过程我对 3 个 if 语句不满意,但我不知道如何用开关将“#”与数字分开,特别是因为我无法按类区分 'head',即我试图检查 ischar 或 isnumeric,但由于变量 'head' 被读取为字符串,它总是会出现这种情况,ischar而且永远不会isnumeric= true。我也不太喜欢使用标记器来使用 if-cases,然后在这里拼凑一行:str2num([head rem]);,因为这可能会消耗大量时间。但是,我不知道该怎么做。因此,如果您对如何调整我的代码有任何有用的建议,我将不胜感激!

祝你星期天愉快,提前谢谢你!

4

2 回答 2

2

下面的代码在大约 7 秒内读取了大约 70000 个时间步,每步 5 个节点。它完成了您的代码所做的大部分工作,并且应该很容易添加代码的额外功能。还有其他方法可以更快地做到这一点,但希望这应该足够了。

filename = 'd:\temp\input.txt';

filetext = fileread(filename);
headerLines = 2;
valuesPerLine = 7;
expr = '[^\n]*[^\n]*';
lines = regexp(filetext, expr, 'match');
isTimeStep = cellfun(@(x) strncmp(x,'#',1), lines );
numTimeSteps = sum(isTimeStep)-headerLines;
nodesPerStep = ((length(lines)-headerLines) / numTimeSteps ) - 1;
data = zeros(nodesPerStep, valuesPerLine, numTimeSteps);

for timeStep = 1:numTimeSteps
    lineIndex = headerLines + (timeStep-1) * (nodesPerStep + 1) + 2;
    for node = 1:nodesPerStep
        data(node, :, timeStep ) = sscanf(lines{lineIndex},'%f');
        lineIndex = lineIndex + 1;
    end    
end

刚刚在一个 200 万行文件(340000 个时间步,每步 5 个节点)上进行了尝试,运行大约需要 36 秒。

如果您想要一个没有编码循环的解决方案,您可以从代码中替换

data = zeros(....

values = cellfun(@(x) sscanf(x,'%f'),lines(~isTimeStep),'uniformoutput',false);
data = reshape(cell2mat(values), nodesPerStep, valuesPerLine, numTimeSteps);

但它需要大约 50% 的时间才能运行。

于 2013-05-19T10:57:47.413 回答
1

在更改任何内容之前要做的第一件事是预先分配所有输出数组:
您的代码输出time_stepsdata,都在循环内增长。这会扼杀你的表现。

假设每个时间步之间总是有五行

在循环之前添加以下行

data = reshape( NaN( num_nodes, 7 ), [], 7, 5 ); % assuming 7 columns and 5 lines for each time step
time_steps = NaN( num_nodes / 5 );

在循环之后只是丢弃剩余的 NaN

data( isnan(data) ) = [];
time_step( isnan(time_step) ) = [];
于 2013-05-19T09:13:43.630 回答