Forked from
SWIFT / SWIFTsim
502 commits behind, 12 commits ahead of the upstream repository.
read_index_file.py 6.72 KiB
#!/usr/bin/env python3
import sys
import numpy as np
import mmap
import struct
import os
class DarkMatterParticle:
def __init__(self, pos, vel, acc, mass, ids):
self.pos = pos
self.vel = vel
self.acc = acc
self.mass = mass
self.ids = ids
class LogfileReader:
n_type = 7
swift_type_dark_matter = 1
# dtype for the particle's data
index_dtype = np.dtype([("ids", np.ulonglong), ("offset", np.uint64)])
def __init__(self, basename):
self.basename = basename
logfile = basename + ".dump"
self.f = open(logfile, "rb")
self.m = mmap.mmap(self.f.fileno(), 0, prot=mmap.PROT_READ)
self.read_logfile_header()
def __del__(self):
self.m.close()
self.f.close()
def read_int(self):
val = self.m.read(4)
return int.from_bytes(val, byteorder="little")
def read_uint(self):
val = self.m.read(4)
return struct.unpack("I", val)[0]
def read_offset(self):
offset = self.m.read(6)
return int.from_bytes(offset, byteorder="little")
def read_string(self):
string = self.m.read(self.string_length)
string = struct.unpack("%is" % self.string_length, string)[0]
i = string.find(b"\x00")
return string[:i]
def read_logfile_header(self):
self.m.seek(0)
self.vers = self.m.read(20)
self.major = self.read_int()
self.minor = self.read_int()
self.offset_direction = self.read_int()
self.first_record = self.read_offset()
self.string_length = self.read_uint()
self.n_masks = self.read_uint()
mask_dtype = np.dtype(
[
("name", "U%i" % self.string_length),
("value", "int32"),
("size", "uint32"),
]
)
self.masks = np.empty(self.n_masks, dtype=mask_dtype)
for i in range(self.n_masks):
self.masks[i]["name"] = self.read_string()
self.masks[i]["value"] = 1 << i
self.masks[i]["size"] = self.read_uint()
print("Fields found (name, mask, size): ", self.masks)
def read_record_header(self):
mask = self.m.read(2)
mask = struct.unpack("h", mask)[0]
if mask != 316:
print(mask)
offset = self.read_offset()
return mask, offset
def read_index(self, index_number):
filename = basename + "_%04i.index" % index_number
# Read the file
with open(filename, "rb") as f:
# read the time
time = np.fromfile(f, dtype=float, count=1)
time_int = np.fromfile(f, dtype=np.longlong, count=1)
print("Time: {}, integer time: {}".format(time[0], time_int[0]))
# read the number of particles
nparts = np.fromfile(f, dtype=np.uint64, count=LogfileReader.n_type)
print("Number of particles:", nparts)
# read if the file is sorted
sort = np.fromfile(f, dtype=np.bool, count=1)
print("File is sorted?", sort[0])
# read the memory alignment garbage
n = ((f.tell() + 7) & ~7) - f.tell()
f.read(n)
# read the particles
print("Particles data (ids / offset):")
data = []
for n in nparts:
if n == 0:
data.append(None)
continue
tmp = np.fromfile(f, dtype=LogfileReader.index_dtype, count=n)
data.append(tmp)
print("\t", data)
# print the history of new particles
n_new = np.fromfile(f, dtype=np.uint64, count=LogfileReader.n_type)
print("New particles: ", n_new)
new = []
for n in n_new:
if n == 0:
new.append(None)
continue
new.append(np.fromfile(f, dtype=LogfileReader.index_dtype, count=n))
print("\t", new)
# print the history of particles removed
n_rem = np.fromfile(f, dtype=np.uint64, count=LogfileReader.n_type)
print("Particles removed: ", n_rem)
removed = []
for n in n_rem:
if n == 0:
removed.append(None)
continue
removed.append(np.fromfile(f, dtype=LogfileReader.index_dtype, count=n))
print("\t", removed)
return data, new, removed
def seek(self, new_offset):
self.m.seek(new_offset)
def read_particle(self, mask):
flag = None
ref = self.masks["name"] == "SpecialFlags"
if mask & self.masks[ref]["value"]:
flag = self.m.read(4)
print("Flag: ", struct.unpack("i", flag)[0])
pos = None
ref = self.masks["name"] == "Coordinates"
if mask & self.masks[ref]["value"]:
pos = self.m.read(24)
pos = struct.unpack("ddd", pos)[0]
vel = None
ref = self.masks["name"] == "Velocities"
if mask & self.masks[ref]["value"]:
vel = self.m.read(12)
vel = struct.unpack("fff", vel)[0]
acc = None
ref = self.masks["name"] == "Accelerations"
if mask & self.masks[ref]["value"]:
acc = self.m.read(12)
acc = struct.unpack("fff", acc)[0]
# print(pos, vel, acc)
mass = None
ref = self.masks["name"] == "Masses"
if mask & self.masks[ref]["value"]:
mass = self.m.read(4)
mass = struct.unpack("f", mass)[0]
ids = None
ref = self.masks["name"] == "ParticleIDs"
if mask & self.masks[ref]["value"]:
ids = self.m.read(8)
ids = struct.unpack("q", ids)[0]
part = DarkMatterParticle(pos, vel, acc, mass, ids)
return part
if __name__ == "__main__":
logfile = sys.argv[-1]
basename = logfile[:-5]
# Open the logfile
reader = LogfileReader(basename)
# Read the first index file
data, _, _ = reader.read_index(0)
# Keep only the DM particles
data = data[LogfileReader.swift_type_dark_matter]
for i in range(len(data)):
if i > 10:
print("Early exit due to low performances")
break
off = data["offset"][i]
off = int(off)
index_ids = data["ids"][i]
reader.seek(off)
for i in range(10):
mask, offset = reader.read_record_header()
print(mask, offset, off)
part = reader.read_particle(mask)
if index_ids != part.ids:
raise Exception("Failed", index_ids, part.ids)
if offset == 0:
print("End of particle")
break
off += offset
reader.seek(off)