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 ファイルではうまくいきません。単なるテスト ファイルである ~25 MB の ascii (約 240k 行) の読み込みを既に中止する必要がありました。ファイルのそれ以降のバージョンは ~500mb になります。ファイルをロードするプロセスをスピードアップする方法はありますか? 3 つの if ステートメントには満足できませんが、先頭にあるスイッチを使用して数字から '#' を分離する方法がわかりませんでした。クラスごとに 'head' を区別します。つまり、ischar または isnumeric をチェックしようとしましたが、変数 'head' は文字列として読み取られるため、常に = の場合にischarなり、決してisnumeric=になることはありませんtrue。また、if-cases を使用できるようにするためにトークナイザーを使用してから、次の行をまとめることにもあまり満足していません。str2num([head rem]);、これはおそらく多くの時間を消費します。しかし、私はそれを行う方法を知りませんでした。したがって、私のコードをどのように適応させるかについて何か有益な提案があれば、非常に感謝しています!

よい日曜日を、よろしくお願いします!

4

2 に答える 2

2

以下のコードは、約 7 秒でステップあたり 5 ノードで約 70000 タイムステップを読み取ります。それはあなたのコードが行うことのほとんどを行い、コードの余分な機能を追加するのに十分簡単なはずです. これをより速く行う方法は他にもありますが、うまくいけばこれで十分です。

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 万行のファイル (1 ステップあたり 5 ノードで 340000 タイム ステップ) で試してみたところ、実行に約 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

何かを変更する前に最初に行うことは、すべての出力配列をPRE-ALLOCATE
することです。 コードは and を出力time_stepsdata、すべてループ内で成長します。これにより、パフォーマンスが低下する可能性があります。

各タイム ステップの間に常に 5 つのラインがあると仮定します。

ループの前に次の行を追加します

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 に答える