mcell_checkpoint.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #!/usr/bin/env python3
  2. ###############################################################################
  3. # #
  4. # Copyright (C) 2006-2017 by #
  5. # The Salk Institute for Biological Studies and #
  6. # Pittsburgh Supercomputing Center, Carnegie Mellon University #
  7. # #
  8. # This program is free software; you can redistribute it and/or #
  9. # modify it under the terms of the GNU General Public License #
  10. # as published by the Free Software Foundation; either version 2 #
  11. # of the License, or (at your option) any later version. #
  12. # #
  13. # This program is distributed in the hope that it will be useful, #
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of #
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  16. # GNU General Public License for more details. #
  17. # #
  18. # You should have received a copy of the GNU General Public License #
  19. # along with this program; if not, write to the Free Software #
  20. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, #
  21. # USA. #
  22. # #
  23. ###############################################################################
  24. import sys
  25. import struct
  26. import argparse
  27. class UnmarshalBuffer(object):
  28. def __init__(self, data):
  29. self.__data = data
  30. self.__offset = 0
  31. self.__endian = '<'
  32. def get_offset(self):
  33. return self.__offset
  34. offset = property(get_offset)
  35. def at_end(self):
  36. return self.__offset >= len(self.__data)
  37. def set_big_endian(self, e):
  38. if e:
  39. self.__endian = '>'
  40. else:
  41. self.__endian = '<'
  42. def next_byte(self):
  43. if sys.version_info[0] == 3:
  44. b = self.__data[self.__offset]
  45. else:
  46. b = ord(self.__data[self.__offset])
  47. self.__offset += 1
  48. return b
  49. def next_vint(self):
  50. b = self.next_byte()
  51. accum = b & 0x7f
  52. while (b & 0x80) != 0:
  53. b = self.next_byte()
  54. accum <<= 7
  55. accum |= (b & 0x7f)
  56. return accum
  57. def next_svint(self):
  58. val = self.next_vint()
  59. if val & 1:
  60. return -(val >> 1)
  61. else:
  62. return (val >> 1)
  63. def next_string(self):
  64. l = self.next_vint()
  65. return self.next_cstring(l)
  66. def next_cstring(self, l):
  67. return self.next_struct('%ds' % l)[0]
  68. def next_struct(self, tmpl):
  69. vals = struct.unpack_from(
  70. self.__endian + tmpl, self.__data, self.__offset)
  71. self.__offset += struct.calcsize(tmpl)
  72. return vals
  73. CMD_CURRENT_TIME = 1
  74. CMD_CURRENT_ITERATION = 2
  75. CMD_CHKPT_SEQ_NUM = 3
  76. CMD_RNG_STATE = 4
  77. CMD_MCELL_VERSION = 5
  78. CMD_SPECIES_TABLE = 6
  79. CMD_SCHEDULER_STATE = 7
  80. CMD_BYTE_ORDER = 8
  81. CMD_NUM_CHKPT_CMD = 9
  82. CMD_CHECKPOINT_API = 10
  83. def read_api(ub):
  84. api_version, = ub.next_struct('I')
  85. return {'api_version': api_version}
  86. def read_current_time(ub):
  87. time, = ub.next_struct('d')
  88. return {'cur_time': time}
  89. def read_current_iteration(ub):
  90. start_time, real_time = ub.next_struct('qd')
  91. return {'start_time': start_time, 'real_time': real_time}
  92. def read_chkpt_sequence(ub):
  93. seq, = ub.next_struct('I')
  94. return {'chkpt_seq': seq}
  95. def read_rng_state(ub):
  96. seed = ub.next_vint()
  97. rngtype, = ub.next_struct('c')
  98. if rngtype == b'I':
  99. ub.next_vint()
  100. aa, bb, cc = ub.next_struct('QQQ')
  101. randrsl = ub.next_struct('256Q')
  102. mm = ub.next_struct('256Q')
  103. return {'rng_seed': seed,
  104. 'rng_type': 'ISAAC64',
  105. 'rng_aa': aa,
  106. 'rng_bb': bb,
  107. 'rng_cc': cc,
  108. 'rng_rsl': randrsl,
  109. 'rng_mm': mm}
  110. elif rngtype == b'M':
  111. a, b, c, d = ub.next_struct('IIII')
  112. return {'rng_seed': seed,
  113. 'rng_type': 'SimpleRNG',
  114. 'rng_a': a,
  115. 'rng_b': b,
  116. 'rng_c': c,
  117. 'rng_d': d}
  118. else:
  119. raise Exception('Sorry -- this file seems to be malformed.')
  120. def read_byte_order(ub):
  121. bo, = ub.next_struct('I')
  122. if bo == 17:
  123. ub.set_big_endian(False)
  124. return {'endian': 'little'}
  125. elif bo == 0x10000000:
  126. ub.set_big_endian(True)
  127. return {'endian': 'big'}
  128. else:
  129. raise Exception('Unknown byte order %d' % bo)
  130. def read_mcell_version(ub):
  131. ver_len, = ub.next_struct('I')
  132. ver = ub.next_cstring(ver_len)
  133. return {'mcell_version': ver}
  134. def read_species(ub):
  135. nsp = ub.next_vint()
  136. species = {}
  137. for i in range(nsp):
  138. species_name = ub.next_string()
  139. species_id = ub.next_vint()
  140. species[species_id] = species_name
  141. return {'species': species}
  142. def read_scheduler(ub, spec):
  143. num_molecules = ub.next_vint()
  144. molecules = []
  145. for i in range(num_molecules):
  146. species = ub.next_vint()
  147. newbie = ub.next_byte()
  148. t, t2, bday, x, y, z = ub.next_struct('dddddd')
  149. orient = ub.next_svint()
  150. cmplx = ub.next_vint()
  151. m = {'species': spec[species],
  152. 'newbie': newbie != 0,
  153. 't': t,
  154. 't2': t2,
  155. 'birthday': bday,
  156. 'pos': (x, y, z),
  157. 'orient': orient}
  158. if cmplx != 0:
  159. suidx = ub.next_vint()
  160. m['cx_idx'] = cmplx
  161. m['cx_sub'] = suidx
  162. if suidx != 0:
  163. nunits = ub.next_vint()
  164. m['cx_cnt'] = nunits
  165. molecules.append(m)
  166. return {'molecules': molecules}
  167. def read_file(fname):
  168. ub = UnmarshalBuffer(open(fname, 'rb').read())
  169. data = {}
  170. while not ub.at_end():
  171. cmd = ub.next_byte()
  172. if cmd == CMD_CURRENT_TIME:
  173. d = read_current_time(ub)
  174. elif cmd == CMD_CURRENT_ITERATION:
  175. d = read_current_iteration(ub)
  176. elif cmd == CMD_CHKPT_SEQ_NUM:
  177. d = read_chkpt_sequence(ub)
  178. elif cmd == CMD_RNG_STATE:
  179. d = read_rng_state(ub)
  180. elif cmd == CMD_MCELL_VERSION:
  181. d = read_mcell_version(ub)
  182. elif cmd == CMD_SPECIES_TABLE:
  183. d = read_species(ub)
  184. elif cmd == CMD_SCHEDULER_STATE:
  185. d = read_scheduler(ub, data['species'])
  186. elif cmd == CMD_BYTE_ORDER:
  187. d = read_byte_order(ub)
  188. elif cmd == CMD_NUM_CHKPT_CMD:
  189. print("CMD_NUM_CHKPT_CMD")
  190. elif cmd == CMD_CHECKPOINT_API:
  191. d = read_api(ub)
  192. else:
  193. raise Exception(
  194. 'Unknown command %02x in file. Perhaps the file is malformed.'
  195. % cmd)
  196. data.update(d)
  197. return data
  198. def dump_data(data, annotate):
  199. # ORIENTS = ['-', '_', '+']
  200. print(' MCell version: %s' % data['mcell_version'].decode("utf-8"))
  201. print(' File endianness: %s' % data['endian'])
  202. print(' Cur time: %.15g' % data['cur_time'])
  203. print(' Start iteration: %ld' % data['start_time'])
  204. print(' Real time: %.15g' % data['real_time'])
  205. print(' Sequence: %d' % data['chkpt_seq'])
  206. rng_keys = [k for k in list(data.keys()) if k.startswith('rng_')]
  207. rng_keys.sort()
  208. for d in rng_keys:
  209. print(' %s: %*s %s' % (d, 8-len(d), '', str(data[d])))
  210. print(' Species:')
  211. species_table = data['species']
  212. species_keys = list(species_table.keys())
  213. species_keys.sort()
  214. for d in species_keys:
  215. name = species_table[d]
  216. print(' %3d: %s' % (d, name.decode("utf-8")))
  217. for m in data['molecules']:
  218. if m['species'] != name:
  219. continue
  220. if annotate:
  221. print((' %s, t: %18.15g, t2: %18.15g, bday: %18.15g '
  222. 'pos: (%18.15g, %18.15g, %18.15g)' %
  223. ('new' if m['newbie'] else 'old',
  224. m['t'],
  225. m['t2'],
  226. m['birthday'],
  227. m['pos'][0],
  228. m['pos'][1],
  229. m['pos'][2],)))
  230. # ORIENTS[m['orient'] + 1])),
  231. else:
  232. print((' %c %18.15g %18.15g %18.15g (%18.15g, %18.15g, '
  233. '%18.15g)' %
  234. ('N' if m['newbie'] else '_',
  235. m['t'],
  236. m['t2'],
  237. m['birthday'],
  238. m['pos'][0],
  239. m['pos'][1],
  240. m['pos'][2],)))
  241. # ORIENTS[m['orient'] + 1])),
  242. def setup_argparser():
  243. parser = argparse.ArgumentParser()
  244. parser.add_argument(
  245. "-a", "--annotate", action='store_true',
  246. help="annotate checkpoint output")
  247. parser.add_argument("chkpt_file", help="name of checkpoint file")
  248. return parser.parse_args()
  249. if __name__ == '__main__':
  250. args = setup_argparser()
  251. try:
  252. import psyco
  253. psyco.full()
  254. except ImportError:
  255. pass
  256. data = read_file(args.chkpt_file)
  257. dump_data(data, args.annotate)