def set_item(handle, uids, value): root = handle.root if hasattr(root, 'my_data_table'): handle.remove_node(root, 'my_data_table', recursive=True) table = IndexedDataContainerTable(root, 'my_data_table', expected_number=n) for uid in uids: table[uid] = value
def __init__(self, group, meshFile): if not ("cuds_version" in group._v_attrs): group._v_attrs.cuds_version = MESH_CUDS_VERSION else: if group._v_attrs.cuds_version != MESH_CUDS_VERSION: raise ValueError( "Mesh file layout has an incompatible version") self._file = meshFile self._group = group self._data = IndexedDataContainerTable(group, 'data') self._uidData = DataContainerTable(self._group, 'item_data') if "points" not in self._group: self._create_points_table() if "edges" not in self._group: self._create_edges_table() if "faces" not in self._group: self._create_faces_table() if "cells" not in self._group: self._create_cells_table() self._items_count = { CUDSItem.POINT: lambda: self._group.points, CUDSItem.EDGE: lambda: self._group.edges, CUDSItem.FACE: lambda: self._group.faces, CUDSItem.CELL: lambda: self._group.cells }
def __init__(self, group): """ Return a reference to existing lattice in a H5CUDS group. Parameters ---------- group : HDF5 group in PyTables file reference to a group (folder) in PyTables file where the tables for lattice and data are located """ if group._v_attrs.cuds_version != LATTICE_CUDS_VERSION: raise ValueError("Lattice file layout has an incompatible version") self._group = group attrs = group.lattice.attrs self._primitive_cell = PrimitiveCell( attrs.primitive_cell[0], attrs.primitive_cell[1], attrs.primitive_cell[2], BravaisLattice(attrs.bravais_lattice)) self._size = attrs.size self._origin = attrs.origin self._table = IndexedDataContainerTable(group, 'lattice') self._data = IndexedDataContainerTable(group, 'data') self._items_count = {CUDSItem.NODE: lambda: self._table}
def main(): try: print(""" Benchmarking various operations on the IndexDataContainerTable. """) with closing(tables.open_file(filename, mode='w')) as handle: root = handle.root table = IndexedDataContainerTable(root, 'my_data_table') print("Append {}:".format(n), bench(lambda: append(handle, 1000, data_container))) with closing(tables.open_file(filename, mode='w')) as handle: root = handle.root table = IndexedDataContainerTable(root, 'my_data_table', expected_number=n) print("Append {} masked:".format(n), bench(lambda: append(handle, 1000, data_container_half))) uids = create_table(filename) sample = random.sample(uids, 300) with closing(tables.open_file(filename, mode='r')) as handle: root = handle.root table = IndexedDataContainerTable(root, 'my_data_table', expected_number=n) print("Iterate {}:".format(n), bench(lambda: iteration(table))) print('Getitem sample of 300:', bench(lambda: getitem_access(table, sample))) with closing(tables.open_file(filename, mode='a')) as handle: root = handle.root table = IndexedDataContainerTable(root, 'my_data_table', expected_number=n) print("Update item of 300 sample:", bench(lambda: setitem(table, data_container_half, sample))) finally: shutil.rmtree(temp_dir)
def open_table(self, table_name, mode='r'): handle = None try: handle = tables.open_file(self.filename, mode=mode) root = handle.root table = IndexedDataContainerTable(root, table_name, record=self.record) yield table finally: if handle is not None: handle.close()
def new_table(self, table_name): handle = None try: handle = tables.open_file(self.filename, mode='w') root = handle.root table = IndexedDataContainerTable(root, table_name, record=self.record) self.assertEqual(len(table), 0) yield table finally: if handle is not None: handle.close()
def test_creating_a_data_container_table_using_default_record(self): with closing(tables.open_file(self.filename, mode='w')) as handle: root = handle.root table = IndexedDataContainerTable(root, 'my_data_table') self.assertEqual(len(table), 0) self.assertIn('my_data_table', root) self.assertTrue(table.valid) data_column = root.my_data_table.colinstances['data'] expected_column_names = [ key.name.lower() for key in self.saved_keys ] self.assertItemsEqual(data_column._v_colnames, expected_column_names)
def create_new(cls, group, primitive_cell, size, origin, record=None): """ Create a new lattice in H5CUDS file. Parameters ---------- group : HDF5 group in PyTables file reference to a group (folder) in PyTables file where the tables for lattice and data will be located primitive_cell : PrimitiveCell primitive cell specifying the 3D Bravais lattice size : int[3] number of lattice nodes (in the direction of each axis). origin : float[3] origin of lattice record : tables.IsDescription A class that describes column types for PyTables table. """ group._v_attrs.cuds_version = LATTICE_CUDS_VERSION # If record not specified use NoUIDRecord in table initialization lattice = IndexedDataContainerTable(group, 'lattice', record if record is not None else NoUIDRecord, np.prod(size)) for i in xrange(np.prod(size)): lattice.append(DataContainer()) pc = primitive_cell lattice._table.attrs.primitive_cell = [pc.p1, pc.p2, pc.p3] lattice._table.attrs.bravais_lattice = pc.bravais_lattice lattice._table.attrs.size = size lattice._table.attrs.origin = origin IndexedDataContainerTable(group, 'data', NoUIDRecord, 1) return cls(group)
def __init__(self, group): if not ("cuds_version" in group._v_attrs): group._v_attrs.cuds_version = PARTICLES_CUDS_VERSION else: if group._v_attrs.cuds_version != PARTICLES_CUDS_VERSION: raise ValueError( "Particles file layout has an incompatible version") self._group = group self._data = IndexedDataContainerTable(group, 'data') self._particles = H5ParticleItems(group, 'particles') self._bonds = H5BondItems(group, 'bonds') self._items_count = { CUDSItem.PARTICLE: lambda: self._particles, CUDSItem.BOND: lambda: self._bonds }
class H5Particles(ABCParticles): """ An HDF5 backed particle container. """ def __init__(self, group): if not ("cuds_version" in group._v_attrs): group._v_attrs.cuds_version = PARTICLES_CUDS_VERSION else: if group._v_attrs.cuds_version != PARTICLES_CUDS_VERSION: raise ValueError( "Particles file layout has an incompatible version") self._group = group self._data = IndexedDataContainerTable(group, 'data') self._particles = H5ParticleItems(group, 'particles') self._bonds = H5BondItems(group, 'bonds') self._items_count = { CUDSItem.PARTICLE: lambda: self._particles, CUDSItem.BOND: lambda: self._bonds } @property def name(self): """ The name of the container """ return self._group._v_name @name.setter def name(self, value): self._group._f_rename(value) @property def data(self): if len(self._data) == 1: return self._data[0] else: return DataContainer() @data.setter def data(self, value): if len(self._data) == 0: self._data.append(value) else: self._data[0] = value # Particle methods ###################################################### def add_particles(self, iterable): """Add a set of particles. If the particles have a uid set then they are used. If any of the particle's uid is None then a new uid is generated for the particle. Returns ------- uid : uuid.UUID uid of particle. Raises ------ ValueError : Any particle uid already exists in the container. """ uids = [] for particle in iterable: uids.append(self._add_particle(particle)) return uids def update_particles(self, iterable): for particle in iterable: self._update_particle(particle) def get_particle(self, uid): return self._particles[uid] def remove_particles(self, uids): for uid in uids: self._remove_particle(uid) def iter_particles(self, ids=None): """Get iterator over particles""" if ids is None: return iter(self._particles) else: return self._particles.itersequence(ids) def has_particle(self, uid): """Checks if a particle with uid "uid" exists in the container.""" return uid in self._particles # Bond methods ####################################################### def add_bonds(self, iterable): """Add a set of bonds. If the bonds have an uid then they are used. If any of the bond's uid is None then a uid is generated for the bond. Returns ------- uid : uuid.UUID uid of bond Raises ------ ValueError : if an uid is given which already exists. """ uids = [] for bond in iterable: uids.append(self._add_bond(bond)) return uids def update_bonds(self, iterable): for bond in iterable: self._update_bond(bond) def get_bond(self, uid): return self._bonds[uid] def remove_bonds(self, uids): for uid in uids: self._remove_bond(uid) def iter_bonds(self, ids=None): """Get iterator over particles""" if ids is None: return iter(self._bonds) else: return self._bonds.itersequence(ids) def has_bond(self, uid): """Checks if a bond with uid "uid" exists in the container.""" return uid in self._bonds def count_of(self, item_type): """ Return the count of item_type in the container. Parameters ---------- item_type : CUDSItem The CUDSItem enum of the type of the items to return the count of. Returns ------- count : int The number of items of item_type in the container. Raises ------ ValueError : If the type of the item is not supported in the current container. """ try: return len(self._items_count[item_type]()) except KeyError: error_str = "Trying to obtain count a of non-supported item: {}" raise ValueError(error_str.format(item_type)) # Private methods --- these are temporary till we optimize things def _add_particle(self, particle): uid = particle.uid if uid is None: uid = uuid.uuid4() particle.uid = uid self._particles.add_unsafe(particle) else: self._particles.add_safe(particle) return uid def _update_particle(self, particle): self._particles.update_existing(particle) def _remove_particle(self, uid): del self._particles[uid] def _add_bond(self, bond): uid = bond.uid if uid is None: uid = uuid.uuid4() bond.uid = uid self._bonds.add_unsafe(bond) else: self._bonds.add_safe(bond) return uid def _update_bond(self, bond): self._bonds.update_existing(bond) def _remove_bond(self, uid): del self._bonds[uid]
class H5Mesh(ABCMesh): """ H5Mesh. Interface of the mesh file driver. Stores general mesh information Points and Elements such as Edges, Faces and Cells and provide the methods to interact with them. The methods are divided in four diferent blocks: (1) methods to get the related item with the provided uid; (2) methods to add a new item or replace; (3) generator methods that return iterators over all or some of the mesh items and; (4) inspection methods to identify if there are any edges, faces or cells described in the mesh. Attributes ---------- data : Data Data relative to the mesh name : String Name of the mesh See Also -------- get_point, get_edge, get_face, get_cell add_point, add_edge, add_face, add_cell update_point, update_edge, update_face, update_cell iter_points, iter_edges, iter_faces, iter_cells has_edges, has_faces, has_cells _create_points_table, _create_edges_table _create_faces_table, _create_cells_table """ def __init__(self, group, meshFile): if not ("cuds_version" in group._v_attrs): group._v_attrs.cuds_version = MESH_CUDS_VERSION else: if group._v_attrs.cuds_version != MESH_CUDS_VERSION: raise ValueError( "Mesh file layout has an incompatible version") self._file = meshFile self._group = group self._data = IndexedDataContainerTable(group, 'data') self._uidData = DataContainerTable(self._group, 'item_data') if "points" not in self._group: self._create_points_table() if "edges" not in self._group: self._create_edges_table() if "faces" not in self._group: self._create_faces_table() if "cells" not in self._group: self._create_cells_table() self._items_count = { CUDSItem.POINT: lambda: self._group.points, CUDSItem.EDGE: lambda: self._group.edges, CUDSItem.FACE: lambda: self._group.faces, CUDSItem.CELL: lambda: self._group.cells } @property def name(self): return self._group._v_name @name.setter def name(self, value): self._group._f_rename(value) @property def data(self): if len(self._data) == 1: return self._data[0] else: return DataContainer() @data.setter def data(self, value): if len(self._data) == 0: self._data.append(value) else: self._data[0] = value def get_point(self, uid): """ Returns a point with a given uid. Returns the point stored in the mesh identified by uid. If such point do not exists an exception is raised. Parameters ---------- uid : UUID uid of the desired point. Returns ------- Point Mesh point identified by uid Raises ------ Exception If the point identified by uid was not found """ if not hasattr(uid, 'hex'): message = 'Expected type for `uid` is uuid.UUID but received {!r}' raise TypeError(message.format(type(uid))) for row in self._group.points.where( 'uid == value', condvars={'value': uid.hex}): return Point( coordinates=tuple(row['coordinates']), uid=uuid.UUID(hex=row['uid'], version=4), data=self._uidData[uuid.UUID(hex=row['data'], version=4)]) else: error_str = "Trying to get an non existing point with uid: {}" raise KeyError(error_str.format(uid)) def get_edge(self, uid): """ Returns an edge with a given uid. Returns the edge stored in the mesh identified by uid. If such edge do not exists a exception is raised. Parameters ---------- uid : UUID uid of the desired edge. Returns ------- Edge Edge identified by uid Raises ------ Exception If the edge identified by uid was not found """ if not hasattr(uid, 'hex'): message = 'Expected type for `uid` is uuid.UUID but received {!r}' raise TypeError(message.format(type(uid))) for row in self._group.edges.where( 'uid == value', condvars={'value': uid.hex}): return Edge( points=tuple( uuid.UUID(hex=pb, version=4) for pb in row['points_uids'][0:row['n_points']]), uid=uuid.UUID(hex=row['uid'], version=4), data=self._uidData[uuid.UUID(hex=row['data'], version=4)]) else: error_str = "Trying to get an non existing edge with uid: {}" raise KeyError(error_str.format(uid)) def get_face(self, uid): """ Returns an face with a given uid. Returns the face stored in the mesh identified by uid. If such face do not exists a exception is raised. Parameters ---------- uid : UUID uid of the desired face. Returns ------- Face Face identified by uid Raises ------ Exception If the face identified by uid was not found """ if not hasattr(uid, 'hex'): message = 'Expected type for `uid` is uuid.UUID but received {!r}' raise TypeError(message.format(type(uid))) for row in self._group.faces.where( 'uid == value', condvars={'value': uid.hex}): return Face( uid=uuid.UUID(hex=row['uid'], version=4), points=tuple( uuid.UUID(hex=pb, version=4) for pb in row['points_uids'][:row['n_points']]), data=self._uidData[uuid.UUID(hex=row['data'], version=4)]) else: error_str = "Trying to get an non existing face with uid: {}" raise KeyError(error_str.format(uid)) def get_cell(self, uid): """ Returns an cell with a given uid. Returns the cell stored in the mesh identified by uid . If such cell do not exists a exception is raised. Parameters ---------- uid : UUID uid of the desired cell. Returns ------- Cell Cell identified by uid Raises ------ Exception If the cell identified by uid was not found """ if not hasattr(uid, 'hex'): message = 'Expected type for `uid` is uuid.UUID but received {!r}' raise TypeError(message.format(type(uid))) for row in self._group.cells.where( 'uid == value', condvars={'value': uid.hex}): return Cell( points=tuple( uuid.UUID(hex=pb, version=4) for pb in row['points_uids'][0:row['n_points']]), uid=uuid.UUID(hex=row['uid'], version=4), data=self._uidData[uuid.UUID(hex=row['data'], version=4)]) else: error_str = "Trying to get an non existing cell with id: {}" raise KeyError(error_str.format(uid)) def add_points(self, points): """ Adds a new set of points to the mesh container. Parameters ---------- points : iterable of Point Points to be added to the mesh container Raises ------ KeyError If other point with the same uid was already in the mesh """ rpoints = [] for point in points: if point.uid is None: point.uid = self._generate_uid() for row in self._group.points.where( 'uid == value', condvars={'value': point.uid.hex}): raise ValueError(err_add.format('point', point.uid)) row = self._group.points.row row['uid'] = point.uid.hex row['data'] = self._uidData.append(point.data).hex row['coordinates'] = point.coordinates row.append() rpoints.append(point.uid) self._group.points.flush() return rpoints def add_edges(self, edges): """ Adds a new set of edges to the mesh container. Parameters ---------- edges : iterable of Edge Edges to be added to the mesh container Raises ------ KeyError If other edge with the same uid was already in the mesh """ redges = [] for edge in edges: if edge.uid is None: edge.uid = self._generate_uid() else: for row in self._group.edges.where( 'uid == value', condvars={'value': edge.uid.hex}): raise ValueError(err_add.format('edge', edge.uid)) n = len(edge.points) row = self._group.edges.row row['uid'] = edge.uid.hex row['data'] = self._uidData.append(edge.data).hex row['n_points'] = n row['points_uids'] = [puid.hex for puid in edge.points] + [''] * (MAX_POINTS_IN_EDGE-n) row.append() redges.append(edge.uid) self._group.edges.flush() return redges def add_faces(self, faces): """ Adds a new set of faces to the mesh container. Parameters ---------- faces : iterable of Face Faces to be added to the mesh container Raises ------ KeyError If other face with the same uid was already in the mesh """ rfaces = [] for face in faces: if face.uid is None: face.uid = self._generate_uid() else: for row in self._group.faces.where( 'uid == value', condvars={'value': face.uid.hex}): raise ValueError(err_add.format('face', face.uid)) n = len(face.points) row = self._group.faces.row row['uid'] = face.uid.hex row['data'] = self._uidData.append(face.data).hex row['n_points'] = n row['points_uids'] = [puid.hex for puid in face.points] + [''] * (MAX_POINTS_IN_FACE-n) row.append() rfaces.append(face.uid) self._group.faces.flush() return rfaces def add_cells(self, cells): """ Adds a new set of cells to the mesh container. Parameters ---------- cells : iterable of Cell Cells to be added to the mesh container Raises ------ KeyError If other cell with the same uid was already in the mesh """ rcells = [] for cell in cells: if cell.uid is None: cell.uid = self._generate_uid() else: for row in self._group.cells.where( 'uid == value', condvars={'value': cell.uid.hex}): raise ValueError(err_add.format('cell', cell.uid)) n = len(cell.points) row = self._group.cells.row row['uid'] = cell.uid.hex row['data'] = self._uidData.append(cell.data).hex row['n_points'] = n row['points_uids'] = [puid.hex for puid in cell.points] + [''] * (MAX_POINTS_IN_CELL-n) row.append() rcells.append(cell.uid) self._group.cells.flush() return rcells def update_points(self, points): """ Updates the information of a point. Gets the mesh points identified by the same uids as the ones provided points and updates their information. Parameters ---------- points : iterable of Point Points to be updated Raises ------ KeyError If any point was not found in the mesh container. """ for point in points: for row in self._group.points.where( 'uid == value', condvars={'value': point.uid.hex}): row['coordinates'] = list(point.coordinates) self._uidData[ uuid.UUID(hex=row['data'], version=4) ] = point.data row.update() row._flush_mod_rows() break else: raise ValueError(err_upd.format('point', point.uid)) def update_edges(self, edges): """ Updates the information of an edge. Gets the mesh edges identified by the same uids as the ones provided edges and updates their information. Parameters ---------- edges : iterable of Edge Edges to be updated. Raises ------ KeyError If any edge was not found in the mesh container. """ for edge in edges: for row in self._group.edges.where( 'uid == value', condvars={'value': edge.uid.hex}): n = len(edge.points) row['n_points'] = n row['points_uids'] = [ puid.hex for puid in edge.points ] + [0] * (MAX_POINTS_IN_EDGE-n) self._uidData[ uuid.UUID(hex=row['data'], version=4) ] = edge.data row.update() row._flush_mod_rows() break else: raise ValueError(err_upd.format('edge', edge.uid)) def update_faces(self, faces): """ Updates the information of a face. Gets the mesh faces identified by the same uids as the ones provided in faces and updates their information. Parameters ---------- faces : iterable of Face Faces to be updated. Raises ------ KeyError If any face was not found in the mesh container. """ for face in faces: for row in self._group.faces.where( 'uid == value', condvars={'value': face.uid.hex}): n = len(face.points) row['n_points'] = n row['points_uids'] = [ puid.hex for puid in face.points ] + [0] * (MAX_POINTS_IN_FACE-n) self._uidData[ uuid.UUID(hex=row['data'], version=4) ] = face.data row.update() row._flush_mod_rows() break else: raise ValueError(err_upd.format('face', face.uid)) def update_cells(self, cells): """ Updates the information of every cell in cells. Gets the mesh cells identified by the same uids as the ones provided in cells and updates their information. Parameters ---------- cellss : iterable of Cell Cells to be updated. Raises ------ KeyError If any cell was not found in the mesh container. """ for cell in cells: for row in self._group.cells.where( 'uid == value', condvars={'value': cell.uid.hex}): n = len(cell.points) row['n_points'] = n row['points_uids'] = [ puid.hex for puid in cell.points ] + [0] * (MAX_POINTS_IN_CELL-n) self._uidData[ uuid.UUID(hex=row['data'], version=4) ] = cell.data row.update() row._flush_mod_rows() break else: raise ValueError(err_upd.format('cell', cell.uid)) def iter_points(self, uids=None): """ Returns an iterator over points. Parameters ---------- uids : iterable of uuid.UUID or None When the uids are provided, then the points are returned in the same order the uids are returned by the iterable. If uids is None, then all points are returned by the iterable and there is no restriction on the order that they are returned. Returns ------- iter Iterator over the points """ if uids is None: for row in self._group.points: yield Point( tuple(row['coordinates']), uuid.UUID(hex=row['uid'], version=4), self._uidData[uuid.UUID(hex=row['data'], version=4)] ) else: for uid in uids: yield self.get_point(uid) def iter_edges(self, uids=None): """ Returns an iterator over edges. Parameters ---------- uids : iterable of uuid.UUID or None When the uids are provided, then the edges are returned in the same order the uids are returned by the iterable. If uids is None, then all edges are returned by the iterable and there is no restriction on the order that they are returned. Returns ------- iter Iterator over the selected edges """ if uids is None: for row in self._group.edges: yield Edge( list(uuid.UUID(hex=pb, version=4) for pb in row['points_uids'][0:row['n_points']]), uuid.UUID(hex=row['uid'], version=4), self._uidData[uuid.UUID(hex=row['data'], version=4)] ) else: for uid in uids: yield self.get_edge(uid) def iter_faces(self, uids=None): """ Returns an iterator over faces. Parameters ---------- uids : iterable of uuid.UUID or None When the uids are provided, then the faces are returned in the same order the uids are returned by the iterable. If uids is None, then all faces are returned by the iterable and there is no restriction on the order that they are returned. Returns ------- iter Iterator over the faces """ if uids is None: for row in self._group.faces: yield Face( list(uuid.UUID(hex=pb, version=4) for pb in row['points_uids'][0:row['n_points']]), uuid.UUID(hex=row['uid'], version=4), self._uidData[uuid.UUID(hex=row['data'], version=4)] ) else: for uid in uids: yield self.get_face(uid) def iter_cells(self, uids=None): """ Returns an iterator over cells. Parameters ---------- uids : iterable of uuid.UUID or None When the uids are provided, then the cells are returned in the same order the uids are returned by the iterable. If uids is None, then all cells are returned by the iterable and there is no restriction on the order that they are returned. Returns ------- iter Iterator over the selected cells """ if uids is None: for row in self._group.cells: yield Cell( list(uuid.UUID(hex=pb, version=4) for pb in row['points_uids'][0:row['n_points']]), uuid.UUID(hex=row['uid'], version=4), self._uidData[uuid.UUID(hex=row['data'], version=4)] ) else: for uid in uids: yield self.get_cell(uid) def has_edges(self): """ Check if the mesh container has edges Returns ------- bool True of there are edges inside the mesh, False otherwise """ return self._group.edges.nrows != 0 def has_faces(self): """ Check if the mesh container has faces Returns ------- bool True of there are faces inside the mesh, False otherwise """ return self._group.faces.nrows != 0 def has_cells(self): """ Check if the mesh container has cells Returns ------- bool True of there are cells inside the mesh, False otherwise """ return self._group.cells.nrows != 0 def count_of(self, item_type): """ Return the count of item_type in the container. Parameters ---------- item_type : CUDSItem The CUDSItem enum of the type of the items to return the count of. Returns ------- count : int The number of items of item_type in the container. Raises ------ ValueError : If the type of the item is not supported in the current container. """ try: return len(self._items_count[item_type]()) except KeyError: error_str = "Trying to obtain count a of non-supported item: {}" raise ValueError(error_str.format(item_type)) def _generate_uid(self): """ Provides and uid for the object Provides an uid as defined in the standard RFC 4122 """ return uuid.uuid4() def _create_points_table(self): """ Generates the table to store points """ self._file.create_table( self._group, "points", _PointDescriptor) def _create_edges_table(self): """ Generates the table to store edges """ self._file.create_table( self._group, "edges", _EdgeDescriptor) def _create_faces_table(self): """ Generates the table to store faces """ self._file.create_table( self._group, "faces", _FaceDescriptor) def _create_cells_table(self): """ Generates the table to store cells """ self._file.create_table( self._group, "cells", _CellDescriptor)
def append(handle, n, value): root = handle.root if hasattr(root, 'my_data_table'): handle.remove_node(root, 'my_data_table', recursive=True) table = IndexedDataContainerTable(root, 'my_data_table', expected_number=n) return [table.append(value) for i in range(n)]
class H5Lattice(ABCLattice): """ H5Lattice object to use H5CUDS lattices. """ def __init__(self, group): """ Return a reference to existing lattice in a H5CUDS group. Parameters ---------- group : HDF5 group in PyTables file reference to a group (folder) in PyTables file where the tables for lattice and data are located """ if group._v_attrs.cuds_version != LATTICE_CUDS_VERSION: raise ValueError("Lattice file layout has an incompatible version") self._group = group attrs = group.lattice.attrs self._primitive_cell = PrimitiveCell( attrs.primitive_cell[0], attrs.primitive_cell[1], attrs.primitive_cell[2], BravaisLattice(attrs.bravais_lattice)) self._size = attrs.size self._origin = attrs.origin self._table = IndexedDataContainerTable(group, 'lattice') self._data = IndexedDataContainerTable(group, 'data') self._items_count = {CUDSItem.NODE: lambda: self._table} @classmethod def create_new(cls, group, primitive_cell, size, origin, record=None): """ Create a new lattice in H5CUDS file. Parameters ---------- group : HDF5 group in PyTables file reference to a group (folder) in PyTables file where the tables for lattice and data will be located primitive_cell : PrimitiveCell primitive cell specifying the 3D Bravais lattice size : int[3] number of lattice nodes (in the direction of each axis). origin : float[3] origin of lattice record : tables.IsDescription A class that describes column types for PyTables table. """ group._v_attrs.cuds_version = LATTICE_CUDS_VERSION # If record not specified use NoUIDRecord in table initialization lattice = IndexedDataContainerTable(group, 'lattice', record if record is not None else NoUIDRecord, np.prod(size)) for i in xrange(np.prod(size)): lattice.append(DataContainer()) pc = primitive_cell lattice._table.attrs.primitive_cell = [pc.p1, pc.p2, pc.p3] lattice._table.attrs.bravais_lattice = pc.bravais_lattice lattice._table.attrs.size = size lattice._table.attrs.origin = origin IndexedDataContainerTable(group, 'data', NoUIDRecord, 1) return cls(group) def get_node(self, index): """ Get a copy of the node corresponding to the given index. Parameters ---------- index : int[3] node index coordinate Returns ------- node : LatticeNode """ try: n = np.ravel_multi_index(index, self._size) except ValueError: raise IndexError('invalid index: {}'.format(index)) return LatticeNode(index, self._table[n]) def update_nodes(self, nodes): """ Updates H5Lattice data for a LatticeNode Parameters ---------- nodes : iterable of LatticeNode objects reference to LatticeNode objects """ # Find correct row for node for node in nodes: index = node.index try: n = np.ravel_multi_index(index, self._size) except ValueError: raise IndexError('invalid index: {}'.format(index)) self._table[n] = node.data def iter_nodes(self, indices=None): """ Get an iterator over the LatticeNodes described by the ids. Parameters ---------- indices : iterable set of int[3], optional node index coordinates Returns ------- A generator for LatticeNode objects """ if indices is None: for row_number, data in enumerate(self._table): index = np.unravel_index(row_number, self._size) yield LatticeNode(index, data) else: for index in indices: yield self.get_node(index) def count_of(self, item_type): """ Return the count of item_type in the container. Parameters ---------- item_type : CUDSItem The CUDSItem enum of the type of the items to return the count of. Returns ------- count : int The number of items of item_type in the container. Raises ------ ValueError : If the type of the item is not supported in the current container. """ try: return len(self._items_count[item_type]()) except KeyError: error_str = "Trying to obtain count a of non-supported item: {}" raise ValueError(error_str.format(item_type)) @property def size(self): return self._size @property def origin(self): return self._origin @property def name(self): return self._group._v_name @name.setter def name(self, value): self._group._f_rename(value) @property def data(self): if len(self._data) == 1: return self._data[0] else: return DataContainer() @data.setter def data(self, value): if len(self._data) == 0: self._data.append(value) else: self._data[0] = value