def read_grid(self, name='gridfunc', idx=0, *args, **kwargs): """ Reads a grid in the current SIESTA.grid.nc file Enables the reading and processing of the grids created by SIESTA """ # Swap as we swap back in the end sc = self.read_sc().swapaxes(0, 2) # Create the grid nx = len(self._dimension('n1')) ny = len(self._dimension('n2')) nz = len(self._dimension('n3')) if name is None: v = self._variable('gridfunc') else: v = self._variable(name) # Create the grid, SIESTA uses periodic, always grid = Grid([nz, ny, nx], bc=Grid.Periodic, sc=sc, dtype=v.dtype) if len(v[:].shape) == 3: grid.grid = v[:, :, :] else: grid.grid = v[idx, :, :, :] # Read the grid, we want the z-axis to be the fastest # looping direction, hence x,y,z == 0,1,2 return grid.swapaxes(0, 2)
def test_default(sisl_tmp): f = sisl_tmp('GRID.xsf', _dir) print(f) grid = Grid(0.2) grid.grid = np.random.rand(*grid.shape) grid.write(f) assert grid.geometry is None
def test_imaginary(sisl_tmp): f = sisl_tmp('GRID.xsf', _dir) geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) grid = Grid(0.2, geometry=geom, dtype=np.complex128) grid.grid = np.random.rand(*grid.shape) + 1j*np.random.rand(*grid.shape) grid.write(f) assert not grid.geometry is None
def read_grid(self, spin=0, *args, **kwargs): """ Read grid contained in the Grid file Parameters ---------- spin : int or array_like, optional the spin-index for retrieving one of the components. If a vector is passed it refers to the fraction per indexed component. I.e. ``[0.5, 0.5]`` will return sum of half the first two components. Default to the first component. """ # Read the sizes nspin, mesh = _siesta.read_grid_sizes(self.file) # Read the cell and grid cell = _siesta.read_grid_cell(self.file) grid = _siesta.read_grid(self.file, nspin, mesh[0], mesh[1], mesh[2]) if isinstance(spin, Integral): grid = grid[:, :, :, spin] else: if len(spin) > grid.shape[0]: raise ValueError(self.__class__.__name__ + '.read_grid requires spin to be an integer or ' 'an array of length equal to the number of spin components.') g = grid[:, :, :, 0] * spin[0] for i, scale in enumerate(spin[1:]): g += grid[:, :, :, 1+i] * scale grid = g cell = np.array(cell.T, np.float64) cell.shape = (3, 3) g = Grid(mesh, sc=SuperCell(cell), dtype=np.float32) g.grid = np.array(grid.swapaxes(0, 2), np.float32) * self.grid_unit return g
def read_grid(self): """ Returns `Grid` object from the CUBE file """ geom = self.read_geom() # Now seek behind to read grid sizes self.fh.seek(0) # Skip headers and origo self.readline() self.readline() na = int(self.readline().split()[0]) ngrid = [0] * 3 for i in [0, 1, 2]: tmp = self.readline().split() ngrid[i] = int(tmp[0]) # Read past the atoms for i in range(na): self.readline() grid = Grid(ngrid, dtype=np.float32, geom=geom) grid.grid = np.loadtxt(self.fh, dtype=grid.dtype) grid.grid.shape = ngrid return grid
def test_default_size(sisl_tmp): f = sisl_tmp('GRID.cube', _dir) grid = Grid(0.2, sc=2.0) grid.grid = np.random.rand(*grid.shape) grid.write(f) read = grid.read(f) assert np.allclose(grid.grid, read.grid) assert grid.geometry is None assert len(read.geometry) == 1
def read_grid(self, name, idx=0): """ Reads a grid in the current SIESTA.nc file Enables the reading and processing of the grids created by SIESTA """ # Swap as we swap back in the end geom = self.read_geom().swapaxes(0, 2) # Shorthand g = self.groups['GRID'] # Create the grid nx = len(g.dimensions['nx']) ny = len(g.dimensions['ny']) nz = len(g.dimensions['nz']) # Shorthand variable name v = g.variables[name] # Create the grid, SIESTA uses periodic, always grid = Grid([nz, ny, nx], bc=Grid.Periodic, dtype=v.dtype) if len(v[:].shape) == 3: grid.grid = v[:, :, :] else: grid.grid = v[idx, :, :, :] try: u = v.unit if u == 'Ry': # Convert to ev grid *= Ry2eV except: # Simply, we have no units pass # Read the grid, we want the z-axis to be the fastest # looping direction, hence x,y,z == 0,1,2 grid = grid.swapaxes(0, 2) grid.set_geom(geom) return grid
def test_geometry(sisl_tmp): f = sisl_tmp('GRID.cube', _dir) geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) grid = Grid(0.2, geometry=geom) grid.grid = np.random.rand(*grid.shape) grid.write(f) read = grid.read(f) assert np.allclose(grid.grid, read.grid) assert not grid.geometry is None assert not read.geometry is None assert grid.geometry == read.geometry
def test_imaginary_fail_geometry(sisl_tmp): fr = sisl_tmp('GRID_real.cube', _dir) fi = sisl_tmp('GRID_imag.cube', _dir) geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) grid = Grid(0.2, geometry=geom, dtype=np.complex128) grid.grid = np.random.rand(*grid.shape) + 1j*np.random.rand(*grid.shape) grid.write(fr) # Assert it fails on geometry grid2 = Grid(0.3, dtype=np.complex128) grid2.write(fi, imag=True) grid.read(fr, imag=fi)
def read_grid(self, index=0, dtype=np.float64, *args, **kwargs): """ Read grid contained in the Grid file Parameters ---------- index : int or array_like, optional the spin-index for retrieving one of the components. If a vector is passed it refers to the fraction per indexed component. I.e. ``[0.5, 0.5]`` will return sum of half the first two components. Default to the first component. dtype : numpy.float64, optional default data-type precision """ index = kwargs.get('spin', index) # Read the sizes and cell nspin, mesh = self.read_grid_size() cell = _siesta.read_grid_cell(self.file) _bin_check(self, 'read_grid', 'could not read grid cell.') grid = _siesta.read_grid(self.file, nspin, mesh[0], mesh[1], mesh[2]) _bin_check(self, 'read_grid', 'could not read grid.') if isinstance(index, Integral): grid = grid[:, :, :, index] else: if len(index) > grid.shape[0]: raise ValueError( self.__class__.__name__ + '.read_grid requires spin to be an integer or ' 'an array of length equal to the number of spin components.' ) # It is F-contiguous, hence the last index g = grid[:, :, :, 0] * index[0] for i, scale in enumerate(index[1:]): g += grid[:, :, :, 1 + i] * scale grid = g cell = np.array(cell.T, np.float64) cell.shape = (3, 3) # Simply create the grid (with no information) # We will overwrite the actual grid g = Grid([1, 1, 1], sc=SuperCell(cell)) # NOTE: there is no need to swap-axes since the returned array is in F ordering # and thus the first axis is the fast (x, y, z) is retained g.grid = (grid * self.grid_unit).astype(dtype=dtype, order='C', copy=False) return g
def test_isosurface_non_orthogonal(self, setup): pytest.importorskip("skimage", reason="scikit-image not available") # If the grid is non-orthogonal, there should be 20 unique values # (10 for each (HERE), see test_isosurface_orthogonal) grid = Grid(0.1, sc=[[1, 0, 0], [0, 1, 0], [0, 2, 1]]) grid.grid = np.tile([1, 2, 3, 4, 5, 4, 3, 2, 1, 0], 100).reshape(10, 10, 10) verts, *returns = grid.isosurface(2.5) # we have twice as many since the 3rd lattice vector has components in y assert np.unique(verts[:, 1]).shape == (20, ) assert np.unique(verts[:, 2]).shape == (2, )
def test_isosurface_orthogonal(self, setup): pytest.importorskip("skimage", reason="scikit-image not available") # Build an empty grid grid = Grid(0.1, sc=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) # Fill it with some values that have a clear isosurface grid.grid = np.tile([1, 2, 3, 4, 5, 4, 3, 2, 1, 0], 100).reshape(10, 10, 10) # Calculate the isosurface for the value of 2.5 verts, *returns = grid.isosurface(2.5) # The third dimension should contain only two coordinates # [1, 2, (HERE) 3, 4, 5, 4, 3, (HERE) 2, 1, 0] assert np.unique(verts[:, 1]).shape == (10, ) assert np.unique(verts[:, 2]).shape == (2, )
def read_grid(self, index=0, dtype=np.float64): """ Reads the charge density from the file and returns with a grid (plus geometry) Parameters ---------- index : int, optional the index of the grid to read. For a spin-polarized VASP calculation 0 and 1 are allowed, UP/DOWN. For non-collinear 0, 1, 2 or 3 is allowed which equals, TOTAL, x, y, z charge density with the Cartesian directions equal to the charge magnetization. dtype : numpy.dtype, optional grid stored dtype Returns ------- Grid : charge density grid with associated geometry """ geom = self.read_geometry() V = geom.sc.volume # Now we are past the cell and geometry # We can now read the size of CHGCAR self.readline() nx, ny, nz = list(map(int, self.readline().split())) n = nx * ny * nz i = 0 vals = [] while i < n * (index + 1): dat = [float(l) for l in self.readline().split()] vals.append(dat) i += len(dat) vals = np.swapaxes(np.array(vals).reshape(nz, ny, nx), 0, 2) vals = vals[index * n:(index + 1) * n] / V # Create the grid with data # Since we populate the grid data afterwards there # is no need to create a bigger grid than necessary. grid = Grid([1, 1, 1], dtype=dtype, geometry=geom) grid.grid = vals return grid
def test_imaginary(sisl_tmp): fr = sisl_tmp('GRID_real.cube', _dir) fi = sisl_tmp('GRID_imag.cube', _dir) geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) grid = Grid(0.2, geometry=geom, dtype=np.complex128) grid.grid = np.random.rand(*grid.shape) + 1j*np.random.rand(*grid.shape) grid.write(fr) grid.write(fi, imag=True) read = grid.read(fr) read_i = grid.read(fi) read.grid = read.grid + 1j*read_i.grid assert np.allclose(grid.grid, read.grid) assert not grid.geometry is None assert not read.geometry is None assert grid.geometry == read.geometry read = grid.read(fr, imag=fi) assert np.allclose(grid.grid, read.grid) read = grid.read(fr, imag=read_i) assert np.allclose(grid.grid, read.grid)
def read_grid(self, name, spin=0, **kwargs): """ Reads a grid in the current Siesta.nc file Enables the reading and processing of the grids created by Siesta Parameters ---------- name : str name of the grid variable to read spin : int or array_like, optional the spin-index for retrieving one of the components. If a vector is passed it refers to the fraction per indexed component. I.e. ``[0.5, 0.5]`` will return sum of half the first two components. Default to the first component. """ spin = kwargs.get('index', spin) geom = self.read_geometry() # Shorthand g = self.groups['GRID'] # Create the grid nx = len(g.dimensions['nx']) ny = len(g.dimensions['ny']) nz = len(g.dimensions['nz']) # Shorthand variable name v = g.variables[name] # Create the grid, Siesta uses periodic, always grid = Grid([nz, ny, nx], bc=Grid.PERIODIC, geometry=geom, dtype=v.dtype) # Unit-conversion BohrC2AngC = Bohr2Ang**3 unit = { 'Rho': 1. / BohrC2AngC, 'RhoInit': 1. / BohrC2AngC, 'RhoTot': 1. / BohrC2AngC, 'RhoDelta': 1. / BohrC2AngC, 'RhoXC': 1. / BohrC2AngC, 'RhoBader': 1. / BohrC2AngC, 'Chlocal': 1. / BohrC2AngC, }.get(name, 1.) if len(v[:].shape) == 3: grid.grid = v[:, :, :] * unit elif isinstance(spin, Integral): grid.grid = v[spin, :, :, :] * unit else: if len(spin) > v.shape[0]: raise SileError( self.__class__.__name__ + '.read_grid requires spin to be an integer or ' 'an array of length equal to the number of spin components.' ) grid.grid[:, :, :] = v[0, :, :, :] * (spin[0] * unit) for i, scale in enumerate(spin[1:]): grid.grid[:, :, :] += v[1 + i, :, :, :] * (scale * unit) try: if v.unit == 'Ry': # Convert to ev grid *= Ry2eV except: # Allowed pass due to pythonic reading pass # Read the grid, we want the z-axis to be the fastest # looping direction, hence x,y,z == 0,1,2 grid.grid = np.copy(np.swapaxes(grid.grid, 0, 2), order='C') return grid
def read_grid(self, index=0, dtype=np.float64): """ Reads the potential (in eV) from the file and returns with a grid (plus geometry) Parameters ---------- index : int or array_like, optional the index of the potential to read. For a spin-polarized VASP calculation 0 and 1 are allowed, UP/DOWN. For non-collinear 0, 1, 2 or 3 is allowed which equals, TOTAL, x, y, z total potential with the Cartesian directions equal to the potential for the magnetization directions. For array-like they refer to the fractional contributions for each corresponding index. dtype : numpy.dtype, optional grid stored dtype Returns ------- Grid : potential with associated geometry """ geom = self.read_geometry() V = geom.sc.volume # Now we are past the cell and geometry # We can now read the size of LOCPOT self.readline() nx, ny, nz = list(map(int, self.readline().split())) n = nx * ny * nz is_index = True if isinstance(index, Integral): max_index = index + 1 else: is_index = False max_index = len(index) rl = self.readline vals = [] vapp = vals.append i = 0 while i < n * max_index: dat = [l for l in rl().split()] vapp(dat) i += len(dat) if i % n == 0 and i < n * max_index: # Each time a new spin-index is present, we need to read the coordinates j = 0 while j < geom.na: j += len(rl().split()) # one line of nx, ny, nz rl() # Cut size before proceeding (otherwise it *may* fail) vals = np.array(vals).astype(dtype).ravel() if is_index: val = vals[n * index:n * (index + 1)].reshape(nz, ny, nx) else: vals = vals[:n * max_index].reshape(-1, nz, ny, nx) val = vals[0] * index[0] for i, scale in enumerate(index[1:]): val += vals[i + 1] * scale del vals # Make it C-ordered with nx, ny, nz val = np.swapaxes(val, 0, 2) / V # Create the grid with data # Since we populate the grid data afterwards there # is no need to create a bigger grid than necessary. grid = Grid([1, 1, 1], dtype=dtype, geometry=geom) grid.grid = val return grid
def test_default_size(sisl_tmp): f = sisl_tmp('GRID.xsf', _dir) grid = Grid(0.2, sc=2.0) grid.grid = np.random.rand(*grid.shape) grid.write(f) assert grid.geometry is None
def read_grid(self, imag=None): """ Returns `Grid` object from the CUBE file Parameters ---------- imag : str or Sile or Grid the imaginary part of the grid. If the geometries does not match an error will be raised. """ if not imag is None: if not isinstance(imag, Grid): imag = Grid.read(imag) geom = self.read_geometry() if geom is None: self.fh.seek(0) sc = self.read_supercell() else: sc = geom.sc # Now seek behind to read grid sizes self.fh.seek(0) # Skip headers and origin self.readline() self.readline() na = int(self.readline().split()[0]) ngrid = [0] * 3 for i in [0, 1, 2]: tmp = self.readline().split() ngrid[i] = int(tmp[0]) # Read past the atoms for i in range(na): self.readline() if geom is None: grid = Grid(ngrid, dtype=np.float64, sc=sc) else: grid = Grid(ngrid, dtype=np.float64, geometry=geom) grid.grid.shape = (-1, ) # TODO check performance of this # We are currently doing this to enable reading # 1-column data and 6-column data. lines = [ item for sublist in self.fh.readlines() for item in sublist.split() ] grid.grid[:] = np.array(lines).astype(grid.dtype) grid.grid.shape = ngrid if imag is None: return grid # We are expecting an imaginary part if not grid.geometry.equal(imag.geometry): raise SislError( str(self) + ' and its imaginary part does not have the same ' 'geometry. Hence a combined complex Grid cannot be formed.') if grid != imag: raise SislError( str(self) + ' and its imaginary part does not have the same ' 'shape. Hence a combined complex Grid cannot be formed.') # Now we have a complex grid grid.grid = grid.grid + 1j * imag.grid return grid