Millepede-II V04-17-03
readMilleBinary.py
Go to the documentation of this file.
1#!/usr/bin/env python
2
3
84
85# in Python2.7, we can use the beta version of the print function
86# imports from __future__ need to happen before any other code
87from __future__ import print_function
88
89import sys
90
91# CLI module distributed with Python
92import argparse
93# packing/unpacking structured binary data with Python
94import struct
95
96parser = argparse.ArgumentParser(
97 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
98 description='read a mille binary file and print its data'
99 )
100parser.add_argument('--type', choices=['c', 'fortran', 'autodetect'], default='autodetect',
101 help='type of binary file that will be read')
102parser.add_argument('filename', help='binary file to read')
103parser.add_argument('-n', '--num-records', type=int, default=10,
104 help='Number of records (i.e. tracks) to print to terminal. Continue until the end of the file if negative.')
105parser.add_argument('-s', '--skip-records', type=int, default=0,
106 help='number of records (tracks) to skip before starting to print.')
107parser.add_argument('--min-val', type=float,
108 help='minimum value to print derivatives')
109parser.add_argument('--quiet', action='store_true',
110 help='do not print any information to terminal')
111
112arg = parser.parse_args()
113
114# the argument parser makes sure the user provides one of the elements
115# in the choices list, so if we get here, we can assume that arg.type
116# is one of them.
117Cfiles = -1
118if arg.type == 'c':
119 CFiles = 1
120elif arg.type == 'fortran':
121 CFiles = 0
122else:
123 # need to auto-detect
124 f = open(arg.filename, "rb")
125 header_words = struct.unpack('ii', f.read(8))
126 f.close()
127 Cfiles = 1 # C
128 if header_words[0] == 4 * (header_words[1] + 1):
129 Cfiles = 0 # Fortran
130 print("Detected Fortran binary file")
131
132# read file
133f = open(arg.filename, "rb")
134
135
136def unpack(typechar, number=1):
137 """unpack a certain number of the input type
138
139 We read from the file stored in the variable `f`.
140
141 Raises
142 ------
143 EOFError
144 if there is no data returned when the read is done
145 ValueError
146 if data is returned but the length does not match
147 the amount of data requested
148
149 Arguments
150 ---------
151 typechar : str
152 single-character name of type to unpack: 'i', 'f', or 'd'
153 number : int, optional
154 number of that type to unpack, default one
155
156 Returns
157 -------
158 array of input length and type, filled with data unpacked
159 from file
160 """
161 # 'i' and 'f' are 4 bytes, 'd' is 8 bytes
162 bytesper = 4
163 if typechar == 'd':
164 bytesper = 8
165
166 total_bytes = bytesper * number
167 bin_data = f.read(total_bytes)
168 if len(bin_data) != total_bytes:
169 if len(bin_data) == 0:
170 raise EOFError()
171 else:
172 raise ValueError('Requested %d bytes but only got %d from the file.' % (total_bytes, len(bin_data)))
173
174 # struct knows that 'i' is 4 bytes, 'f' is 4 bytes, and 'd' is 8 bytes
175 # https://docs.python.org/2.7/library/struct.html#format-characters
176 return struct.unpack(typechar * number, bin_data)
177
178
179nrec = 0
180try:
181 while (nrec < arg.num_records + arg.skip_records) or (arg.num_records < 0):
182# read 1 record
183 nr = 0
184 if (Cfiles == 0):
185 lenf = struct.unpack('i', f.read(4))
186
187 try:
188 length = unpack('i')
189 except EOFError:
190 # EOF is allowed on first word of format,
191 # that would mean we are done reading
192 break
193
194 # using bit-shifting instead of division since
195 # integer-division was promoted to its own operator
196 # in Python3, luckily shifting by 1 is the same as
197 # integer division by 2
198 nr = abs(length[0] >> 1)
199 nrec += 1
200
201 floattype = 'f'
202 if length[0] < 0:
203 floattype = 'd'
204
205 # read read nr floats and then nr integers
206 glder = unpack(floattype, nr)
207 inder = unpack('i', nr)
208
209 if (Cfiles == 0):
210 lenf = unpack('i')
211
212 if (nrec <= arg.skip_records): # must be after last fromfile
213 continue
214
215 if arg.quiet:
216 continue
217
218 print(" === NR ", nrec, length[0] / 2)
219
220 # no details, only header
221 if arg.num_records < 0:
222 continue
223
224 i = 0
225 nh = 0
226 ja = 0
227 jb = 0
228 jsp = 0
229 nsp = 0
230 while (i < (nr - 1)):
231 i += 1
232 while (i < nr) and (inder[i] != 0): i += 1
233 ja = i
234 i += 1
235 while (i < nr) and (inder[i] != 0): i += 1
236 jb = i
237 i += 1
238 # special data ?
239 if (ja + 1 == jb) and (glder[jb] < 0.):
240 jsp = jb
241 nsp = int(-glder[jb])
242 i += nsp - 1
243 print(' ### spec. ', nsp, inder[jsp + 1:i + 1], glder[jsp + 1:i + 1])
244 continue
245 while (i < nr) and (inder[i] != 0): i += 1
246 i -= 1
247 nh += 1
248 if (jb < i):
249# measurement with global derivatives
250 print(' -g- meas. ', nh, inder[jb + 1], jb - ja - 1, i - jb, glder[ja], glder[jb])
251 else:
252# measurement without global derivatives
253 print(' -l- meas. ', nh, inder[ja + 1], jb - ja - 1, i - jb, glder[ja], glder[jb])
254 if (ja + 1 < jb):
255 lab = []
256 val = []
257 for k in range(ja + 1, jb):
258 if arg.min_val is None:
259 lab.append(inder[k])
260 val.append(glder[k])
261 elif abs(glder[k]) >= arg.min_val:
262 lab.append(inder[k])
263 val.append(glder[k])
264 print(" local ", lab)
265 print(" local ", val)
266 if (jb + 1 < i + 1):
267 lab = []
268 val = []
269 for k in range(jb + 1, i + 1):
270 if arg.min_val is None:
271 lab.append(inder[k])
272 val.append(glder[k])
273 elif abs(glder[k]) >= arg.min_val:
274 lab.append(inder[k])
275 val.append(glder[k])
276 print(" global ", lab)
277 print(" global ", val)
278
279except EOFError:
280 if (nr > 0):
281 print(" >>> error: end of file before end of record", nrec)
282 sys.exit(1)
283except ValueError as e:
284 print(" >>> error: unable to unpack values before end of record", nrec, *(e.args))
285 sys.exit(2)
286
287print(" end of file after", nrec, "records")
288f.close()
def unpack(typechar, number=1)