Skip to content

Commit 321c0a2

Browse files
authored
Binary output reader (#799)
* add binary wrapper * fix comment
1 parent 131b41e commit 321c0a2

File tree

2 files changed

+248
-0
lines changed

2 files changed

+248
-0
lines changed

misc/binary_reader_example.m

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
% Example of using binary_reader_wrapper
2+
% Need to change "format" to 2 when post-processing the example cases
3+
4+
clear; clc; close all;
5+
6+
mfcPath = '..';
7+
8+
%% 1D
9+
10+
binDir = fullfile(mfcPath, 'examples', '1D_acoustic_dipole', 'binary');
11+
ti = 0;
12+
tf = 250;
13+
tDelta = 1;
14+
15+
pres = binary_reader_wrapper(binDir, ti, tf, tDelta, 1);
16+
17+
figure;
18+
contourf(pres)
19+
20+
%% 2D
21+
22+
binDir = fullfile(mfcPath, 'examples', '2D_acoustic_support5', 'binary');
23+
ti = 0;
24+
tf = 200;
25+
tDelta = 10;
26+
27+
pres = binary_reader_wrapper(binDir, ti, tf, tDelta, 2);
28+
29+
figure;
30+
for i = 1:9
31+
subplot(3,3,i)
32+
contourf(squeeze(pres(:, :, 2*i))');
33+
end
34+
35+
%% 3D
36+
37+
binDir = fullfile(mfcPath, 'examples', '3D_acoustic_support7', 'binary');
38+
ti = 0;
39+
tf = 100;
40+
tDelta = 5;
41+
42+
pres = binary_reader_wrapper(binDir, ti, tf, tDelta, 3);
43+
44+
figure;
45+
for i = 1:9
46+
subplot(3,3,i)
47+
contourf(squeeze(pres(:, :, 25, 2*i))');
48+
end

misc/binary_reader_wrapper.m

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
% Wrapper for reading MFC binary output file
2+
% Works for 1D/2D/3D with multiple processors
3+
4+
function pres = binary_reader_wrapper(binDir, ti, tf, t_delta, dim)
5+
% Add more output variables (like rho or xCoords) as desired
6+
7+
% Total time steps
8+
tArr = ti : t_delta : tf;
9+
tArrLen = length(tArr);
10+
11+
if (dim ~= 1)
12+
[iProcList, m, n, p, xIdxs, yIdxs, zIdxs, xCoords, yCoords, zCoords] = getProcIdx(binDir, tArr, dim);
13+
else
14+
% For 1D, the folder 'root' contains all the data
15+
if (isempty(binDir))
16+
error(strcat("ERROR: invalid binDir (not a binary/root folder): ", binDir))
17+
end
18+
filename = fullfile(binDir, 'root', [num2str(tArr(1)), '.dat']);
19+
dat = f_binary_reader(filename, 'n', 'real*8', 50);
20+
m = dat.m;
21+
iProcList = 1;
22+
xIdxs{1} = 1:m+1;
23+
end
24+
25+
% Loop through files for each time step
26+
for tIdx = 1:tArrLen
27+
if (mod(tIdx, 10) == 0 || tIdx == 1)
28+
disp(['Reading time step ', num2str(tIdx), ' of ', num2str(tArrLen)]);
29+
end
30+
31+
for iProc = 1 : length(iProcList)
32+
if (dim ~= 1)
33+
filename = fullfile(binDir, ['p', num2str(iProcList(iProc)-1)], [num2str(tArr(tIdx)), '.dat']);
34+
else
35+
filename = fullfile(binDir, 'root', [num2str(tArr(tIdx)), '.dat']);
36+
end
37+
dat = f_binary_reader(filename, 'n', 'real*8', 50);
38+
39+
xIdx = xIdxs{iProc};
40+
nx = m(iProc)+1;
41+
if (dim >= 2)
42+
yIdx = yIdxs{iProc};
43+
ny = n(iProc)+1;
44+
end
45+
if (dim == 3)
46+
zIdx = zIdxs{iProc};
47+
nz = p(iProc)+1;
48+
end
49+
50+
% Add more variables (like rho) as desired
51+
if (dim == 1)
52+
pres(xIdx, tIdx) = dat.pres;
53+
elseif (dim == 2)
54+
pres(xIdx, yIdx, tIdx) = reshape(dat.pres, nx, ny);
55+
elseif (dim == 3)
56+
pres(xIdx, yIdx, zIdx, tIdx) = reshape(dat.pres, nx, ny, nz);
57+
end
58+
end
59+
end
60+
end
61+
62+
%% Helper Functions
63+
64+
function [iProcList, m, n, p, xIdxs, yIdxs, zIdxs, xCoords, yCoords, zCoords] = getProcIdx(binDir, tArr, dim)
65+
% Set up global index mapping for multiple processors (only for 2D/3D, so dim == 2 or 3)
66+
67+
% Returns:
68+
% iProcList - list of folder indices corresponding to valid processors
69+
% m, n, p - number of cells in each proc (lists)
70+
% xIdxs, yIdxs, zIdxs - global index arrays for each proc
71+
% xCoords, yCoords, zCoords - global cell center coordinate arrays
72+
73+
% List folders according to processor number used for the simulation
74+
p_folders = dir( fullfile(binDir, 'p*') );
75+
nProcFolders = length(p_folders);
76+
if (nProcFolders == 0)
77+
disp("ERROR: No p_* folders found in binDir:")
78+
disp(binDir)
79+
error('No processor folders found.');
80+
end
81+
82+
% First get the coord range for each proc (using the first time step)
83+
iProcList = [];
84+
validProc = 0;
85+
for procNum = 1:nProcFolders
86+
filename = fullfile(binDir, ['p', num2str(procNum-1)], [num2str(tArr(1)), '.dat']);
87+
dat = f_binary_reader(filename, 'n', 'real*8', 50);
88+
if ((dat.m == 0) || (dim >= 2 && dat.n == 0) || (dim == 3 && dat.p == 0))
89+
continue
90+
end
91+
validProc = validProc + 1;
92+
m(validProc) = dat.m;
93+
n(validProc) = dat.n;
94+
xCoord{validProc} = dat.x_cb;
95+
yCoord{validProc} = dat.y_cb;
96+
if (dim == 3)
97+
p(validProc) = dat.p;
98+
zCoord{validProc} = dat.z_cb;
99+
end
100+
iProcList(end+1) = procNum;
101+
end
102+
nProc = validProc;
103+
assert(nProc == length(iProcList));
104+
105+
% Assign empty arrays if not used
106+
if dim < 3
107+
p = [];
108+
zCoord = {};
109+
end
110+
111+
% For each proc we build a list of processors that come before it
112+
% in a given direction by comparing the coordinates
113+
xProcOrder = cell(1, nProc);
114+
yProcOrder = cell(1, nProc);
115+
zProcOrder = {};
116+
if (dim == 3)
117+
zProcOrder = cell(1, nProc);
118+
end
119+
120+
for iProc = 1 : nProc
121+
if (dim == 2)
122+
xProcOrder{iProc} = getProcOrder(xCoord, iProc, yCoord);
123+
yProcOrder{iProc} = getProcOrder(yCoord, iProc, xCoord);
124+
elseif (dim == 3)
125+
xProcOrder{iProc} = getProcOrder(xCoord, iProc, yCoord, zCoord);
126+
yProcOrder{iProc} = getProcOrder(yCoord, iProc, xCoord, zCoord);
127+
zProcOrder{iProc} = getProcOrder(zCoord, iProc, xCoord, yCoord);
128+
end
129+
end
130+
131+
% Using the order, we compute the global indices using the proc orders
132+
for iProc = 1 : nProc
133+
xLocal{iProc} = 1:(m(iProc)+1);
134+
yLocal{iProc} = 1:(n(iProc)+1);
135+
if (dim == 3)
136+
zLocal{iProc} = 1:(p(iProc)+1);
137+
end
138+
end
139+
140+
xIdxs = getGlobalIdx(xLocal, xProcOrder);
141+
yIdxs = getGlobalIdx(yLocal, yProcOrder);
142+
zIdxs = {};
143+
if (dim == 3)
144+
zIdxs = getGlobalIdx(zLocal, zProcOrder);
145+
end
146+
147+
% Get global cell center locations
148+
for iProc = 1 : nProc
149+
xCoords( xIdxs{iProc} ) = xCoord{iProc}(1:end-1) + diff(xCoord{iProc})/2;
150+
yCoords( yIdxs{iProc} ) = yCoord{iProc}(1:end-1) + diff(yCoord{iProc})/2;
151+
if (dim == 3)
152+
zCoords( zIdxs{iProc} ) = zCoord{iProc}(1:end-1) + diff(zCoord{iProc})/2;
153+
end
154+
end
155+
% Assign empty outputs if not used
156+
if dim < 3
157+
zCoords = [];
158+
end
159+
end
160+
161+
function order = getProcOrder(coordCell, iProc, varargin)
162+
% For the processor, compute a list of processors that come it based on their coordinates
163+
164+
order = [];
165+
currentCoord = coordCell{iProc}(1);
166+
nProc = numel(coordCell);
167+
for j = 1:nProc
168+
if j == iProc
169+
continue;
170+
end
171+
if coordCell{j}(1) < currentCoord
172+
valid = true;
173+
for k = 1:length(varargin)
174+
if varargin{k}{iProc}(1) ~= varargin{k}{j}(1)
175+
valid = false;
176+
break;
177+
end
178+
end
179+
if valid
180+
order(end+1) = j;
181+
end
182+
end
183+
end
184+
end
185+
186+
function globalIdxs = getGlobalIdx(localIdxs, procOrder)
187+
% Compute the global indices for each processor
188+
189+
nProc = length(localIdxs);
190+
globalIdxs = cell(1, nProc);
191+
for i = 1:nProc
192+
offset = 0;
193+
if ~isempty(procOrder{i})
194+
for j = procOrder{i}
195+
offset = offset + length(localIdxs{j});
196+
end
197+
end
198+
globalIdxs{i} = localIdxs{i} + offset;
199+
end
200+
end

0 commit comments

Comments
 (0)