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