def _load_data(self): """Function to read in all particle data for a simulation. """ particles = self pointer_location = {particle: [0] * len(self.times) for particle in particles} for particle in particles: if len(particle._positions) == 0 and len(particle._tags) == 0: for t in range(len(self.times)): size = 0 for mesh in self._file_paths.keys(): size += particle.n_particles[mesh][t] for quantity in particle.quantities: particle._data[quantity.quantity].append(np.empty((size,), dtype=np.float32)) particle._positions.append(np.empty((size, 3), dtype=np.float32)) particle._tags.append(np.empty((size,), dtype=int)) for mesh, file_path in self._file_paths.items(): with open(file_path, 'rb') as infile: # Initial offset (ONE, fds version and number of particle classes) offset = 3 * fdtype.INT.itemsize # Number of quantities for each particle class (plus an INTEGER_ZERO) offset += fdtype.new((('i', 2),)).itemsize * len(particles) # 30-char long name and unit information for each quantity offset += fdtype.new((('c', 30),)).itemsize * 2 * sum( [len(particle.quantities) for particle in particles]) infile.seek(offset) for t in range(len(self.times)): # Skip time value infile.seek(fdtype.FLOAT.itemsize, 1) # Read data for each particle class for particle in particles: # Read number of particles in each class n_particles = fdtype.read(infile, fdtype.INT, 1)[0][0][0] offset = pointer_location[particle][t] # Read positions dtype_positions = fdtype.new((('f', 3 * n_particles),)) pos = fdtype.read(infile, dtype_positions, 1)[0][0] particle._positions[t][offset: offset + n_particles] = pos.reshape((n_particles, 3), order='F').astype(float) # Read tags dtype_tags = fdtype.new((('i', n_particles),)) particle._tags[t][offset: offset + n_particles] = \ fdtype.read(infile, dtype_tags, 1)[0][0] # Read actual quantity values if len(particle.quantities) > 0: dtype_data = fdtype.new( (('f', str((n_particles, len(particle.quantities)))),)) data_raw = fdtype.read(infile, dtype_data, 1)[0][0].reshape( (n_particles, len(particle.quantities)), order='F') for q, quantity in enumerate(particle.quantities): particle._data[quantity.quantity][t][ offset:offset + n_particles] = data_raw[:, q].astype(float) pointer_location[particle][t] += particle.n_particles[mesh][t]
class SubPlot3D: """Subplot of a pl3d output for a single mesh. :ivar mesh: The mesh containing the data. """ # Offset of the binary file to the end of the file header. _offset = fdtype.new((('i', 3), )).itemsize + fdtype.new( (('i', 4), )).itemsize def __init__(self, file_path: str, mesh: Mesh): self.file_path = file_path # Path to the binary data file self.mesh = mesh @property def data(self) -> np.ndarray: """Method to lazy load the 3D data for each quantity of a single mesh. :returns: 4D numpy array with (x,y,z,q) as dimensions, while q represents the 5 quantities. """ if not hasattr(self, "_data"): with open(self.file_path, 'rb') as infile: dtype_data = fdtype.new( (('f', self.mesh.dimension.size() * 5), )) infile.seek(self._offset) self._data = fdtype.read(infile, dtype_data, 1)[0][0].reshape( self.mesh.dimension.shape() + (5, ), order='F') return self._data def clear_cache(self): """Remove all data from the internal cache that has been loaded so far to free memory. """ if hasattr(self, "_data"): del self._data
def __init__(self, mesh: Mesh, iso_filepath: str, times: List, viso_filepath: str = ""): self.mesh = mesh self.file_path = iso_filepath if viso_filepath != "": self.v_file_path = viso_filepath with open(self.file_path, 'rb') as infile: nlevels = fdtype.read(infile, fdtype.INT, 3)[2][0][0] dtype_header_levels = fdtype.new((('f', nlevels), )) dtype_header_zeros = fdtype.combine(fdtype.INT, fdtype.new((('i', 2), ))) self._offset = fdtype.INT.itemsize * 3 + dtype_header_levels.itemsize + \ dtype_header_zeros.itemsize self.times = times self.n_vertices = list() self.n_triangles = list() if not settings.LAZY_LOAD: self._load_data(infile) if self.has_color_data: if not settings.LAZY_LOAD: with open(self.v_file_path, 'rb') as infile: self._load_vdata(infile)
def _load_vdata(self, infile: BinaryIO): """Loads all color data for all isosurfaces in a given viso file. """ self._colors = np.empty((self.n_t, ), dtype=object) dtype_nverts = fdtype.new((('i', 4), )) infile.seek(fdtype.INT.itemsize * 2) t = fdtype.read(infile, fdtype.FLOAT, 1) while t.size != 0: time_index = self.times.index(t[0][0][0]) n_vertices = fdtype.read(infile, dtype_nverts, 1)[0][0][2] if n_vertices > 0: self._colors[time_index] = fdtype.read( infile, fdtype.new((('f', n_vertices), )), 1) t = fdtype.read(infile, fdtype.FLOAT, 1)
def _load_data(self, infile: BinaryIO): """Loads data for the subsurface which is given in an iso file. """ dtype_time = fdtype.new((('f', 1), ('i', 1))) dtype_dims = fdtype.new((('i', 2), )) self._vertices = list() self._triangles = list() self._surfaces = list() infile.seek(self._offset) time_data = fdtype.read(infile, dtype_time, 1) while time_data.size != 0: self.times.append(time_data[0][0][0]) dims_data = fdtype.read(infile, dtype_dims, 1) n_vertices = dims_data[0][0][0] n_triangles = dims_data[0][0][1] if n_vertices > 0: dtype_vertices = fdtype.new((('f', 3 * n_vertices), )) dtype_triangles = fdtype.new((('i', 3 * n_triangles), )) dtype_surfaces = fdtype.new((('i', n_triangles), )) self._vertices.append( fdtype.read(infile, dtype_vertices, 1)[0][0].reshape( (n_vertices, 3)).astype(float)) self._triangles.append( fdtype.read(infile, dtype_triangles, 1)[0][0].reshape( (n_triangles, 3)).astype(int) - 1) self._surfaces.append( fdtype.read(infile, dtype_surfaces, 1)[0][0].astype(int) - 1) self.n_vertices.append(n_vertices) self.n_triangles.append(n_triangles) else: self._vertices.append(np.empty((0, 3))) self._triangles.append(np.empty((0, 3))) self._surfaces.append(np.empty((0, ))) self.n_vertices.append(0) self.n_triangles.append(0) time_data = fdtype.read(infile, dtype_time, 1) self.n_t = len(self.times)
def data(self) -> np.ndarray: """Method to lazy load the 3D data for each quantity of a single mesh. :returns: 4D numpy array with (x,y,z,q) as dimensions, while q represents the 5 quantities. """ if not hasattr(self, "_data"): with open(self.file_path, 'rb') as infile: dtype_data = fdtype.new( (('f', self.mesh.dimension.size() * 5), )) infile.seek(self._offset) self._data = fdtype.read(infile, dtype_data, 1)[0][0].reshape( self.mesh.dimension.shape() + (5, ), order='F') return self._data
def _load_isosurface(self, smv_file: TextIO, line: str): """Loads the isosurface at current pointer position. """ double_quantity = line[0] == 'T' mesh_index = int(line.strip().split()[1]) - 1 iso_filename = smv_file.readline().strip() iso_id = int(iso_filename.split('_')[-1][:-4]) iso_file_path = os.path.join(self.root_path, iso_filename) if double_quantity: viso_file_path = os.path.join(self.root_path, smv_file.readline().strip()) quantity = smv_file.readline().strip() label = smv_file.readline().strip() unit = smv_file.readline().strip() if double_quantity: v_quantity = smv_file.readline().strip() v_label = smv_file.readline().strip() v_unit = smv_file.readline().strip() if iso_id not in self.isosurfaces: with open(iso_file_path, 'rb') as infile: nlevels = fdtype.read(infile, fdtype.INT, 3)[2][0][0] dtype_header_levels = fdtype.new((('f', nlevels), )) levels = fdtype.read(infile, dtype_header_levels, 1)[0] if double_quantity: if iso_id not in self.isosurfaces: self.isosurfaces[iso_id] = Isosurface(iso_id, double_quantity, quantity, label, unit, levels, v_quantity=v_quantity, v_label=v_label, v_unit=v_unit) self.isosurfaces[iso_id]._add_subsurface( self.meshes[mesh_index], iso_file_path, viso_file_path=viso_file_path) else: if iso_id not in self.isosurfaces: self.isosurfaces[iso_id] = Isosurface(iso_id, double_quantity, quantity, label, unit, levels) self.isosurfaces[iso_id]._add_subsurface(self.meshes[mesh_index], iso_file_path)
def _load_boundary_data(self, smv_file: TextIO, line: str, cell_centered: bool): """Loads the boundary data at current pointer position. """ line = line.split() mesh_index = int(line[1]) - 1 mesh = self.meshes[mesh_index] filename = smv_file.readline().strip() quantity = smv_file.readline().strip() label = smv_file.readline().strip() unit = smv_file.readline().strip() bid = int(filename.split('_')[-1][:-3]) - 1 file_path = os.path.join(self.root_path, filename) patches = dict() if os.path.exists(file_path + ".bnd"): times = list() lower_bounds = list() upper_bounds = list() with open(file_path + ".bnd", 'r') as bnd_file: for line in bnd_file: splits = line.split() times.append(float(splits[0])) lower_bounds.append(float(splits[1])) upper_bounds.append(float(splits[2])) times = np.array(times) lower_bounds = np.array(lower_bounds, dtype=np.float32) upper_bounds = np.array(upper_bounds, dtype=np.float32) n_t = times.shape[0] else: times = None n_t = -1 lower_bounds = np.array([0.0], dtype=np.float32) upper_bounds = np.array([np.float32(-1e33)], dtype=np.float32) with open(file_path, 'rb') as infile: # Offset of the binary file to the end of the file header. offset = 3 * fdtype.new((('c', 30), )).itemsize infile.seek(offset) n_patches = fdtype.read(infile, fdtype.INT, 1)[0][0][0] dtype_patches = fdtype.new((('i', 9), )) patch_infos = fdtype.read(infile, dtype_patches, n_patches) offset += fdtype.INT.itemsize + dtype_patches.itemsize * n_patches patch_offset = fdtype.FLOAT.itemsize for patch_info in patch_infos: patch_info = patch_info[0] extent, dimension = self._indices_to_extent( patch_info[:6], mesh) orientation = patch_info[6] obst_index = patch_info[7] p = Patch(file_path, dimension, extent, orientation, cell_centered, patch_offset, offset, n_t) # Skip obstacles with index 0, which just gives the extent of the (whole) mesh faces # These might be needed in case of "closed" mesh faces if obst_index != 0: obst_index -= 1 # Account for fortran indexing if obst_index not in patches: patches[obst_index] = list() patches[obst_index].append(p) patch_offset += fdtype.new( (('f', str(p.dimension.shape(cell_centered=False))), )).itemsize for obst_index, p in patches.items(): for patch in p: patch._post_init(patch_offset) self._subobstructions[mesh][obst_index]._add_patches( bid, cell_centered, quantity, label, unit, p, times, n_t, lower_bounds, upper_bounds)