diff --git a/CHANGELOG.md b/CHANGELOG.md index ef89b62c1f..307e6b7c10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ we hit release version 1.0.0. - `BrillouinZone.merge` allows simple merging of several objects, #537 ### Changed +- SuperCell class is officially deprecated in favor of Lattice, see #95 for details + The old class will still be accessible and usable for some time (at least a year) - Enabled EigenState.wavefunction(grid) to accept grid as the initialization of the grid argument, so one does not need to produce the Grid on before-hand - Geometry.rotate(only=) to (what=), this is to unify the interfaces across, #541 diff --git a/docs/api/basic.rst b/docs/api/basic.rst index 3f47a18c1c..399e348258 100644 --- a/docs/api/basic.rst +++ b/docs/api/basic.rst @@ -30,7 +30,7 @@ Simple objects Atoms Geometry GeometryCollection - SuperCell + Lattice Grid diff --git a/docs/tutorials/tutorial_01.rst b/docs/tutorials/tutorial_01.rst index a2f14fb0af..cd2fd2b73a 100644 --- a/docs/tutorials/tutorial_01.rst +++ b/docs/tutorials/tutorial_01.rst @@ -17,7 +17,7 @@ The *only* required information is the atomic coordinates:: } this will create a `Geometry` object with 1 Hydrogen atom with a single orbital -(default if not specified), and a supercell of 10 A in each Cartesian direction. +(default if not specified), and a lattice of 10 A in each Cartesian direction. When printing a `Geometry` object a list of information is printed in an XML-like fashion. ``na`` corresponds to the total number of atoms in the geometry, while ``no`` refers to the total number of orbitals. diff --git a/docs/tutorials/tutorial_04.rst b/docs/tutorials/tutorial_04.rst index 6fb0cd341d..8368da507f 100644 --- a/docs/tutorials/tutorial_04.rst +++ b/docs/tutorials/tutorial_04.rst @@ -15,7 +15,7 @@ used. First, recall that the number of supercells can be retrieved by:: }, nsc: [1, 1, 1], maxR: -1.0 } - >>> geometry.nsc # or geometry.sc.nsc + >>> geometry.nsc # or geometry.lattice.nsc array([1, 1, 1], dtype=int32) where ``nsc`` is the specific super-cell information. In the default @@ -26,7 +26,7 @@ depending on the size of the supercell. Specifying the number of super-cells may be done when creating the geometry, or after it has been created:: - >>> geometry = Geometry([[0, 0, 0]], sc=SuperCell(5, [3, 3, 3])) + >>> geometry = Geometry([[0, 0, 0]], lattice=Lattice(5, nsc=[3, 3, 3])) >>> geometry.nsc array([3, 3, 3], dtype=int32) >>> geometry.set_nsc([3, 1, 5]) @@ -46,7 +46,7 @@ Here we show a square 2D lattice with one atom in the unit-cell and a supercell which extends 2 cells along the Cartesian :math:`x` lattice vector (5 in total) and 1 cell along the Cartesian :math:`y` lattice vector (3 in total):: - >>> square = Geometry([[0.5,0.5,0]], sc=SuperCell([1,1,10], [5, 3, 1])) + >>> square = Geometry([[0.5,0.5,0]], lattice=Lattice([1,1,10], nsc=[5, 3, 1])) which results in this underlying geometry: diff --git a/docs/tutorials/tutorial_05.rst b/docs/tutorials/tutorial_05.rst index eac66bbad1..1e6295678a 100644 --- a/docs/tutorials/tutorial_05.rst +++ b/docs/tutorials/tutorial_05.rst @@ -5,7 +5,7 @@ Electronic structure setup -- part 1 ------------------------------------ A `Hamiltonian` is an extension of a `Geometry`. From the `Geometry` it -reads the number of orbitals, the supercell information. +reads the number of orbitals, the lattice information. Hamiltonians are matrices, and in sisl all Hamiltonians are treated as sparse matrices, i.e. matrices where there are an overweight of @@ -45,7 +45,7 @@ Let us try and continue from :ref:`tutorial-01` and create a square 2D lattice with one atom in the unit-cell and a supercell which couples only to nearest neighbour atoms. - >>> square = Geometry([[0.5,0.5,0]], sc=SuperCell([1, 1, 10], [3, 3, 1])) + >>> square = Geometry([[0.5,0.5,0]], lattice=Lattice([1, 1, 10], nsc=[3, 3, 1])) >>> H = Hamiltonian(square) Now we have a periodic structure with couplings allowed only to nearest neighbour diff --git a/docs/tutorials/tutorial_05_square.py b/docs/tutorials/tutorial_05_square.py index d0329e22c3..d191a19d43 100644 --- a/docs/tutorials/tutorial_05_square.py +++ b/docs/tutorials/tutorial_05_square.py @@ -4,7 +4,7 @@ from sisl import * # Generate square lattice with nearest neighbour couplings -square = Geometry([[0.5, 0.5, 0]], sc=SuperCell([1, 1, 10], [3, 3, 1])) +square = Geometry([[0.5, 0.5, 0]], lattice=Lattice([1, 1, 10], [3, 3, 1])) # Generate Hamiltonian H = Hamiltonian(square) diff --git a/docs/tutorials/tutorial_06.rst b/docs/tutorials/tutorial_06.rst index ca9f2038bd..454c0ae550 100644 --- a/docs/tutorials/tutorial_06.rst +++ b/docs/tutorials/tutorial_06.rst @@ -14,7 +14,7 @@ atomic specie to be a Hydrogen atom with a single orbital with a range of :math: >>> Hydrogen = Atom(1, R=1.) >>> square = Geometry([[0.5, 0.5, 0]], Hydrogen, - sc=SuperCell([1, 1, 10], [3, 3, 1])) + lattice=Lattice([1, 1, 10], nsc=[3, 3, 1])) >>> H = Hamiltonian(square) >>> print(H) {spin: 1, non-zero: 0 diff --git a/docs/tutorials/tutorial_06_square.py b/docs/tutorials/tutorial_06_square.py index aae47a5a88..8be7a4e172 100644 --- a/docs/tutorials/tutorial_06_square.py +++ b/docs/tutorials/tutorial_06_square.py @@ -6,7 +6,7 @@ # Generate square lattice with nearest neighbour couplings Hydrogen = Atom(1, R=1.) square = Geometry([[0.5, 0.5, 0]], Hydrogen, - sc=SuperCell([1, 1, 10], [3, 3, 1])) + lattice=Lattice([1, 1, 10], [3, 3, 1])) # Generate Hamiltonian H = Hamiltonian(square) diff --git a/docs/tutorials/tutorial_siesta_1.ipynb b/docs/tutorials/tutorial_siesta_1.ipynb index 44ee972095..3ab57422c0 100644 --- a/docs/tutorials/tutorial_siesta_1.ipynb +++ b/docs/tutorials/tutorial_siesta_1.ipynb @@ -27,7 +27,7 @@ "## Creating the geometry\n", "\n", "Our system of interest will be the $\\mathrm H_2\\mathrm O$ system. The first task will be to create the molecule geometry.\n", - "This is done using lists of atomic coordinates and atomic species. Additionally one needs to define the supercell (or if you prefer: unit-cell) where the molecule resides in. Siesta is a periodic DFT code and thus all directions are periodic. I.e. when simulating molecules it is vital to have a large vacuum gap between periodic images. In this case we use a supercell of side-lengths $10\\mathrm{Ang}$." + "This is done using lists of atomic coordinates and atomic species. Additionally one needs to define the lattice (or if you prefer: unit-cell) where the molecule resides in. Siesta is a periodic DFT code and thus all directions are periodic. I.e. when simulating molecules it is vital to have a large vacuum gap between periodic images. In this case we use a supercell of side-lengths $10\\mathrm{Ang}$." ] }, { @@ -38,16 +38,16 @@ "source": [ "h2o = Geometry([[0, 0, 0], [0.8, 0.6, 0], [-0.8, 0.6, 0.]], \n", " [Atom('O'), Atom('H'), Atom('H')], \n", - " sc=SuperCell(10, origin=[-5] * 3))" + " lattice=Lattice(10, origin=[-5] * 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The input are the 1) xyz coordinates, 2) the atomic species and 3) the supercell that is attached.\n", + "The input are the 1) xyz coordinates, 2) the atomic species and 3) the lattice that is attached.\n", "\n", - "By printing the object one gets basic information regarding the geometry, such as 1) number of atoms, 2) species of atoms, 3) number of orbitals, 4) orbitals associated with each atom and 5) number of supercells." + "By printing the object one gets basic information regarding the geometry, such as 1) number of atoms, 2) species of atoms, 3) number of orbitals, 4) orbitals associated with each atom and 5) number of supercells (should be 1 for molecules)." ] }, { diff --git a/examples/ex_03.py b/examples/ex_03.py index 5c8963b269..315be364c6 100644 --- a/examples/ex_03.py +++ b/examples/ex_03.py @@ -187,7 +187,7 @@ print('Reading output') gout = sisl.get_sile('zz.gout') # Correct what to read from the gulp output -gout.set_supercell_key("Cartesian lattice vectors") +gout.set_lattice_key("Cartesian lattice vectors") # Selectively decide whether you want to read the dynamical # matrix from the GULP output file or from the # FORCE_CONSTANTS_2ND file. diff --git a/pyproject.toml b/pyproject.toml index 75823d5ba3..96cd970378 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -190,7 +190,7 @@ ignore-patterns = [ extension-pkg-allow-list = [ "sisl._math_small", "sisl._indices", - "sisl._supercell", + "sisl._lattice", "sisl.io.siesta._siesta", "sisl.physics._bloch", "sisl.physics._matrix_k", diff --git a/setup.py b/setup.py index 1cd66bcd83..82b8f26f6f 100644 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def run(self): "sisl._sparse": { "depends": [_ospath("sisl/_indices.pxd")] }, - "sisl._supercell": {}, + "sisl._lattice": {}, "sisl.physics._bloch": {}, "sisl.physics._phase": {}, "sisl.physics._matrix_utils": {}, diff --git a/sisl/__init__.py b/sisl/__init__.py index 99a2f79069..3598183622 100644 --- a/sisl/__init__.py +++ b/sisl/__init__.py @@ -23,7 +23,7 @@ AtomicOrbital Atoms Geometry - SuperCell + Lattice Grid Below are a group of advanced classes rarely needed. @@ -107,7 +107,7 @@ from .quaternion import * from .shape import * -from .supercell import * +from .lattice import * from .atom import * from .orbital import * diff --git a/sisl/_supercell.pyx b/sisl/_lattice.pyx similarity index 100% rename from sisl/_supercell.pyx rename to sisl/_lattice.pyx diff --git a/sisl/_typing.py b/sisl/_typing.py index 708e9a8f66..45d70a6de5 100644 --- a/sisl/_typing.py +++ b/sisl/_typing.py @@ -9,14 +9,14 @@ #from typing import TYPE_CHECKING, final from sisl import ( - Geometry, SuperCell, + Geometry, Lattice, Atom, Atoms ) -# A SuperCell or a Geometry +# A Lattice or a Geometry CellOrGeometry = Union[ - SuperCell, + Lattice, Geometry, ] diff --git a/sisl/conftest.py b/sisl/conftest.py index 0212970f52..251339600b 100644 --- a/sisl/conftest.py +++ b/sisl/conftest.py @@ -7,7 +7,7 @@ from pathlib import Path import pytest -from sisl import Atom, Geometry, SuperCell, Hamiltonian, _environ +from sisl import Atom, Geometry, Lattice, Hamiltonian, _environ # Here we create the necessary methods and fixtures to enabled/disable @@ -137,26 +137,26 @@ class System: alat = 1.42 sq3h = 3.**.5 * 0.5 C = Atom(Z=6, R=1.42) - sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * alat, - nsc=[3, 3, 1]) + lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * alat, + nsc=[3, 3, 1]) d.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * alat, - atoms=C, sc=sc) + atoms=C, lattice=lattice) d.R = np.array([0.1, 1.5]) d.t = np.array([0., 2.7]) d.tS = np.array([(0., 1.0), (2.7, 0.)]) d.C = Atom(Z=6, R=max(d.R)) - d.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * alat, - nsc=[3, 3, 1]) + d.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * alat, + nsc=[3, 3, 1]) d.gtb = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * alat, - atoms=C, sc=sc) + atoms=C, lattice=lattice) d.ham = Hamiltonian(d.gtb) d.ham.construct([(0.1, 1.5), (0.1, 2.7)]) @@ -203,7 +203,7 @@ def pytest_configure(config): for mark in ['io', 'generic', 'bloch', 'hamiltonian', 'geometry', 'geom', 'shape', 'state', 'electron', 'phonon', 'utils', 'unit', 'distribution', 'spin', 'self_energy', 'help', 'messages', 'namedindex', 'sparse', - 'supercell', 'sc', 'quaternion', 'sparse_geometry', 'sparse_orbital', + 'lattice', 'supercell', 'sc', 'quaternion', 'sparse_geometry', 'sparse_orbital', 'ranges', 'physics', "physics_feature", 'orbital', 'oplist', 'grid', 'atoms', 'atom', 'sgrid', 'sdata', 'sgeom', 'version', diff --git a/sisl/geom/basic.py b/sisl/geom/basic.py index 33c170a6b3..d7776c8b2b 100644 --- a/sisl/geom/basic.py +++ b/sisl/geom/basic.py @@ -4,7 +4,7 @@ import numpy as np from sisl._internal import set_module -from sisl import Geometry, SuperCell +from sisl import Geometry, Lattice from ._common import geometry_define_nsc, geometry2uc __all__ = ['sc', 'bcc', 'fcc', 'hcp', 'rocksalt'] @@ -32,10 +32,10 @@ def sc(alat, atom): atom : Atom the atom in the SC lattice """ - sc = SuperCell(np.array([[1, 0, 0], - [0, 1, 0], - [0, 0, 1]], np.float64) * alat) - g = Geometry([0, 0, 0], atom, sc=sc) + lattice = Lattice(np.array([[1, 0, 0], + [0, 1, 0], + [0, 0, 1]], np.float64) * alat) + g = Geometry([0, 0, 0], atom, lattice=lattice) geometry_define_nsc(g) return g @@ -54,16 +54,16 @@ def bcc(alat, atoms, orthogonal=False): whether the lattice is orthogonal (2 atoms) """ if orthogonal: - sc = SuperCell(np.array([[1, 0, 0], + lattice = Lattice(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], np.float64) * alat) ah = alat / 2 - g = Geometry([[0, 0, 0], [ah, ah, ah]], atoms, sc=sc) + g = Geometry([[0, 0, 0], [ah, ah, ah]], atoms, lattice=lattice) else: - sc = SuperCell(np.array([[-1, 1, 1], + lattice = Lattice(np.array([[-1, 1, 1], [1, -1, 1], [1, 1, -1]], np.float64) * alat / 2) - g = Geometry([0, 0, 0], atoms, sc=sc) + g = Geometry([0, 0, 0], atoms, lattice=lattice) geometry_define_nsc(g) return g @@ -82,17 +82,17 @@ def fcc(alat, atoms, orthogonal=False): whether the lattice is orthogonal (4 atoms) """ if orthogonal: - sc = SuperCell(np.array([[1, 0, 0], + lattice = Lattice(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], np.float64) * alat) ah = alat / 2 g = Geometry([[0, 0, 0], [ah, ah, 0], - [ah, 0, ah], [0, ah, ah]], atoms, sc=sc) + [ah, 0, ah], [0, ah, ah]], atoms, lattice=lattice) else: - sc = SuperCell(np.array([[0, 1, 1], + lattice = Lattice(np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]], np.float64) * alat / 2) - g = Geometry([0, 0, 0], atoms, sc=sc) + g = Geometry([0, 0, 0], atoms, lattice=lattice) geometry_define_nsc(g) return g @@ -116,26 +116,26 @@ def hcp(a, atoms, coa=1.63333, orthogonal=False): c = a * coa a3sq = a / 3 ** .5 if orthogonal: - sc = SuperCell([[a + a * _c60 * 2, 0, 0], + lattice = Lattice([[a + a * _c60 * 2, 0, 0], [0, a * _c30 * 2, 0], [0, 0, c / 2]]) gt = Geometry([[0, 0, 0], [a, 0, 0], [a * _s30, a * _c30, 0], - [a * (1 + _s30), a * _c30, 0]], atoms, sc=sc) + [a * (1 + _s30), a * _c30, 0]], atoms, lattice=lattice) # Create the rotated one on top gr = gt.copy() # mirror structure - gr.xyz[0, 1] += sc.cell[1, 1] - gr.xyz[1, 1] += sc.cell[1, 1] + gr.xyz[0, 1] += lattice.cell[1, 1] + gr.xyz[1, 1] += lattice.cell[1, 1] gr = gr.translate(-np.amin(gr.xyz, axis=0)) # Now displace to get the correct offset gr = gr.translate([0, a * _s30 / 2, 0]) g = gt.append(gr, 2) else: - sc = SuperCell([a, a, c, 90, 90, 60]) + lattice = Lattice([a, a, c, 90, 90, 60]) g = Geometry([[0, 0, 0], [a3sq * _c30, a3sq * _s30, c / 2]], - atoms, sc=sc) + atoms, lattice=lattice) geometry_define_nsc(g) return g diff --git a/sisl/geom/category/_coord.py b/sisl/geom/category/_coord.py index cc3c3b5a5c..df76c643fd 100644 --- a/sisl/geom/category/_coord.py +++ b/sisl/geom/category/_coord.py @@ -9,10 +9,11 @@ from sisl._category import CategoryMeta from sisl._internal import set_module +from sisl.messages import deprecate_argument from sisl.utils.misc import direction from sisl.shape import * -from sisl.supercell import SuperCell, SuperCellChild -from sisl._supercell import cell_invert +from sisl.lattice import Lattice, LatticeChild +from sisl._lattice import cell_invert import sisl._array as _a from .base import AtomCategory, NullCategory @@ -28,18 +29,18 @@ class AtomFracSite(AtomCategory): Parameters ---------- - sc : SuperCell, SuperCellChild or argument to SuperCell - an object that defines the lattice vectors (will be passed through to `SuperCell` - if not an object instance of `SuperCell` or `SuperCellChild` + lattice : Lattice, LatticeChild or argument to Lattice + an object that defines the lattice vectors (will be passed through to `Lattice` + if not an object instance of `Lattice` or `LatticeChild` atol : float, optional the absolute tolerance (in Ang) to check whether the site is an integer site. offset : array_like, optional an offset made to the geometry coordinates before calculating the fractional - coordinates according to `sc` + coordinates according to `lattice` foffset : array_like, optional fractional offset of the fractional coordinates, this allows to select sub-regions - in the `sc` lattice vectors. + in the `lattice` lattice vectors. Examples -------- @@ -55,16 +56,17 @@ class AtomFracSite(AtomCategory): """ __slots__ = (f"_{a}" for a in ("cell", "icell", "length", "atol", "offset", "foffset")) - def __init__(self, sc, atol=1.e-5, offset=(0., 0., 0.), foffset=(0., 0., 0.)): - if isinstance(sc, SuperCellChild): - sc = sc.sc - elif not isinstance(sc, SuperCell): - sc = SuperCell(sc) + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def __init__(self, lattice, atol=1.e-5, offset=(0., 0., 0.), foffset=(0., 0., 0.)): + if isinstance(lattice, LatticeChild): + lattice = lattice.lattice + elif not isinstance(lattice, Lattice): + lattice = Lattice(lattice) # Unit-cell to fractionalize - self._cell = sc.cell.copy() + self._cell = lattice.cell.copy() # lengths of lattice vectors - self._length = sc.length.copy().reshape(1, 3) + self._length = lattice.length.copy().reshape(1, 3) # inverse cell (for fractional coordinate calculations) self._icell = cell_invert(self._cell) # absolute tolerance [Ang] diff --git a/sisl/geom/flat.py b/sisl/geom/flat.py index 97529bf525..636959cb73 100644 --- a/sisl/geom/flat.py +++ b/sisl/geom/flat.py @@ -4,7 +4,7 @@ import numpy as np from sisl._internal import set_module -from sisl import Atom, Geometry, SuperCell +from sisl import Atom, Geometry, Lattice from ._common import geometry_define_nsc __all__ = ['honeycomb', 'graphene'] @@ -32,21 +32,21 @@ def honeycomb(bond, atoms, orthogonal=False): """ sq3h = 3.**.5 * 0.5 if orthogonal: - sc = SuperCell(np.array([[3., 0., 0.], + lattice = Lattice(np.array([[3., 0., 0.], [0., 2 * sq3h, 0.], [0., 0., 10.]], np.float64) * bond) g = Geometry(np.array([[0., 0., 0.], [0.5, sq3h, 0.], [1.5, sq3h, 0.], [2., 0., 0.]], np.float64) * bond, - atoms, sc=sc) + atoms, lattice=lattice) else: - sc = SuperCell(np.array([[1.5, -sq3h, 0.], + lattice = Lattice(np.array([[1.5, -sq3h, 0.], [1.5, sq3h, 0.], [0., 0., 10.]], np.float64) * bond) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms, sc=sc) + atoms, lattice=lattice) geometry_define_nsc(g, [True, True, False]) return g diff --git a/sisl/geom/nanotube.py b/sisl/geom/nanotube.py index 7e312ddf3e..a16603c5ba 100644 --- a/sisl/geom/nanotube.py +++ b/sisl/geom/nanotube.py @@ -4,7 +4,7 @@ import numpy as np from sisl._internal import set_module -from sisl import Atom, Geometry, SuperCell +from sisl import Atom, Geometry, Lattice from ._common import geometry_define_nsc __all__ = ['nanotube'] @@ -135,9 +135,9 @@ def gcd(a, b): idx = np.argsort(xyz[:, 2]) xyz = xyz[idx, :] - sc = SuperCell([rs * 4, rs * 4, t]) + lattice = Lattice([rs * 4, rs * 4, t]) - geom = Geometry(xyz, atoms, sc=sc) + geom = Geometry(xyz, atoms, lattice=lattice) geom = geom.translate(-np.amin(geom.xyz, axis=0)) geometry_define_nsc(geom, [False, False, True]) diff --git a/sisl/geom/special.py b/sisl/geom/special.py index 8377874b6f..caa8b19747 100644 --- a/sisl/geom/special.py +++ b/sisl/geom/special.py @@ -4,7 +4,7 @@ import numpy as np from sisl._internal import set_module -from sisl import Atom, Geometry, SuperCell +from sisl import Atom, Geometry, Lattice from ._common import geometry_define_nsc __all__ = ['diamond'] @@ -24,11 +24,11 @@ def diamond(alat=3.57, atoms=None): dist = alat * 3. ** .5 / 4 if atoms is None: atoms = Atom(Z=6, R=dist * 1.01) - sc = SuperCell(np.array([[0, 1, 1], - [1, 0, 1], - [1, 1, 0]], np.float64) * alat / 2) + lattice = Lattice(np.array([[0, 1, 1], + [1, 0, 1], + [1, 1, 0]], np.float64) * alat / 2) dia = Geometry(np.array([[0, 0, 0], [1, 1, 1]], np.float64) * alat / 4, - atoms, sc=sc) + atoms, lattice=lattice) geometry_define_nsc(dia) return dia diff --git a/sisl/geom/surfaces.py b/sisl/geom/surfaces.py index b392307684..ae998bec36 100644 --- a/sisl/geom/surfaces.py +++ b/sisl/geom/surfaces.py @@ -7,7 +7,7 @@ import numpy as np from sisl._internal import set_module -from sisl import Atom, Geometry, SuperCell +from sisl import Atom, Geometry, Lattice from ._common import geometry_define_nsc, geometry2uc __all__ = ['fcc_slab', 'bcc_slab', 'rocksalt_slab'] @@ -232,7 +232,7 @@ def iter_func(key, layer): end=end.pop(0), vacuum=None, **kwargs) # add vacuum - vacuum = SuperCell([0, 0, vacuums.pop(0)]) + vacuum = Lattice([0, 0, vacuums.pop(0)]) out = out.add(vacuum, offset=(0, 0, vacuum.cell[2, 2])) ivacuum += 1 islab += 1 @@ -250,7 +250,7 @@ def iter_func(key, layer): if layer is None: dx = out.cell[2, 2] - out.xyz[:, 2].max() # this ensures the vacuum is exactly vacuums[iv] - vacuum = SuperCell([0, 0, vacuums.pop(0) - dx]) + vacuum = Lattice([0, 0, vacuums.pop(0) - dx]) ivacuum += 1 out = out.add(vacuum) else: @@ -396,57 +396,57 @@ def fcc_slab(alat, atoms, miller, layers=None, vacuum=20., *, orthogonal=False, info = _calc_info(start, end, layers, 2) - sc = SuperCell(np.array([0.5 ** 0.5, 0.5 ** 0.5, 0.5]) * alat) - g = Geometry([0, 0, 0], atoms=atoms, sc=sc) + lattice = Lattice(np.array([0.5 ** 0.5, 0.5 ** 0.5, 0.5]) * alat) + g = Geometry([0, 0, 0], atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide AB layers relative to each other B = (info.offset + 1) % 2 - g.xyz[B::2] += (sc.cell[0] + sc.cell[1]) / 2 + g.xyz[B::2] += (lattice.cell[0] + lattice.cell[1]) / 2 elif miller == (1, 1, 0): info = _calc_info(start, end, layers, 2) - sc = SuperCell(np.array([1., 0.5, 0.125]) ** 0.5 * alat) - g = Geometry([0, 0, 0], atoms=atoms, sc=sc) + lattice = Lattice(np.array([1., 0.5, 0.125]) ** 0.5 * alat) + g = Geometry([0, 0, 0], atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide AB layers relative to each other B = (info.offset + 1) % 2 - g.xyz[B::2] += (sc.cell[0] + sc.cell[1]) / 2 + g.xyz[B::2] += (lattice.cell[0] + lattice.cell[1]) / 2 elif miller == (1, 1, 1): info = _calc_info(start, end, layers, 3) if orthogonal: - sc = SuperCell(np.array([0.5, 4 * 0.375, 1 / 3]) ** 0.5 * alat) + lattice = Lattice(np.array([0.5, 4 * 0.375, 1 / 3]) ** 0.5 * alat) g = Geometry(np.array([[0, 0, 0], [0.125, 0.375, 0]]) ** 0.5 * alat, - atoms=atoms, sc=sc) + atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide ABC layers relative to each other B = 2 * (info.offset + 1) % 6 C = 2 * (info.offset + 2) % 6 - vec = (3 * sc.cell[0] + sc.cell[1]) / 6 + vec = (3 * lattice.cell[0] + lattice.cell[1]) / 6 g.xyz[B::6] += vec g.xyz[B+1::6] += vec g.xyz[C::6] += 2 * vec g.xyz[C+1::6] += 2 * vec else: - sc = SuperCell(np.array([[0.5, 0, 0], + lattice = Lattice(np.array([[0.5, 0, 0], [0.125, 0.375, 0], [0, 0, 1 / 3]]) ** 0.5 * alat) - g = Geometry([0, 0, 0], atoms=atoms, sc=sc) + g = Geometry([0, 0, 0], atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide ABC layers relative to each other B = (info.offset + 1) % 3 C = (info.offset + 2) % 3 - vec = (sc.cell[0] + sc.cell[1]) / 3 + vec = (lattice.cell[0] + lattice.cell[1]) / 3 g.xyz[B::3] += vec g.xyz[C::3] += 2 * vec @@ -526,72 +526,72 @@ def bcc_slab(alat, atoms, miller, layers=None, vacuum=20., *, orthogonal=False, info = _calc_info(start, end, layers, 2) - sc = SuperCell(np.array([1, 1, 0.5]) * alat) - g = Geometry([0, 0, 0], atoms=atoms, sc=sc) + lattice = Lattice(np.array([1, 1, 0.5]) * alat) + g = Geometry([0, 0, 0], atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide AB layers relative to each other B = (info.offset + 1) % 2 - g.xyz[B::2] += (sc.cell[0] + sc.cell[1]) / 2 + g.xyz[B::2] += (lattice.cell[0] + lattice.cell[1]) / 2 elif miller == (1, 1, 0): info = _calc_info(start, end, layers, 2) if orthogonal: - sc = SuperCell(np.array([1, 2, 0.5]) ** 0.5 * alat) + lattice = Lattice(np.array([1, 2, 0.5]) ** 0.5 * alat) g = Geometry(np.array([[0, 0, 0], [0.5, 0.5 ** 0.5, 0]]) * alat, - atoms=atoms, sc=sc) + atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide ABC layers relative to each other B = 2 * (info.offset + 1) % 4 - vec = sc.cell[1] / 2 + vec = lattice.cell[1] / 2 g.xyz[B::4] += vec g.xyz[B+1::4] += vec else: - sc = SuperCell(np.array([[1, 0, 0], + lattice = Lattice(np.array([[1, 0, 0], [0.5, 0.5 ** 0.5, 0], [0, 0, 0.5 ** 0.5]]) * alat) - g = Geometry([0, 0, 0], atoms=atoms, sc=sc) + g = Geometry([0, 0, 0], atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide AB layers relative to each other B = (info.offset + 1) % 2 - g.xyz[B::2] += sc.cell[0] / 2 + g.xyz[B::2] += lattice.cell[0] / 2 elif miller == (1, 1, 1): info = _calc_info(start, end, layers, 3) if orthogonal: - sc = SuperCell(np.array([2, 4 * 1.5, 1 / 12]) ** 0.5 * alat) + lattice = Lattice(np.array([2, 4 * 1.5, 1 / 12]) ** 0.5 * alat) g = Geometry(np.array([[0, 0, 0], [0.5, 1.5, 0]]) ** 0.5 * alat, - atoms=atoms, sc=sc) + atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide ABC layers relative to each other B = 2 * (info.offset + 1) % 6 C = 2 * (info.offset + 2) % 6 - vec = (sc.cell[0] + sc.cell[1]) / 3 + vec = (lattice.cell[0] + lattice.cell[1]) / 3 for i in range(2): g.xyz[B+i::6] += vec g.xyz[C+i::6] += 2 * vec else: - sc = SuperCell(np.array([[2, 0, 0], + lattice = Lattice(np.array([[2, 0, 0], [0.5, 1.5, 0], [0, 0, 1 / 12]]) ** 0.5 * alat) - g = Geometry([0, 0, 0], atoms=atoms, sc=sc) + g = Geometry([0, 0, 0], atoms=atoms, lattice=lattice) g = g.tile(info.nlayers, 2) # slide ABC layers relative to each other B = (info.offset + 1) % 3 C = (info.offset + 2) % 3 - vec = (sc.cell[0] + sc.cell[1]) / 3 + vec = (lattice.cell[0] + lattice.cell[1]) / 3 g.xyz[B::3] += vec g.xyz[C::3] += 2 * vec diff --git a/sisl/geom/tests/test_geom.py b/sisl/geom/tests/test_geom.py index 0b05cf5b43..05805c196e 100644 --- a/sisl/geom/tests/test_geom.py +++ b/sisl/geom/tests/test_geom.py @@ -3,7 +3,7 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. import pytest -from sisl import Atom, SuperCell +from sisl import Atom, Lattice from sisl.geom import * from sisl._math_small import cross3, dot3 @@ -14,7 +14,7 @@ pytestmark = [pytest.mark.geom] -class CellDirect(SuperCell): +class CellDirect(Lattice): @property def volume(self): @@ -22,7 +22,7 @@ def volume(self): def is_right_handed(geometry): - sc = CellDirect(geometry.sc.cell) + sc = CellDirect(geometry.lattice.cell) return sc.volume > 0. diff --git a/sisl/geometry.py b/sisl/geometry.py index e0948c1b5f..f48d88701a 100644 --- a/sisl/geometry.py +++ b/sisl/geometry.py @@ -22,6 +22,7 @@ from sisl._typing_ext.numpy import ArrayLike, NDArray if TYPE_CHECKING: from sisl.typing import AtomsArgument, OrbitalsArgument +from .lattice import Lattice, LatticeChild from .orbital import Orbital from ._internal import set_module, singledispatchmethod from . import _plot as plt @@ -36,7 +37,6 @@ from .utils import lstranges, strmap from .utils.mathematics import fnorm from .quaternion import Quaternion -from .supercell import SuperCell, SuperCellChild from .atom import Atom, Atoms from .shape import Shape, Sphere, Cube from ._namedindex import NamedIndex @@ -64,7 +64,7 @@ def is_class(cls, name, case=True) -> bool: @set_module("sisl") -class Geometry(SuperCellChild): +class Geometry(LatticeChild): """ Holds atomic information, coordinates, species, lattice vectors The `Geometry` class holds information regarding atomic coordinates, @@ -79,7 +79,7 @@ class Geometry(SuperCellChild): .. code:: python >>> square = Geometry([[0.5, 0.5, 0.5]], Atom(1), - ... sc=SuperCell([1, 1, 10], nsc=[3, 3, 1])) + ... lattice=Lattice([1, 1, 10], nsc=[3, 3, 1])) >>> print(square) Geometry{na: 1, no: 1, Atoms{species: 1, @@ -88,7 +88,7 @@ class Geometry(SuperCellChild): }: 1, }, maxR: -1.00000, - SuperCell{volume: 1.0000e+01, nsc: [3 3 1]} + Lattice{volume: 1.0000e+01, nsc: [3 3 1]} } @@ -99,7 +99,7 @@ class Geometry(SuperCellChild): ``xyz[i, :]`` is the atomic coordinate of the i'th atom. atoms : array_like or Atoms atomic species retrieved from the `PeriodicTable` - sc : SuperCell + lattice : Lattice the unit-cell describing the atoms in a periodic super-cell @@ -110,7 +110,7 @@ class Geometry(SuperCellChild): >>> xyz = [[0, 0, 0], ... [1, 1, 1]] - >>> sc = SuperCell([2,2,2]) + >>> sc = Lattice([2,2,2]) >>> g = Geometry(xyz, Atom('H'), sc) The following estimates the lattice vectors from the @@ -136,7 +136,10 @@ class Geometry(SuperCellChild): Atom : contained atoms are each an object of this """ - def __init__(self, xyz: ArrayLike, atoms=None, sc=None, names=None): + @deprecate_argument("sc", "lattice", + "argument sc has been deprecated in favor of lattice, please update your code.", + "0.15.0") + def __init__(self, xyz: ArrayLike, atoms=None, lattice=None, names=None): # Create the geometry coordinate, be aware that we do not copy! self.xyz = _a.asarrayd(xyz).reshape(-1, 3) @@ -154,7 +157,7 @@ def __init__(self, xyz: ArrayLike, atoms=None, sc=None, names=None): else: self._names = NamedIndex(names) - self.__init_sc(sc) + self.__init_lattice(lattice) # Define a dispatcher for converting and requesting # new Geometries @@ -181,7 +184,7 @@ def __init__(self, xyz: ArrayLike, atoms=None, sc=None, names=None): ) ) - def __init_sc(self, sc): + def __init_lattice(self, lattice): """ Initializes the supercell by *calculating* the size if not supplied If the supercell has not been passed we estimate the unit cell size @@ -190,9 +193,9 @@ def __init_sc(self, sc): """ # We still need the *default* super cell for # estimating the supercell - self.set_supercell(sc) + self.set_lattice(lattice) - if sc is not None: + if lattice is not None: return # First create an initial guess for the supercell @@ -205,7 +208,7 @@ def __init_sc(self, sc): # We create a molecule box with +10 A in each direction m, M = np.amin(self.xyz, axis=0), np.amax(self.xyz, axis=0) + 10. - self.set_supercell(M-m) + self.set_lattice(M-m) return sc_cart = _a.zerosd([3]) @@ -235,7 +238,7 @@ def __init_sc(self, sc): cart[i] = 0. # Re-set the supercell to the newly found one - self.set_supercell(sc_cart) + self.set_lattice(sc_cart) @property def atoms(self) -> Atoms: @@ -448,7 +451,7 @@ def as_primary(self, na_primary: int, axes=(0, 1, 2), ret_super: bool=False): ------- Geometry the primary unit cell - SuperCell + Lattice the tiled supercell numbers used to find the primary unit cell (only if `ret_super` is true) Raises @@ -517,13 +520,13 @@ def as_primary(self, na_primary: int, axes=(0, 1, 2), ret_super: bool=False): raise SislError(f'{self.__class__.__name__}.as_primary could not determine the optimal supercell.') # Cut down the supercell (TODO this does not correct the number of supercell connections!) - sc = self.sc.copy() + lattice = self.lattice.copy() for i in range(3): - sc = sc.untile(supercell[i], i) + lattice = lattice.untile(supercell[i], i) # Now we need to find the atoms that are in the primary cell # We do this by finding all coordinates within the primary unit-cell - fxyz = dot(self.xyz, sc.icell.T) + fxyz = dot(self.xyz, lattice.icell.T) # Move to 0 and shift in 0.05 Ang in each direction fxyz -= fxyz.min(0) @@ -539,7 +542,7 @@ def as_primary(self, na_primary: int, axes=(0, 1, 2), ret_super: bool=False): ind = np.logical_and.reduce(fxyz < 1., axis=1).nonzero()[0] geom = self.sub(ind) - geom.set_supercell(sc) + geom.set_lattice(lattice) if ret_super: return geom, supercell return geom @@ -697,7 +700,7 @@ def __str__(self) -> str: s += str(self.atoms).replace('\n', '\n ') if len(self.names) > 0: s += ',\n ' + str(self.names).replace('\n', '\n ') - return (s + ',\n maxR: {0:.5f},\n {1}\n}}'.format(self.maxR(), str(self.sc).replace('\n', '\n '))).strip() + return (s + ',\n maxR: {0:.5f},\n {1}\n}}'.format(self.maxR(), str(self.lattice).replace('\n', '\n '))).strip() def __repr__(self) -> str: """ A simple, short string representation. """ @@ -1087,7 +1090,7 @@ def iter_block(self, iR=20, R=None, atoms: Optional[AtomsArgument]=None, method: def copy(self) -> Geometry: """ A copy of the object. """ - g = self.__class__(np.copy(self.xyz), atoms=self.atoms.copy(), sc=self.sc.copy()) + g = self.__class__(np.copy(self.xyz), atoms=self.atoms.copy(), lattice=self.lattice.copy()) g._names = self.names.copy() return g @@ -1435,7 +1438,7 @@ def _lattice(lattice, atoms, **kwargs): lattice = (lattice,) fxyz = self.fxyz for ax in lattice: - atoms = _sort(fxyz[:, ax] * self.sc.length[ax], atoms, **kwargs) + atoms = _sort(fxyz[:, ax] * self.lattice.length[ax], atoms, **kwargs) return atoms funcs["lattice"] = _lattice @@ -1726,11 +1729,11 @@ def sub(self, atoms) -> Geometry: See Also -------- - SuperCell.fit : update the supercell according to a reference supercell + Lattice.fit : update the supercell according to a reference supercell remove : the negative of this routine, i.e. remove a subset of atoms """ atoms = self.sc2uc(atoms) - return self.__class__(self.xyz[atoms, :], atoms=self.atoms.sub(atoms), sc=self.sc.copy()) + return self.__class__(self.xyz[atoms, :], atoms=self.atoms.sub(atoms), lattice=self.lattice.copy()) def sub_orbital(self, atoms, orbitals) -> Geometry: r""" Retain only a subset of the orbitals on `atoms` according to `orbitals` @@ -1978,12 +1981,12 @@ def untile(self, reps, axis, segment=0, rtol=1e-4, atol=1e-4) -> Geometry: # Truncate to the correct segments lseg = segment % reps # Cut down cell - sc = self.sc.untile(reps, axis) + lattice = self.lattice.untile(reps, axis) # List of atoms n = self.na // reps off = n * lseg new = self.sub(_a.arangei(off, off + n)) - new.set_supercell(sc) + new.set_lattice(lattice) if not np.allclose(new.tile(reps, axis).xyz, self.xyz, rtol=rtol, atol=atol): warn("The cut structure cannot be re-created by tiling\n" "The tolerance between the coordinates can be altered using rtol, atol") @@ -2006,7 +2009,7 @@ def tile(self, reps, axis) -> Geometry: Examples -------- - >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], sc=1.) + >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], lattice=1.) >>> g = geom.tile(2,axis=0) >>> print(g.xyz) # doctest: +NORMALIZE_WHITESPACE [[0. 0. 0. ] @@ -2032,7 +2035,7 @@ def tile(self, reps, axis) -> Geometry: if reps < 1: raise ValueError(f'{self.__class__.__name__}.tile requires a repetition above 0') - sc = self.sc.tile(reps, axis) + lattice = self.lattice.tile(reps, axis) # Our first repetition *must* be with # the former coordinate @@ -2047,7 +2050,7 @@ def tile(self, reps, axis) -> Geometry: # Create the geometry and return it (note the smaller atoms array # will also expand via tiling) - return self.__class__(xyz, atoms=self.atoms.tile(reps), sc=sc) + return self.__class__(xyz, atoms=self.atoms.tile(reps), lattice=lattice) def repeat(self, reps, axis) -> Geometry: """ Create a repeated geometry @@ -2078,7 +2081,7 @@ def repeat(self, reps, axis) -> Geometry: Examples -------- - >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], sc=1) + >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], lattice=1) >>> g = geom.repeat(2,axis=0) >>> print(g.xyz) # doctest: +NORMALIZE_WHITESPACE [[0. 0. 0. ] @@ -2103,7 +2106,7 @@ def repeat(self, reps, axis) -> Geometry: if reps < 1: raise ValueError(f'{self.__class__.__name__}.repeat requires a repetition above 0') - sc = self.sc.repeat(reps, axis) + lattice = self.lattice.repeat(reps, axis) # Our first repetition *must* be with # the former coordinate @@ -2118,7 +2121,7 @@ def repeat(self, reps, axis) -> Geometry: xyz.shape = (-1, 3) # Create the geometry and return it - return self.__class__(xyz, atoms=self.atoms.repeat(reps), sc=sc) + return self.__class__(xyz, atoms=self.atoms.repeat(reps), lattice=lattice) def __mul__(self, m, method='tile') -> Geometry: """ Implement easy tile/repeat function @@ -2135,7 +2138,7 @@ def __mul__(self, m, method='tile') -> Geometry: Examples -------- - >>> geometry = Geometry([0.] * 3, sc=[1.5, 3, 4]) + >>> geometry = Geometry([0.] * 3, lattice=[1.5, 3, 4]) >>> geometry * 2 == geometry.tile(2, 0).tile(2, 1).tile(2, 2) True >>> geometry * [2, 1, 2] == geometry.tile(2, 0).tile(2, 2) @@ -2307,7 +2310,7 @@ def rotate(self, angle, v, origin=None, See Also -------- Quaternion : class to rotate - SuperCell.rotate : rotation passed to the contained supercell + Lattice.rotate : rotation passed to the contained supercell """ if origin is None: origin = [0., 0., 0.] @@ -2336,7 +2339,7 @@ def rotate(self, angle, v, origin=None, vn /= fnorm(vn) # Rotate by direct call - sc = self.sc.rotate(angle, vn, rad=rad, what=what) + lattice = self.lattice.rotate(angle, vn, rad=rad, what=what) # Copy xyz = np.copy(self.xyz) @@ -2356,7 +2359,7 @@ def rotate(self, angle, v, origin=None, for i in idx: xyz[atoms, i] = rotated[:, i] - return self.__class__(xyz, atoms=self.atoms.copy(), sc=sc) + return self.__class__(xyz, atoms=self.atoms.copy(), lattice=lattice) def rotate_miller(self, m, v) -> Geometry: """ Align Miller direction along ``v`` @@ -2404,7 +2407,7 @@ def translate(self, v, atoms: Optional[AtomsArgument]=None, cell=False) -> Geome else: g.xyz[self._sanitize_atoms(atoms).ravel(), :] += np.asarray(v, g.xyz.dtype) if cell: - g.set_supercell(g.sc.translate(v)) + g.set_lattice(g.lattice.translate(v)) return g move = translate @@ -2458,13 +2461,13 @@ def swap(self, atoms_a, atoms_b) -> Geometry: xyz = np.copy(self.xyz) xyz[atoms_a, :] = self.xyz[atoms_b, :] xyz[atoms_b, :] = self.xyz[atoms_a, :] - return self.__class__(xyz, atoms=self.atoms.swap(atoms_a, atoms_b), sc=self.sc.copy()) + return self.__class__(xyz, atoms=self.atoms.swap(atoms_a, atoms_b), lattice=self.lattice.copy()) def swapaxes(self, axes_a: Union[int, str], axes_b: Union[int, str], what: str="abc") -> Geometry: """ Swap the axes components by either lattice vectors (only cell), or Cartesian coordinates - See `SuperCell.swapaxes` for details. + See `Lattice.swapaxes` for details. Parameters ---------- @@ -2485,7 +2488,7 @@ def swapaxes(self, axes_a: Union[int, str], See Also -------- - SuperCell.swapaxes + Lattice.swapaxes Examples -------- @@ -2508,8 +2511,8 @@ def swapaxes(self, axes_a: Union[int, str], """ # swap supercell # We do not need to check argument types etc, - # SuperCell.swapaxes will do this for us - sc = self.sc.swapaxes(axes_a, axes_b, what) + # Lattice.swapaxes will do this for us + lattice = self.lattice.swapaxes(axes_a, axes_b, what) if isinstance(axes_a, int) and isinstance(axes_b, int): if "xyz" in what: @@ -2527,7 +2530,7 @@ def swapaxes(self, axes_a: Union[int, str], if aidx < 3: idx[aidx], idx[bidx] = idx[bidx], idx[aidx] - return self.__class__(self.xyz[:, idx].copy(), atoms=self.atoms.copy(), sc=sc) + return self.__class__(self.xyz[:, idx].copy(), atoms=self.atoms.copy(), lattice=lattice) def center(self, atoms: Optional[AtomsArgument]=None, what: str="xyz") -> ndarray: @@ -2550,7 +2553,7 @@ def center(self, atoms: Optional[AtomsArgument]=None, determine which center to calculate """ if "cell" == what: - return self.sc.center() + return self.lattice.center() if atoms is None: g = self @@ -2569,7 +2572,7 @@ def center(self, atoms: Optional[AtomsArgument]=None, avg_cos = (mass @ np.cos(theta)) / sum_mass avg_sin = (mass @ np.sin(theta)) / sum_mass avg_theta = np.arctan2(-avg_sin, -avg_cos) / (2*np.pi) + 0.5 - return avg_theta @ g.sc.cell + return avg_theta @ g.lattice.cell if "mass" == what: mass = g.mass @@ -2601,9 +2604,9 @@ def append(self, other, axis, offset="none") -> Geometry: Parameters ---------- - other : Geometry or SuperCell + other : Geometry or Lattice Other geometry class which needs to be appended - If a `SuperCell` only the super cell will be extended + If a `Lattice` only the super cell will be extended axis : int Cell direction to which the `other` geometry should be appended. @@ -2623,11 +2626,11 @@ def append(self, other, axis, offset="none") -> Geometry: attach : attach a geometry insert : insert a geometry """ - if isinstance(other, SuperCell): + if isinstance(other, Lattice): # Only extend the supercell. xyz = np.copy(self.xyz) atoms = self.atoms.copy() - sc = self.sc.append(other, axis) + lattice = self.lattice.append(other, axis) names = self._names.copy() if isinstance(offset, str): if offset == "none": @@ -2655,10 +2658,10 @@ def append(self, other, axis, offset="none") -> Geometry: xyz = np.append(self.xyz, offset + other.xyz, axis=0) atoms = self.atoms.append(other.atoms) - sc = self.sc.append(other.sc, axis) + lattice = self.lattice.append(other.lattice, axis) names = self._names.merge(other._names, offset=len(self)) - return self.__class__(xyz, atoms=atoms, sc=sc, names=names) + return self.__class__(xyz, atoms=atoms, lattice=lattice, names=names) def prepend(self, other, axis, offset="none") -> Geometry: """ Prepend two structures along `axis` @@ -2678,9 +2681,9 @@ def prepend(self, other, axis, offset="none") -> Geometry: Parameters ---------- - other : Geometry or SuperCell + other : Geometry or Lattice Other geometry class which needs to be prepended - If a `SuperCell` only the super cell will be extended + If a `Lattice` only the super cell will be extended axis : int Cell direction to which the `other` geometry should be prepended @@ -2700,11 +2703,11 @@ def prepend(self, other, axis, offset="none") -> Geometry: attach : attach a geometry insert : insert a geometry """ - if isinstance(other, SuperCell): + if isinstance(other, Lattice): # Only extend the supercell. xyz = np.copy(self.xyz) atoms = self.atoms.copy() - sc = self.sc.prepend(other, axis) + lattice = self.lattice.prepend(other, axis) names = self._names.copy() if isinstance(offset, str): if offset == "none": @@ -2732,20 +2735,20 @@ def prepend(self, other, axis, offset="none") -> Geometry: xyz = np.append(other.xyz, offset + self.xyz, axis=0) atoms = self.atoms.prepend(other.atoms) - sc = self.sc.prepend(other.sc, axis) + lattice = self.lattice.prepend(other.lattice, axis) names = other._names.merge(self._names, offset=len(other)) - return self.__class__(xyz, atoms=atoms, sc=sc, names=names) + return self.__class__(xyz, atoms=atoms, lattice=lattice, names=names) def add(self, other, offset=(0, 0, 0)) -> Geometry: - """ Merge two geometries (or a Geometry and SuperCell) by adding the two atoms together + """ Merge two geometries (or a Geometry and Lattice) by adding the two atoms together If `other` is a Geometry only the atoms gets added, to also add the supercell vectors - simply do ``geom.add(other).add(other.sc)``. + simply do ``geom.add(other).add(other.lattice)``. Parameters ---------- - other : Geometry or SuperCell + other : Geometry or Lattice Other geometry class which is added offset : (3,), optional offset in geometry of `other` when adding the atoms. Only if `other` is @@ -2758,18 +2761,18 @@ def add(self, other, offset=(0, 0, 0)) -> Geometry: attach : attach a geometry insert : insert a geometry """ - if isinstance(other, SuperCell): + if isinstance(other, Lattice): xyz = self.xyz.copy() + _a.arrayd(offset) - sc = self.sc + other + lattice = self.lattice + other atoms = self.atoms.copy() names = self._names.copy() else: other = self.new(other) xyz = np.append(self.xyz, other.xyz + _a.arrayd(offset), axis=0) - sc = self.sc.copy() + lattice = self.lattice.copy() atoms = self.atoms.add(other.atoms) names = self._names.merge(other._names, offset=len(self)) - return self.__class__(xyz, atoms=atoms, sc=sc, names=names) + return self.__class__(xyz, atoms=atoms, lattice=lattice, names=names) def insert(self, atom, other) -> Geometry: """ Inserts other atoms right before index @@ -2797,19 +2800,19 @@ def insert(self, atom, other) -> Geometry: other = self.new(other) xyz = np.insert(self.xyz, atom, other.xyz, axis=0) atoms = self.atoms.insert(atom, other.atoms) - return self.__class__(xyz, atoms, sc=self.sc.copy()) + return self.__class__(xyz, atoms, lattice=self.lattice.copy()) def __add__(self, b) -> Geometry: """ Merge two geometries (or geometry and supercell) Parameters ---------- - self, b : Geometry or SuperCell or tuple or list + self, b : Geometry or Lattice or tuple or list when adding a Geometry with a Geometry it defaults to using `add` function with the LHS retaining the cell-vectors. a tuple/list may be of length 2 with the first element being a Geometry and the second being an integer specifying the lattice vector where it is appended. - One may also use a `SuperCell` instead of a `Geometry` which behaves similarly. + One may also use a `Lattice` instead of a `Geometry` which behaves similarly. Examples -------- @@ -2825,7 +2828,7 @@ def __add__(self, b) -> Geometry: append : appending geometries prepend : prending geometries """ - if isinstance(b, (SuperCell, Geometry)): + if isinstance(b, (Lattice, Geometry)): return self.add(b) return self.append(b[0], b[1]) @@ -2834,12 +2837,12 @@ def __radd__(self, b) -> Geometry: Parameters ---------- - self, b : Geometry or SuperCell or tuple or list + self, b : Geometry or Lattice or tuple or list when adding a Geometry with a Geometry it defaults to using `add` function with the LHS retaining the cell-vectors. a tuple/list may be of length 2 with the first element being a Geometry and the second being an integer specifying the lattice vector where it is appended. - One may also use a `SuperCell` instead of a `Geometry` which behaves similarly. + One may also use a `Lattice` instead of a `Geometry` which behaves similarly. Examples -------- @@ -2855,7 +2858,7 @@ def __radd__(self, b) -> Geometry: append : appending geometries prepend : prending geometries """ - if isinstance(b, (SuperCell, Geometry)): + if isinstance(b, (Lattice, Geometry)): return b.add(self) return self + b @@ -2970,7 +2973,7 @@ def reverse(self, atoms: Optional[AtomsArgument]=None) -> Geometry: atoms = self._sanitize_atoms(atoms).ravel() xyz = np.copy(self.xyz) xyz[atoms, :] = self.xyz[atoms[::-1], :] - return self.__class__(xyz, atoms=self.atoms.reverse(atoms), sc=self.sc.copy()) + return self.__class__(xyz, atoms=self.atoms.reverse(atoms), lattice=self.lattice.copy()) def mirror(self, method, atoms: Optional[AtomsArgument]=None, point=(0, 0, 0)) -> Geometry: r""" Mirrors the atomic coordinates about a plane given by its normal vector @@ -3058,12 +3061,12 @@ def axyz(self, atoms: Optional[AtomsArgument]=None, isc=None) -> ndarray: Examples -------- - >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], sc=1.) + >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], lattice=1.) >>> print(geom.axyz(isc=[1,0,0])) # doctest: +NORMALIZE_WHITESPACE [[1. 0. 0. ] [1.5 0. 0. ]] - >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], sc=1.) + >>> geom = Geometry([[0, 0, 0], [0.5, 0, 0]], lattice=1.) >>> print(geom.axyz(0)) # doctest: +NORMALIZE_WHITESPACE [0. 0. 0.] @@ -3076,11 +3079,11 @@ def axyz(self, atoms: Optional[AtomsArgument]=None, isc=None) -> ndarray: if isc is None: # get offsets from atomic indices (note that this will be per atom) isc = self.a2isc(atoms) - offset = self.sc.offset(isc) + offset = self.lattice.offset(isc) return self.xyz[self.sc2uc(atoms), :] + offset # Neither of atoms, or isc are `None`, we add the offset to all coordinates - return self.axyz(atoms) + self.sc.offset(isc) + return self.axyz(atoms) + self.lattice.offset(isc) def scale(self, scale, what:str ="abc", @@ -3103,7 +3106,7 @@ def scale(self, scale, scale = np.asarray(scale) # Scale the supercell - sc = self.sc.scale(scale, what=what) + lattice = self.lattice.scale(scale, what=what) if what == "xyz": # It is faster to rescale coordinates by simply multiplying them by the scale @@ -3112,15 +3115,15 @@ def scale(self, scale, elif what == "abc": # Scale the coordinates by keeping fractional coordinates the same - xyz = self.fxyz @ sc.cell + xyz = self.fxyz @ lattice.cell if scale_atoms: # To rescale atoms, we need to know the span of each cartesian coordinate before and # after the scaling, and scale the atoms according to the coordinate that has # been scaled by the largest factor. - prev_verts = self.sc.vertices().reshape(8, 3) + prev_verts = self.lattice.vertices().reshape(8, 3) prev_span = prev_verts.max(axis=0) - prev_verts.min(axis=0) - scaled_verts = sc.vertices().reshape(8, 3) + scaled_verts = lattice.vertices().reshape(8, 3) scaled_span = scaled_verts.max(axis=0) - scaled_verts.min(axis=0) max_scale = (scaled_span / prev_span).max() else: @@ -3132,7 +3135,7 @@ def scale(self, scale, else: atoms = self.atoms.copy() - return self.__class__(xyz, atoms=atoms, sc=sc) + return self.__class__(xyz, atoms=atoms, lattice=lattice) def within_sc(self, shapes, isc=None, atoms: Optional[AtomsArgument]=None, atoms_xyz=None, @@ -3194,7 +3197,7 @@ def within_sc(self, shapes, isc=None, # Get shape centers off = shapes[-1].center[:] # Get the supercell offset - soff = self.sc.offset(isc)[:] + soff = self.lattice.offset(isc)[:] # Get atomic coordinate in principal cell if atoms_xyz is None: @@ -3365,7 +3368,7 @@ def close_sc(self, xyz_ia, isc=(0, 0, 0), R=None, off = xyz_ia # Calculate the complete offset - foff = self.sc.offset(isc)[:] - off[:] + foff = self.lattice.offset(isc)[:] - off[:] # Get atomic coordinate in principal cell if atoms_xyz is None: @@ -3602,8 +3605,8 @@ def isc_tile(isc, n): for s in range(self.n_s): na = self.na * s - isc = self.sc.sc_off[s, :] - sret = self.within_sc(shapes, self.sc.sc_off[s, :], + isc = self.lattice.sc_off[s, :] + sret = self.within_sc(shapes, self.lattice.sc_off[s, :], atoms=atoms, atoms_xyz=atoms_xyz, ret_xyz=ret_xyz, ret_rij=ret_rij) if n_ret == 0: @@ -3730,7 +3733,7 @@ def isc_tile(isc, n): for s in range(self.n_s): na = self.na * s - isc = self.sc.sc_off[s, :] + isc = self.lattice.sc_off[s, :] sret = self.close_sc(xyz_ia, isc, R=R, atoms=atoms, atoms_xyz=atoms_xyz, ret_xyz=ret_xyz, ret_rij=ret_rij) @@ -3809,7 +3812,7 @@ def a2transpose(self, atoms1, atoms2=None) -> tuple[ndarray, ndarray]: atoms1 = self._sanitize_atoms(atoms1) if atoms2 is None: # we only need to transpose atoms1 - offset = self.sc.sc_index(-self.a2isc(atoms1)) * self.na + offset = self.lattice.sc_index(-self.a2isc(atoms1)) * self.na return atoms1 % self.na + offset atoms2 = self._sanitize_atoms(atoms2) @@ -3824,7 +3827,7 @@ def a2transpose(self, atoms1, atoms2=None) -> tuple[ndarray, ndarray]: # Now convert atoms na = self.na - sc_index = self.sc.sc_index + sc_index = self.lattice.sc_index isc1 = self.a2isc(atoms1) isc2 = self.a2isc(atoms2) @@ -3871,7 +3874,7 @@ def o2transpose(self, orb1: OrbitalsArgument, orb2: Optional[OrbitalsArgument]=N orb1 = self._sanitize_orbs(orb1) if orb2 is None: # we only need to transpose orb1 - offset = self.sc.sc_index(-self.o2isc(orb1)) * self.no + offset = self.lattice.sc_index(-self.o2isc(orb1)) * self.no return orb1 % self.no + offset orb2 = self._sanitize_orbs(orb2) @@ -3886,7 +3889,7 @@ def o2transpose(self, orb1: OrbitalsArgument, orb2: Optional[OrbitalsArgument]=N # Now convert orbs no = self.no - sc_index = self.sc.sc_index + sc_index = self.lattice.sc_index isc1 = self.o2isc(orb1) isc2 = self.o2isc(orb2) @@ -4025,7 +4028,7 @@ def a2isc(self, atoms: AtomsArgument) -> ndarray: atoms = self._sanitize_atoms(atoms) // self.na if atoms.ndim > 1: atoms = atoms.ravel() - return self.sc.sc_off[atoms, :] + return self.lattice.sc_off[atoms, :] # This function is a bit weird, it returns a real array, # however, there should be no ambiguity as it corresponds to th @@ -4034,7 +4037,7 @@ def a2sc(self, atoms: AtomsArgument) -> ndarray: """ Returns the super-cell offset for a specific atom """ - return self.sc.offset(self.a2isc(atoms)) + return self.lattice.offset(self.a2isc(atoms)) def o2isc(self, orbitals: OrbitalsArgument) -> ndarray: """ @@ -4045,15 +4048,15 @@ def o2isc(self, orbitals: OrbitalsArgument) -> ndarray: orbitals = self._sanitize_orbs(orbitals) // self.no if orbitals.ndim > 1: orbitals = orbitals.ravel() - return self.sc.sc_off[orbitals, :] + return self.lattice.sc_off[orbitals, :] def o2sc(self, orbitals: OrbitalsArgument) -> ndarray: """ Returns the super-cell offset for a specific orbital. """ - return self.sc.offset(self.o2isc(orbitals)) + return self.lattice.offset(self.o2isc(orbitals)) - def __plot__(self, axis=None, supercell=True, axes=False, + def __plot__(self, axis=None, lattice=True, axes=False, atom_indices=False, *args, **kwargs): """ Plot the geometry in a specified ``matplotlib.Axes`` object. @@ -4061,8 +4064,8 @@ def __plot__(self, axis=None, supercell=True, axes=False, ---------- axis : array_like, optional only plot a subset of the axis, defaults to all axis - supercell : bool, optional - If `True` also plot the supercell structure + lattice : bool, optional + If `True` also plot the lattice structure atom_indices : bool, optional if true, also add atomic numbering in the plot (0-based) axes : bool or matplotlib.Axes, optional @@ -4092,8 +4095,8 @@ def __plot__(self, axis=None, supercell=True, axes=False, axes = plt.get_axes(axes, **d) # Start by plotting the supercell - if supercell: - axes = self.sc.__plot__(axis, axes=axes, *args, **kwargs) + if lattice: + axes = self.lattice.__plot__(axis, axes=axes, *args, **kwargs) # Create short-hand xyz = self.xyz @@ -4132,7 +4135,7 @@ def equal(self, other, R=True, tol=1e-4) -> bool: other = self.new(other) if not isinstance(other, Geometry): return False - same = self.sc.equal(other.sc, tol=tol) + same = self.lattice.equal(other.lattice, tol=tol) same = same and np.allclose(self.xyz, other.xyz, atol=tol) same = same and self.atoms.equal(other.atoms, R) return same @@ -4145,7 +4148,6 @@ def __ne__(self, other): def sparserij(self, dtype=np.float64, na_iR=1000, method='rand'): """ Return the sparse matrix with all distances in the matrix - The sparse matrix will only be defined for the elements which have orbitals overlapping with other atoms. @@ -4228,7 +4230,7 @@ def distance(self, atoms: Optional[AtomsArgument]=None, Examples -------- - >>> geom = Geometry([0]*3, Atom(1, R=1.), sc=SuperCell(1., nsc=[5, 5, 1])) + >>> geom = Geometry([0]*3, Atom(1, R=1.), lattice=Lattice(1., nsc=[5, 5, 1])) >>> geom.distance() # use geom.maxR() # doctest: +NORMALIZE_WHITESPACE array([1.]) >>> geom.distance(tol=[0.5, 0.4, 0.3, 0.2]) @@ -4266,7 +4268,7 @@ def distance(self, atoms: Optional[AtomsArgument]=None, if i == 0 and j == 0 and k == 0: continue sc = [i, j, k] - off = self.sc.offset(sc) + off = self.lattice.offset(sc) for ii, jj, kk in product([0, 1], [0, 1], [0, 1]): o = self.cell[0, :] * ii + \ @@ -4345,7 +4347,7 @@ def func(lst): return d - def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): + def within_inf(self, lattice, periodic=None, tol=1e-5, origin=None): """ Find all atoms within a provided supercell Note this function is rather different from `close` and `within`. @@ -4353,7 +4355,7 @@ def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): periodic system (where ``self.nsc > 1`` or `periodic` is true). Atomic coordinates lying on the boundary of the supercell will be duplicated - on the neighbouring supercell images. Thus performing `geom.within_inf(geom.sc)` + on the neighbouring supercell images. Thus performing `geom.within_inf(geom.lattice)` may result in more atoms than in the structure. Notes @@ -4363,7 +4365,7 @@ def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): Parameters ---------- - sc : SuperCell or SuperCellChild + lattice : Lattice or LatticeChild the supercell in which this geometry should be expanded into. periodic : list of bool explicitly define the periodic directions, by default the periodic @@ -4378,7 +4380,7 @@ def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): Returns ------- numpy.ndarray - unit-cell atomic indices which are inside the `sc` cell + unit-cell atomic indices which are inside the `lattice` cell numpy.ndarray atomic coordinates for the `ia` atoms (including supercell offsets) numpy.ndarray @@ -4396,8 +4398,8 @@ def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): # enough to fully encompass the supercell # 1. Number of times each lattice vector must be expanded to fit - # inside the "possibly" larger `sc`. - idx = dot(sc.cell, self.icell.T) + # inside the "possibly" larger `lattice`. + idx = dot(lattice.cell, self.icell.T) tile_min = floor(idx.min(0)) tile_max = ceil(idx.max(0)).astype(dtype=int32) @@ -4410,7 +4412,7 @@ def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): del idx, tmp # 1a) correct for origin displacement - idx = floor(dot(sc.origin, self.icell.T)) + idx = floor(dot(lattice.origin, self.icell.T)) tile_min = np.where(tile_min < idx, tile_min, idx).astype(dtype=int32) idx = floor(dot(origin, self.icell.T)) tile_min = np.where(tile_min < idx, tile_min, idx).astype(dtype=int32) @@ -4421,7 +4423,7 @@ def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): # 3. Find the *new* origin according to the *negative* tilings. # This is important for skewed cells as the placement of the new - # larger geometry has to be shifted to have sc inside + # larger geometry has to be shifted to have lattice inside big_origin = (tile_min.reshape(3, 1) * self.cell).sum(0) # The xyz geometry that fully encompass the (possibly) larger supercell @@ -4429,7 +4431,7 @@ def within_inf(self, sc, periodic=None, tol=1e-5, origin=None): full_geom = (self * tile).translate(big_origin - origin) # Now we have to figure out all atomic coordinates within - cuboid = sc.toCuboid() + cuboid = lattice.toCuboid() # Make sure that full_geom doesn't return coordinates outside the unit cell # for non periodic directions @@ -4537,18 +4539,18 @@ def apply(self, data, func, mapper, axis: int=0, segments="atoms"): # Create pickling routines def __getstate__(self): """ Returns the state of this object """ - d = self.sc.__getstate__() + d = self.lattice.__getstate__() d['xyz'] = self.xyz d['atoms'] = self.atoms.__getstate__() return d def __setstate__(self, d): """ Re-create the state of this object """ - sc = SuperCell([1, 1, 1]) - sc.__setstate__(d) + lattice = Lattice([1, 1, 1]) + lattice.__setstate__(d) atoms = Atoms() atoms.__setstate__(d['atoms']) - self.__init__(d['xyz'], atoms=atoms, sc=sc) + self.__init__(d['xyz'], atoms=atoms, lattice=lattice) @classmethod def _ArgumentParser_args_single(cls): @@ -4947,8 +4949,8 @@ def dispatch(self, aseg, **kwargs): xyz = aseg.get_positions() cell = aseg.get_cell() nsc = [3 if pbc else 1 for pbc in aseg.pbc] - sc = SuperCell(cell, nsc=nsc) - return self._obj(xyz, atoms=Z, sc=sc, **kwargs) + lattice = Lattice(cell, nsc=nsc) + return self._obj(xyz, atoms=Z, lattice=lattice, **kwargs) new_dispatch.register("ase", GeometryNewAseDispatcher) # currently we can't ensure the ase Atoms type @@ -4981,8 +4983,8 @@ def dispatch(self, struct, **kwargs): else: cell = xyz.max() - xyz.min(0) + 15. nsc = [1, 1, 1] - sc = SuperCell(cell, nsc=nsc) - return self._obj(xyz, atoms=Z, sc=sc, **kwargs) + lattice = Lattice(cell, nsc=nsc) + return self._obj(xyz, atoms=Z, lattice=lattice, **kwargs) new_dispatch.register("pymatgen", GeometryNewpymatgenDispatcher) # currently we can't ensure the pymatgen classes @@ -5229,7 +5231,7 @@ def sgeom(geometry=None, argv=None, ret_geometry=False): print('Cell:') for i in (0, 1, 2): print(' {:10.6f} {:10.6f} {:10.6f}'.format(*g.cell[i, :])) - print('SuperCell:') + print('Lattice:') print(' {:d} {:d} {:d}'.format(*g.nsc)) print(' {:>10s} {:>10s} {:>10s} {:>3s}'.format('x', 'y', 'z', 'Z')) for ia in g: diff --git a/sisl/grid.py b/sisl/grid.py index b55e9a25ae..002e8e2bff 100644 --- a/sisl/grid.py +++ b/sisl/grid.py @@ -13,6 +13,7 @@ from scipy.ndimage import zoom as ndimage_zoom from ._internal import set_module +from .messages import deprecate_argument from . import _array as _a from ._help import dtype_complex_to_real, wrap_filterwarnings from .shape import Shape @@ -21,14 +22,14 @@ from .utils import import_attr from .utils.mathematics import fnorm -from .supercell import SuperCellChild +from .lattice import LatticeChild from .geometry import Geometry __all__ = ['Grid', 'sgrid'] @set_module("sisl") -class Grid(SuperCellChild): +class Grid(LatticeChild): """ Real-space grid information with associated geometry. This grid object handles cell vectors and divisions of said grid. @@ -40,25 +41,25 @@ class Grid(SuperCellChild): a list of integers specifies the exact grid size. bc : list of int (3, 2) or (3, ), optional the boundary conditions for each of the cell's planes. Default to periodic BC. - sc : SuperCell, optional - the supercell that this grid represents. `sc` has precedence if both `geometry` and `sc` - has been specified. Default to ``[1, 1, 1]``. + lattice : Lattice, optional + the lattice that this grid represents. `lattice` has precedence if both `geometry` and `lattice` + has been specified. Defaults to ``[1, 1, 1]``. dtype : numpy.dtype, optional the data-type of the grid, default to `numpy.float64`. geometry : Geometry, optional - associated geometry with the grid. If `sc` has not been passed the supercell will + associated geometry with the grid. If `lattice` has not been passed the lattice will be taken from this geometry. Examples -------- - >>> grid1 = Grid(0.1, sc=10) - >>> grid2 = Grid(0.1, sc=SuperCell(10)) - >>> grid3 = Grid(0.1, sc=SuperCell([10] * 3)) + >>> grid1 = Grid(0.1, lattice=10) + >>> grid2 = Grid(0.1, lattice=Lattice(10)) + >>> grid3 = Grid(0.1, lattice=Lattice([10] * 3)) >>> grid1 == grid2 True >>> grid1 == grid3 True - >>> grid = Grid(0.1, sc=10, dtype=np.complex128) + >>> grid = Grid(0.1, lattice=10, dtype=np.complex128) >>> grid == grid1 False """ @@ -72,11 +73,14 @@ class Grid(SuperCellChild): #: Constant for defining an open boundary condition OPEN = 4 - def __init__(self, shape, bc=None, sc=None, dtype=None, geometry=None): + @deprecate_argument("sc", "lattice", + "argument sc has been deprecated in favor of lattice, please update your code.", + "0.15.0") + def __init__(self, shape, bc=None, lattice=None, dtype=None, geometry=None): if bc is None: bc = [[self.PERIODIC] * 2] * 3 - self.set_supercell(sc) + self.set_lattice(lattice) # Create the atomic structure in the grid, if possible self.set_geometry(geometry) @@ -92,10 +96,10 @@ def __init__(self, shape, bc=None, sc=None, dtype=None, geometry=None): self.set_bc(bc) # If the user sets the super-cell, that has precedence. - if sc is not None: + if lattice is not None: if not self.geometry is None: - self.geometry.set_supercell(sc) - self.set_supercell(sc) + self.geometry.set_lattice(lattice) + self.set_lattice(lattice) def __getitem__(self, key): """ Grid value at `key` """ @@ -118,7 +122,7 @@ def set_geometry(self, geometry): self.geometry = None else: self.geometry = geometry - self.set_supercell(geometry.sc) + self.set_lattice(geometry.lattice) def fill(self, val): """ Fill the grid with this value @@ -369,9 +373,9 @@ def set_bc(self, boundary=None, a=None, b=None, c=None): set_boundary_condition = set_bc def __sc_geometry_dict(self): - """ Internal routine for copying the SuperCell and Geometry """ + """ Internal routine for copying the Lattice and Geometry """ d = dict() - d['sc'] = self.sc.copy() + d['lattice'] = self.lattice.copy() if not self.geometry is None: d['geometry'] = self.geometry.copy() return d @@ -389,7 +393,7 @@ def copy(self, dtype=None): return grid def swapaxes(self, a, b): - """ Swap two axes in the grid (also swaps axes in the supercell) + """ Swap two axes in the grid (also swaps axes in the lattice) If ``swapaxes(0,1)`` it returns the 0 in the 1 values. @@ -404,7 +408,7 @@ def swapaxes(self, a, b): idx[a] = b s = np.copy(self.shape) d = self.__sc_geometry_dict() - d['sc'] = d['sc'].swapaxes(a, b) + d['lattice'] = d['lattice'].swapaxes(a, b) d['dtype'] = self.dtype grid = self.__class__(s[idx], bc=self.bc[idx], **d) # We need to force the C-order or we loose the contiguity @@ -420,7 +424,7 @@ def dcell(self): @property def dvolume(self): """ Volume of the grid voxel elements """ - return self.sc.volume / self.size + return self.lattice.volume / self.size def _copy_sub(self, n, axis, scale_geometry=False): # First calculate the new shape @@ -433,12 +437,12 @@ def _copy_sub(self, n, axis, scale_geometry=False): raise ValueError('You cannot retain no indices.') grid = self.__class__(shape, bc=np.copy(self.bc), dtype=self.dtype, **self.__sc_geometry_dict()) # Update cell shape (the cell is smaller now) - grid.set_supercell(cell) + grid.set_lattice(cell) if scale_geometry and not self.geometry is None: geom = self.geometry.copy() fxyz = geom.fxyz.copy() - geom.set_supercell(grid.sc) - geom.xyz[:, :] = np.dot(fxyz, grid.sc.cell) + geom.set_lattice(grid.lattice) + geom.xyz[:, :] = np.dot(fxyz, grid.lattice.cell) grid.set_geometry(geom) return grid @@ -579,7 +583,7 @@ def sub(self, idx, axis): min_xyz = self.dcell[axis, :] * idx[0] # Now shift the geometry according to what is retained geom = self.geometry.translate(-min_xyz) - geom.set_supercell(grid.sc) + geom.set_lattice(grid.lattice) grid.set_geometry(geom) else: grid = self._copy_sub(len(idx), axis, scale_geometry=True) @@ -632,7 +636,7 @@ def tile(self, reps, axis): reps_all[axis] = reps grid.grid = np.tile(self.grid, reps_all) if self.geometry is None: - grid.set_supercell(self.sc.tile(reps, axis)) + grid.set_lattice(self.lattice.tile(reps, axis)) else: grid.set_geometry(self.geometry.tile(reps, axis)) return grid @@ -949,7 +953,7 @@ def __str__(self): if not self.geometry is None: s += '{}\n}}'.format(str(self.geometry).replace('\n', '\n ')) else: - s += '{}\n}}'.format(str(self.sc).replace('\n', '\n ')) + s += '{}\n}}'.format(str(self.lattice).replace('\n', '\n ')) return s def _check_compatibility(self, other, msg): @@ -1520,7 +1524,7 @@ def _conv_shape(length, value): if "." in value: return int(round(length / float(value))) return int(value) - shape = list(map(_conv_shape, ns._grid.sc.length, values[:3])) + shape = list(map(_conv_shape, ns._grid.lattice.length, values[:3])) # shorten list for easier arguments values = values[3:] if len(values) > 0: @@ -1530,7 +1534,7 @@ def _conv_shape(length, value): action=InterpGrid, help="""Interpolate grid for higher or lower density (minimum 3 arguments) Requires at least 3 arguments, number of points along 1st, 2nd and 3rd lattice vector. These may contain a "." to signal a distance in angstrom of each voxel. -For instance --interp 0.1 10 100 will result in an interpolated shape of [nint(grid.sc.length / 0.1), 10, 100]. +For instance --interp 0.1 10 100 will result in an interpolated shape of [nint(grid.lattice.length / 0.1), 10, 100]. The 4th optional argument is the order of interpolation; an integer 0<=i<=5 (default 1) The 5th optional argument is the mode to interpolate; wrap/mirror/constant/reflect/nearest @@ -1572,7 +1576,7 @@ def __call__(self, parser, ns, values, option_string=None): for ax in (0, 1, 2): shape = grid.shape[ax] if shape > 1: - axs.append(np.linspace(0, grid.sc.length[ax], shape, endpoint=False)) + axs.append(np.linspace(0, grid.lattice.length[ax], shape, endpoint=False)) idx.append(ax) # Now plot data @@ -1615,7 +1619,7 @@ def __call__(self, parser, ns, value, option_string=None): # the distance along the lattice vector idx = np.argmax(grid.shape) - dx = np.linspace(0, grid.sc.length[idx], grid.shape[idx], endpoint=False) + dx = np.linspace(0, grid.lattice.length[idx], grid.shape[idx], endpoint=False) sile.write_data(dx, grid.grid.ravel()) else: raise ValueError(f"""Either of these two cases are not fullfilled: @@ -1711,7 +1715,7 @@ def sgrid(grid=None, argv=None, ret_grid=False): kwargs = {} if input_file is None: stdout_grid = False - grid = Grid(0.1, geometry=Geometry([0] * 3, sc=1)) + grid = Grid(0.1, geometry=Geometry([0] * 3, lattice=1)) else: grid = Grid.read(input_file) diff --git a/sisl/io/bigdft/ascii.py b/sisl/io/bigdft/ascii.py index 832e949a8e..c2636cbe85 100644 --- a/sisl/io/bigdft/ascii.py +++ b/sisl/io/bigdft/ascii.py @@ -9,7 +9,7 @@ from ..sile import * from sisl._internal import set_module -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl.unit import unit_convert import numpy as np @@ -110,9 +110,9 @@ def read_geometry(self): # Create the supercell if is_angdeg: # The input is in skewed axis - sc = SuperCell([dxx, dyx, dyy, dzx, dzy, dzz]) + lattice = Lattice([dxx, dyx, dyy, dzx, dzy, dzz]) else: - sc = SuperCell([[dxx, 0., 0.], [dyx, dyy, 0.], [dzx, dzy, dzz]]) + lattice = Lattice([[dxx, 0., 0.], [dyx, dyy, 0.], [dzx, dzy, dzz]]) # Now create the geometry xyz = np.array(xyz, np.float64) @@ -120,7 +120,7 @@ def read_geometry(self): if is_frac: # Transform from fractional to actual # coordinates - xyz = np.dot(xyz, sc.cell.T) + xyz = np.dot(xyz, lattice.cell.T) elif is_bohr: # Not when fractional coordinates are used @@ -128,7 +128,7 @@ def read_geometry(self): # correct unit xyz *= Bohr2Ang - return Geometry(xyz, spec, sc=sc) + return Geometry(xyz, spec, lattice=lattice) @sile_fh_open() def write_geometry(self, geom, fmt='.8f'): diff --git a/sisl/io/cube.py b/sisl/io/cube.py index 998293700f..7b6c37169f 100644 --- a/sisl/io/cube.py +++ b/sisl/io/cube.py @@ -6,9 +6,10 @@ # Import sile objects from sisl.io.sile import * from ._help import header_to_dict +from sisl.messages import deprecate_argument from sisl._internal import set_module -from sisl import Geometry, Atom, SuperCell, Grid, SislError +from sisl import Geometry, Atom, Lattice, Grid, SislError from sisl.unit import unit_convert @@ -26,15 +27,16 @@ class cubeSile(Sile): """ @sile_fh_open() - def write_supercell(self, sc, fmt="15.10e", size=None, origin=None, + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice, fmt="15.10e", size=None, origin=None, unit="Bohr", *args, **kwargs): - """ Writes `SuperCell` object attached to this grid + """ Writes `Lattice` object attached to this grid Parameters ---------- - sc : SuperCell - supercell to be written + lattice : Lattice + lattice to be written fmt : str, optional floating point format for stored values size : (3, ), optional @@ -55,7 +57,7 @@ def write_supercell(self, sc, fmt="15.10e", size=None, origin=None, if size is None: size = np.ones([3], np.int32) if origin is None: - origin = sc.origin[:] + origin = lattice.origin[:] _fmt = "{:d} {:15.10e} {:15.10e} {:15.10e}\n" @@ -64,7 +66,7 @@ def write_supercell(self, sc, fmt="15.10e", size=None, origin=None, # Write the cell and voxels for ix in range(3): - dcell = sc.cell[ix, :] / size[ix] * Ang2unit + dcell = lattice.cell[ix, :] / size[ix] * Ang2unit self._write(_fmt.format(size[ix], *dcell)) self._write("1 0. 0. 0. 0.\n") @@ -143,7 +145,7 @@ def write_grid(self, grid, fmt=".5e", imag=False, unit="Bohr", *args, **kwargs): sile_raise_write(self) if grid.geometry is None: - self.write_supercell(grid.sc, size=grid.shape, unit=unit, *args, **kwargs) + self.write_lattice(grid.lattice, size=grid.shape, unit=unit, *args, **kwargs) else: self.write_geometry(grid.geometry, size=grid.shape, unit=unit, *args, **kwargs) @@ -186,8 +188,8 @@ def _r_header_dict(self): return header @sile_fh_open() - def read_supercell(self, na=False): - """ Returns `SuperCell` object from the CUBE file + def read_lattice(self, na=False): + """ Returns `Lattice` object from the CUBE file Parameters ---------- @@ -211,14 +213,14 @@ def read_supercell(self, na=False): cell = cell * unit2Ang origin = origin * unit2Ang if na: - return lna, SuperCell(cell, origin=origin) - return SuperCell(cell, origin=origin) + return lna, Lattice(cell, origin=origin) + return Lattice(cell, origin=origin) @sile_fh_open() def read_geometry(self): """ Returns `Geometry` object from the CUBE file """ unit2Ang = self._r_header_dict()["unit"] - na, sc = self.read_supercell(na=True) + na, lattice = self.read_lattice(na=True) if na == 0: return None @@ -233,7 +235,7 @@ def read_geometry(self): xyz[ia, 1] = float(tmp[3]) xyz[ia, 2] = float(tmp[4]) - return Geometry(xyz * unit2Ang, atom, sc=sc) + return Geometry(xyz * unit2Ang, atom, lattice=lattice) @sile_fh_open() def read_grid(self, imag=None): @@ -252,9 +254,9 @@ def read_grid(self, imag=None): geom = self.read_geometry() if geom is None: self.fh.seek(0) - sc = self.read_supercell() + lattice = self.read_lattice() else: - sc = geom.sc + lattice = geom.lattice # read headers (and seek to start) self._r_header_dict() @@ -270,7 +272,7 @@ def read_grid(self, imag=None): self.readline() if geom is None: - grid = Grid(ngrid, dtype=np.float64, sc=sc) + grid = Grid(ngrid, dtype=np.float64, lattice=lattice) else: grid = Grid(ngrid, dtype=np.float64, geometry=geom) grid.grid.shape = (-1,) diff --git a/sisl/io/fhiaims/_geometry.py b/sisl/io/fhiaims/_geometry.py index 3557a860b3..f395c9eb7f 100644 --- a/sisl/io/fhiaims/_geometry.py +++ b/sisl/io/fhiaims/_geometry.py @@ -11,8 +11,9 @@ from .sile import SileFHIaims +from sisl.messages import deprecate_argument from sisl._internal import set_module -from sisl import Geometry, SuperCell +from sisl import Geometry, Lattice __all__ = ["inSileFHIaims"] @@ -23,21 +24,22 @@ class inSileFHIaims(SileFHIaims): """ FHI-aims geometry file object """ @sile_fh_open() - def write_supercell(self, sc, fmt=".8f"): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice, fmt=".8f"): """ Writes the supercell to the contained file Parameters ---------- - sc : SuperCell + lattice : Lattice the supercell to be written fmt : str, optional used format for the precision of the data """ sile_raise_write(self) _fmt = f"lattice_vector {{:{fmt}}} {{:{fmt}}} {{:{fmt}}}\n" - self._write(_fmt.format(*sc.cell[0])) - self._write(_fmt.format(*sc.cell[1])) - self._write(_fmt.format(*sc.cell[2])) + self._write(_fmt.format(*lattice.cell[0])) + self._write(_fmt.format(*lattice.cell[1])) + self._write(_fmt.format(*lattice.cell[2])) @sile_fh_open() def write_geometry(self, geometry, fmt=".8f", as_frac=False, velocity=None, moment=None): @@ -59,7 +61,7 @@ def write_geometry(self, geometry, fmt=".8f", as_frac=False, velocity=None, mome # Check that we can write to the file sile_raise_write(self) - self.write_supercell(geometry.sc, fmt) + self.write_lattice(geometry.lattice, fmt) if as_frac: xyz = geometry.fxyz @@ -80,7 +82,7 @@ def write_geometry(self, geometry, fmt=".8f", as_frac=False, velocity=None, mome self._write(_fmtm.format(moment[ia])) @sile_fh_open() - def read_supercell(self): + def read_lattice(self): """ Reads supercell object from the file """ self.fh.seek(0) @@ -90,7 +92,7 @@ def read_supercell(self): if line.startswith("lattice_vector"): cell.append([float(f) for f in line.split()[1:]]) - return SuperCell(cell) + return Lattice(cell) @sile_fh_open() def read_geometry(self, velocity=False, moment=False): @@ -115,7 +117,7 @@ def read_geometry(self, velocity=False, moment=False): moment : array_like array of initial moments of each atom, will only be returned if `moment` is true """ - sc = self.read_supercell() + lattice = self.read_lattice() self.fh.seek(0) sp = [] @@ -134,7 +136,7 @@ def ensure_length(l, length, add): if line[0] == "atom": xyz.append([float(f) for f in line[1:4]]) elif line[0] == "atom_frac": - xyz.append([float(f) for f in line[1:4]] @ sc.cell) + xyz.append([float(f) for f in line[1:4]] @ lattice.cell) elif line[0] == "velocity": # ensure xyz and v are same length ensure_length(v, len(xyz) - 1, [0, 0, 0]) @@ -151,7 +153,7 @@ def ensure_length(l, length, add): # we found an atom sp.append(line[4]) - ret = (Geometry(xyz, atoms=sp, sc=sc), ) + ret = (Geometry(xyz, atoms=sp, lattice=lattice), ) if not velocity and not moment: return ret[0] diff --git a/sisl/io/gulp/got.py b/sisl/io/gulp/got.py index 1729a94895..685a6c5aa9 100644 --- a/sisl/io/gulp/got.py +++ b/sisl/io/gulp/got.py @@ -8,10 +8,11 @@ from sisl._internal import set_module from sisl.messages import info, warn +from sisl.messages import deprecate_argument, deprecate_method from .sile import SileGULP from .fc import fcSileGULP from ..sile import add_sile, sile_fh_open -from sisl import Geometry, Atom, Orbital, SuperCell +from sisl import Geometry, Atom, Orbital, Lattice from sisl import constant, units from sisl.physics import DynamicalMatrix @@ -37,7 +38,7 @@ def _setup(self, *args, **kwargs): """ Setup `gotSileGULP` after initialization """ super()._setup(*args, **kwargs) self._keys = dict() - self.set_supercell_key('Cartesian lattice vectors') + self.set_lattice_key('Cartesian lattice vectors') self.set_geometry_key('Final fractional coordinates') self.set_dynamical_matrix_key('Real Dynamical matrix') @@ -46,12 +47,14 @@ def set_key(self, segment, key): if key is not None: self._keys[segment] = key - def set_supercell_key(self, key): + def set_lattice_key(self, key): """ Overwrites internal key lookup value for the cell vectors """ - self.set_key('sc', key) + self.set_key('lattice', key) + + set_supercell_key = deprecate_method("set_supercell_key is deprecated in favor of set_lattice_key", "0.15")(set_lattice_key) @sile_fh_open() - def read_super(self, key=None): + def read_lattice_nsc(self, key=None): """ Reads the dimensions of the supercell """ f, l = self.step_to('Supercell dimensions') @@ -62,21 +65,21 @@ def read_super(self, key=None): xyz = l.split('=')[1:] # Now read off the quantities... - sc = [int(i.split()[0]) for i in xyz] + nsc = [int(i.split()[0]) for i in xyz] - return np.array(sc[:3], np.int32) + return np.array(nsc[:3], np.int32) @sile_fh_open() - def read_supercell(self, key=None, **kwargs): - """ Reads a `SuperCell` and creates the GULP cell """ - self.set_supercell_key(key) + def read_lattice(self, key=None, **kwargs): + """ Reads a `Lattice` and creates the GULP cell """ + self.set_lattice_key(key) - f, _ = self.step_to(self._keys['sc']) + f, _ = self.step_to(self._keys['lattice']) if not f: raise ValueError( - 'SileGULP tries to lookup the SuperCell vectors ' - 'using key "' + self._keys['sc'] + '". \n' - 'Use ".set_supercell_key(...)" to search for different name.\n' + 'SileGULP tries to lookup the Lattice vectors ' + 'using key "' + self._keys['lattice'] + '". \n' + 'Use ".set_lattice_key(...)" to search for different name.\n' 'This could not be found found in file: "' + self.file + '".') # skip 1 line @@ -86,7 +89,7 @@ def read_supercell(self, key=None, **kwargs): l = self.readline().split() cell[i, :] = [float(x) for x in l[:3]] - return SuperCell(cell) + return Lattice(cell) def set_geometry_key(self, key): """ Overwrites internal key lookup value for the geometry vectors """ @@ -96,15 +99,15 @@ def set_geometry_key(self, key): def read_geometry(self, **kwargs): """ Reads a geometry and creates the GULP dynamical geometry """ # create default supercell - sc = SuperCell([1, 1, 1]) + lattice = Lattice([1, 1, 1]) for _ in [0, 1]: # Step to either the geometry or - f, _, ki = self.step_to([self._keys['sc'], self._keys['geometry']], ret_index=True) + f, _, ki = self.step_to([self._keys['lattice'], self._keys['geometry']], ret_index=True) if not f and ki == 0: - raise ValueError('SileGULP tries to lookup the SuperCell vectors ' - 'using key "' + self._keys['sc'] + '". \n' - 'Use ".set_supercell_key(...)" to search for different name.\n' + raise ValueError('SileGULP tries to lookup the Lattice vectors ' + 'using key "' + self._keys['lattice'] + '". \n' + 'Use ".set_lattice_key(...)" to search for different name.\n' 'This could not be found found in file: "' + self.file + '".') elif f and ki == 0: # supercell @@ -115,7 +118,7 @@ def read_geometry(self, **kwargs): cell[i, 0] = float(l[0]) cell[i, 1] = float(l[1]) cell[i, 2] = float(l[2]) - sc = SuperCell(cell) + lattice = Lattice(cell) elif not f and ki == 1: raise ValueError('SileGULP tries to lookup the Geometry coordinates ' @@ -150,7 +153,7 @@ def read_geometry(self, **kwargs): elif not f: # could not find either cell or geometry - raise ValueError('SileGULP tries to lookup the SuperCell or Geometry.\n' + raise ValueError('SileGULP tries to lookup the Lattice or Geometry.\n' 'None succeeded, ensure file has correct format.\n' 'This could not be found found in file: "{}".'.format(self.file)) @@ -158,10 +161,10 @@ def read_geometry(self, **kwargs): # to wait until here to convert from fractional if 'fractional' in self._keys['geometry'].lower(): # Correct for fractional coordinates - xyz = np.dot(xyz, sc.cell) + xyz = np.dot(xyz, lattice.cell) # Return the geometry - return Geometry(xyz, Z, sc=sc) + return Geometry(xyz, Z, lattice=lattice) def set_dynamical_matrix_key(self, key): """ Overwrites internal key lookup value for the dynamical matrix vectors """ diff --git a/sisl/io/gulp/tests/test_gout.py b/sisl/io/gulp/tests/test_gout.py index 3ca42ab942..b8c7902f5f 100644 --- a/sisl/io/gulp/tests/test_gout.py +++ b/sisl/io/gulp/tests/test_gout.py @@ -26,9 +26,9 @@ def test_zz_dynamical_matrix(sisl_files): def test_zz_sc_geom(sisl_files): si = sisl.get_sile(sisl_files(_dir, 'zz.gout')) - sc = si.read_supercell() + lattice = si.read_lattice() geom = si.read_geometry() - assert sc == geom.sc + assert lattice == geom.lattice def test_graphene_8x8_untiling(sisl_files): diff --git a/sisl/io/ham.py b/sisl/io/ham.py index 27ba7faf90..c3049cb361 100644 --- a/sisl/io/ham.py +++ b/sisl/io/ham.py @@ -11,7 +11,7 @@ from sisl._internal import set_module from sisl.messages import warn -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl.sparse import ispmatrix, ispmatrixd from sisl.physics import Hamiltonian from sisl._help import wrap_filterwarnings @@ -85,7 +85,7 @@ def Z2no(i, no): self.readline() # step past the block # Create geometry with associated supercell and atoms - geom = Geometry(xyz, atoms=Atom[Z], sc=SuperCell(cell, nsc)) + geom = Geometry(xyz, atoms=Atom[Z], lattice=Lattice(cell, nsc)) return geom @@ -248,7 +248,7 @@ def write_hamiltonian(self, H, hermitian=True, **kwargs): if hermitian: herm_acc = kwargs.get('herm_acc', 1e-6) # We check whether it is Hermitian (not S) - for i, isc in enumerate(geom.sc.sc_off): + for i, isc in enumerate(geom.lattice.sc_off): oi = i * geom.no oj = geom.sc_index(-isc) * geom.no # get the difference between the ^\dagger elements @@ -264,7 +264,7 @@ def write_hamiltonian(self, H, hermitian=True, **kwargs): if hermitian: # Remove all double stuff - for i, isc in enumerate(geom.sc.sc_off): + for i, isc in enumerate(geom.lattice.sc_off): if np.any(isc < 0): # We have ^\dagger element, remove it o = i * geom.no @@ -301,7 +301,7 @@ def write_hamiltonian(self, H, hermitian=True, **kwargs): # Start writing of the model # We loop on all super-cells - for i, isc in enumerate(geom.sc.sc_off): + for i, isc in enumerate(geom.lattice.sc_off): # Check that we have any contributions in this # sub-section Hsub = h[:, i * geom.no:(i + 1) * geom.no] diff --git a/sisl/io/molden.py b/sisl/io/molden.py index 13b1cf84b0..38d1181d4b 100644 --- a/sisl/io/molden.py +++ b/sisl/io/molden.py @@ -4,6 +4,7 @@ # Import sile objects from .sile import * +from sisl.messages import deprecate_argument from sisl._internal import set_module from sisl import Geometry @@ -16,7 +17,8 @@ class moldenSile(Sile): """ Molden file object """ @sile_fh_open() - def write_supercell(self, sc): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice): """ Writes the supercell to the contained file """ # Check that we can write to the file sile_raise_write(self) @@ -33,7 +35,7 @@ def write_geometry(self, geometry, fmt='.8f'): sile_raise_write(self) # Be sure to write the supercell - self.write_supercell(geometry.sc) + self.write_lattice(geometry.lattice) # Write in ATOM mode self._write('[Atoms] Angs\n') diff --git a/sisl/io/openmx/omx.py b/sisl/io/openmx/omx.py index ec4149ee37..55877fc7ef 100644 --- a/sisl/io/openmx/omx.py +++ b/sisl/io/openmx/omx.py @@ -11,7 +11,7 @@ from ..sile import * from .sile import SileOpenMX -from sisl import Geometry, SphericalOrbital, Atom, SuperCell +from sisl import Geometry, SphericalOrbital, Atom, Lattice __all__ = ['omxSileOpenMX'] @@ -256,10 +256,10 @@ def read_basis(self, *args, **kwargs): Parameters ---------- output: bool, optional - whether to read supercell from output files (default to read from + whether to read lattice from output files (default to read from the input file). order: {'dat', 'omx'} - the order of which to try and read the supercell. + the order of which to try and read the lattice If `order` is present `output` is disregarded. """ order = kwargs.pop('order', ['dat', 'omx']) @@ -338,8 +338,8 @@ def decompose_basis(l): atom.append(Atom(Z, orbs, tag=d[0])) return atom - def read_supercell(self, output=False, *args, **kwargs): - """ Reads supercell + def read_lattice(self, output=False, *args, **kwargs): + """ Reads lattice One can limit the tried files to only one file by passing only a single file ending. @@ -347,10 +347,10 @@ def read_supercell(self, output=False, *args, **kwargs): Parameters ---------- output: bool, optional - whether to read supercell from output files (default to read from + whether to read lattice from output files (default to read from the input file). order: {'dat', 'omx'} - the order of which to try and read the supercell. + the order of which to try and read the lattice. If `order` is present `output` is disregarded. """ if output: @@ -358,13 +358,13 @@ def read_supercell(self, output=False, *args, **kwargs): else: order = kwargs.pop('order', ['dat', 'omx']) for f in order: - v = getattr(self, '_r_supercell_{}'.format(f.lower()))(*args, **kwargs) + v = getattr(self, '_r_lattice_{}'.format(f.lower()))(*args, **kwargs) if v is not None: return v return None - def _r_supercell_omx(self, *args, **kwargs): - """ Returns `SuperCell` object from the omx file """ + def _r_lattice_omx(self, *args, **kwargs): + """ Returns `Lattice` object from the omx file """ conv = self.get('Atoms.UnitVectors.Unit', default='Ang') if conv.upper() == 'AU': conv = units('Bohr', 'Ang') @@ -382,9 +382,9 @@ def _r_supercell_omx(self, *args, **kwargs): raise SileError('Could not find Atoms.UnitVectors in file') cell *= conv - return SuperCell(cell) + return Lattice(cell) - _r_supercell_dat = _r_supercell_omx + _r_lattice_dat = _r_lattice_omx def read_geometry(self, output=False, *args, **kwargs): """ Returns Geometry object @@ -413,7 +413,7 @@ def read_geometry(self, output=False, *args, **kwargs): def _r_geometry_omx(self, *args, **kwargs): """ Returns `Geometry` """ - sc = self.read_supercell(order=['omx']) + lattice = self.read_lattice(order=['omx']) na = self.get('Atoms.Number', default=0) conv = self.get('Atoms.SpeciesAndCoordinates.Unit', default='Ang') @@ -448,9 +448,9 @@ def find_atom(tag): if conv == 'AU': xyz *= units('Bohr', 'Ang') elif conv == 'FRAC': - xyz = np.dot(xyz, sc.cell) + xyz = np.dot(xyz, lattice.cell) - return Geometry(xyz, atoms=atom, sc=sc) + return Geometry(xyz, atoms=atom, lattice=lattice) _r_geometry_dat = _r_geometry_omx diff --git a/sisl/io/pdb.py b/sisl/io/pdb.py index 86b942be54..9bd2d871cd 100644 --- a/sisl/io/pdb.py +++ b/sisl/io/pdb.py @@ -10,8 +10,9 @@ # Import sile objects from .sile import * +from sisl.messages import deprecate_argument from sisl._internal import set_module -from sisl import Geometry, SuperCell, Atoms, Atom +from sisl import Geometry, Lattice, Atoms, Atom __all__ = ['pdbSile'] @@ -77,13 +78,14 @@ def _step_record(self, record, reread=True): return found, l @sile_fh_open() - def write_supercell(self, sc): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice): """ Writes the supercell to the contained file """ # Check that we can write to the file sile_raise_write(self) # Get parameters and append the space group and specification - args = sc.parameters() + ('P 1', 1) + args = lattice.parameters() + ('P 1', 1) #COLUMNS DATA TYPE FIELD DEFINITION #------------------------------------------------------------- @@ -106,7 +108,7 @@ def write_supercell(self, sc): #31 - 40 Real(10.6) s[n][3] Sn3 #46 - 55 Real(10.5) u[n] Un for i in range(3): - args = [i + 1] + sc.cell[i, :].tolist() + [0.] + args = [i + 1] + lattice.cell[i, :].tolist() + [0.] self._write(('SCALE{:1d} {:10.6f}{:10.6f}{:10.6f} {:10.5f}\n').format(*args)) #COLUMNS DATA TYPE FIELD DEFINITION @@ -118,11 +120,11 @@ def write_supercell(self, sc): #46 - 55 Real(10.5) t[n] Tn fmt = 'ORIGX{:1d} ' + '{:10.6f}' * 3 + '{:10.5f}\n' for i in range(3): - args = [i + 1, 0, 0, 0, sc.origin[i]] + args = [i + 1, 0, 0, 0, lattice.origin[i]] self._write(fmt.format(*args)) @sile_fh_open() - def read_supercell(self): + def read_lattice(self): """ Read supercell from the contained file """ f, line = self._step_record('CRYST1') @@ -134,7 +136,7 @@ def read_supercell(self): alpha = float(line[33:40]) beta = float(line[40:47]) gamma = float(line[47:54]) - cell = SuperCell.tocell([a, b, c, alpha, beta, gamma]) + cell = Lattice.tocell([a, b, c, alpha, beta, gamma]) f, line = self._step_record('SCALE1') if f: @@ -154,7 +156,7 @@ def read_supercell(self): if f: origin[i] = float(line[45:55]) - return SuperCell(cell, origin=origin) + return Lattice(cell, origin=origin) @sile_fh_open() def write_geometry(self, geometry): @@ -165,7 +167,7 @@ def write_geometry(self, geometry): geometry : Geometry the geometry to be written """ - self.write_supercell(geometry.sc) + self.write_lattice(geometry.lattice) # Start a model self._w_model(True) @@ -208,7 +210,7 @@ def read_geometry(self): """ Read geometry from the contained file """ # First we read in the geometry - sc = self.read_supercell() + lattice = self.read_lattice() # Try and go to the first model record in_model, l = self._step_record('MODEL') @@ -237,7 +239,7 @@ def is_end_model(line): # Create the atom list atoms = [dict(Z=Z[i], tag=tags[i]) for i in idx] - return Geometry(xyz, atoms, sc=sc) + return Geometry(xyz, atoms, lattice=lattice) def ArgumentParser(self, p=None, *args, **kwargs): """ Returns the arguments that is available for this Sile """ diff --git a/sisl/io/scaleup/ref.py b/sisl/io/scaleup/ref.py index 0590c34b37..c320c63f58 100644 --- a/sisl/io/scaleup/ref.py +++ b/sisl/io/scaleup/ref.py @@ -7,7 +7,7 @@ # Import the geometry object import sisl._array as _a -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl.unit import unit_convert import numpy as np @@ -22,7 +22,7 @@ class refSileScaleUp(SileScaleUp): """ REF file object for ScaleUp """ @sile_fh_open() - def read_supercell(self): + def read_lattice(self): """ Reads a supercell from the Sile """ # 1st line is number of supercells nsc = _a.fromiteri(map(int, self.readline().split()[:3])) @@ -31,7 +31,7 @@ def read_supercell(self): cell = _a.fromiterd(map(float, self.readline().split()[:9])) # Typically ScaleUp uses very large unit-cells # so supercells will typically be restricted to [3, 3, 3] - return SuperCell(cell * Bohr2Ang, nsc=nsc) + return Lattice(cell * Bohr2Ang, nsc=nsc) @sile_fh_open() def read_geometry(self, primary=False, **kwargs): @@ -71,7 +71,7 @@ def read_geometry(self, primary=False, **kwargs): c[2, 1] = cell[3] / 2. c[2, 2] = 1. + cell[2] cell = c * Ang2Bohr - sc = SuperCell(cell * Bohr2Ang, nsc=nsc) + lattice = Lattice(cell * Bohr2Ang, nsc=nsc) # Create list of coordinates and atoms xyz = np.empty([na * ns, 3], np.float64) @@ -87,7 +87,7 @@ def read_geometry(self, primary=False, **kwargs): atoms[ia] = species[int(line[4]) - 1] xyz[ia, :] = _a.fromiterd(map(float, line[5:8])) - return Geometry(xyz * Bohr2Ang, atoms, sc=sc) + return Geometry(xyz * Bohr2Ang, atoms, lattice=lattice) @sile_fh_open() def write_geometry(self, geometry, fmt='18.8e'): @@ -96,7 +96,7 @@ def write_geometry(self, geometry, fmt='18.8e'): sile_raise_write(self) # 1st line is number of supercells - self._write('{:5d}{:5d}{:5d}\n'.format(*geometry.sc.nsc // 2 + 1)) + self._write('{:5d}{:5d}{:5d}\n'.format(*geometry.lattice.nsc // 2 + 1)) # natoms, nspecies self._write('{:5d}{:5d}\n'.format(len(geometry), len(geometry.atoms.atom))) @@ -114,7 +114,7 @@ def write_geometry(self, geometry, fmt='18.8e'): line = '{:5d}{:5d}{:5d}{:5d}{:5d}' + f'{{:{fmt}}}' * 3 + '\n' args = [None] * 8 - for _, isc in geometry.sc: + for _, isc in geometry.lattice: if np.any(isc < 0): continue @@ -163,8 +163,8 @@ def read_geometry(self, *args, **kwargs): restart = super().read_geometry() if not ref is None: - restart.sc = SuperCell(np.dot(ref.sc.cell, restart.sc.cell.T), - nsc=restart.nsc) + restart.lattice = Lattice(np.dot(ref.lattice.cell, restart.lattice.cell.T), + nsc=restart.nsc) restart.xyz += ref.xyz return restart diff --git a/sisl/io/siesta/_help.py b/sisl/io/siesta/_help.py index b1e0bc0511..8bded97aa1 100644 --- a/sisl/io/siesta/_help.py +++ b/sisl/io/siesta/_help.py @@ -69,8 +69,8 @@ def _csr_to_siesta(geom, csr): def _csr_from_sc_off(geom, sc_off, csr): """ Internal routine to convert *any* SparseCSR matrix from sisl nsc to siesta nsc """ - nsc = geom.sc.nsc.astype(np.int32) - sc = geom.sc.__class__([1], nsc=nsc) + nsc = geom.lattice.nsc.astype(np.int32) + sc = geom.lattice.__class__([1], nsc=nsc) sc.sc_off = sc_off from_sc_off = sc.sc_index(geom.sc_off) # this transfers the local siesta csr matrix ordering to the geometry ordering diff --git a/sisl/io/siesta/binaries.py b/sisl/io/siesta/binaries.py index bcaad148c9..32a2b61657 100644 --- a/sisl/io/siesta/binaries.py +++ b/sisl/io/siesta/binaries.py @@ -19,7 +19,7 @@ from sisl.messages import info, warn, SislError import sisl._array as _a -from sisl import Geometry, Atom, Atoms, SuperCell, Grid, SparseCSR +from sisl import Geometry, Atom, Atoms, Lattice, Grid, SparseCSR from sisl import AtomicOrbital from sisl.sparse import _ncol_to_indptr from sisl.unit.siesta import unit_convert @@ -105,10 +105,10 @@ def get_copy(geom, is_copy): warn(f"{cls.__name__}.{method} has mismatched atomic coordinates, will copy geometry and use file XYZ.") geom, is_copy = get_copy(geom, is_copy) geom.xyz[:, :] = geom_b.xyz[:, :] - if not np.allclose(geom_b.sc.cell, geom.sc.cell): + if not np.allclose(geom_b.lattice.cell, geom.lattice.cell): warn(f"{cls.__name__}.{method} has non-equal lattice vectors, will copy geometry and use file lattice.") geom, is_copy = get_copy(geom, is_copy) - geom.sc.cell[:, :] = geom_b.sc.cell[:, :] + geom.lattice.cell[:, :] = geom_b.lattice.cell[:, :] if not np.array_equal(geom_b.nsc, geom.nsc): warn(f"{cls.__name__}.{method} has non-equal number of supercells, will copy geometry and use file supercell count.") geom, is_copy = get_copy(geom, is_copy) @@ -158,12 +158,12 @@ def version(self) -> int: """ The version of the file """ return _siesta.read_tshs_version(self.file) - def read_supercell(self): - """ Returns a SuperCell object from a TranSiesta file """ + def read_lattice(self): + """ Returns a Lattice object from a TranSiesta file """ n_s = _siesta.read_tshs_sizes(self.file)[3] - self._fortran_check("read_supercell", "could not read sizes.") + self._fortran_check("read_lattice", "could not read sizes.") arr = _siesta.read_tshs_cell(self.file, n_s) - self._fortran_check("read_supercell", "could not read cell.") + self._fortran_check("read_lattice", "could not read cell.") nsc = np.array(arr[0], np.int32) # We have to transpose since the data is read *as-is* # The cell in fortran files are (:, A1) @@ -172,19 +172,19 @@ def read_supercell(self): # Note that care must be taken for the different data-structures # In particular not all data needs to be transposed (sparse H and S) cell = arr[1].T * _Bohr2Ang - return SuperCell(cell, nsc=nsc) + return Lattice(cell, nsc=nsc) def read_geometry(self, geometry=None): """ Returns Geometry object from a TranSiesta file """ # Read supercell - sc = self.read_supercell() + lattice = self.read_lattice() na = _siesta.read_tshs_sizes(self.file)[1] self._fortran_check("read_geometry", "could not read sizes.") arr = _siesta.read_tshs_geom(self.file, na) self._fortran_check("read_geometry", "could not read geometry.") - # see onlysSileSiesta.read_supercell for .T + # see onlysSileSiesta.read_lattice for .T xyz = arr[0].T * _Bohr2Ang lasto = arr[1] @@ -226,7 +226,7 @@ def get_atom(atoms, orbs): atom.append(a.__class__(a.Z, [-1. for io in range(no)], mass=a.mass, tag=a.tag)) # Create and return geometry object - return Geometry(xyz, atom, sc=sc) + return Geometry(xyz, atom, lattice=lattice) def read_overlap(self, **kwargs): """ Returns the overlap matrix from the TranSiesta file """ @@ -236,7 +236,7 @@ def read_overlap(self, **kwargs): # read the sizes used... sizes = _siesta.read_tshs_sizes(self.file) self._fortran_check("read_overlap", "could not read sizes.") - # see onlysSileSiesta.read_supercell for .T + # see onlysSileSiesta.read_lattice for .T isc = _siesta.read_tshs_cell(self.file, sizes[3])[2].T self._fortran_check("read_overlap", "could not read cell.") no = sizes[2] @@ -321,7 +321,7 @@ def read_hamiltonian(self, geometry=None, **kwargs): # read the sizes used... sizes = _siesta.read_tshs_sizes(self.file) self._fortran_check("read_hamiltonian", "could not read sizes.") - # see onlysSileSiesta.read_supercell for .T + # see onlysSileSiesta.read_lattice for .T isc = _siesta.read_tshs_cell(self.file, sizes[3])[2].T self._fortran_check("read_hamiltonian", "could not read cell.") spin = sizes[0] @@ -406,7 +406,7 @@ def write_hamiltonian(self, H, **kwargs): nsc = H.geometry.nsc[:].astype(np.int32) isc = _siesta.siesta_sc_off(*nsc) - # see onlysSileSiesta.read_supercell for .T + # see onlysSileSiesta.read_lattice for .T _siesta.write_tshs_hs(self.file, nsc[0], nsc[1], nsc[2], cell.T / _Bohr2Ang, xyz.T / _Bohr2Ang, H.geometry.firsto, csr.ncol, csr.col + 1, @@ -442,8 +442,8 @@ def read_density_matrix(self, **kwargs): # We truly, have no clue, # Just generate a boxed system xyz = [[x, 0, 0] for x in range(no)] - sc = SuperCell([no, 1, 1], nsc=nsc) - geom = Geometry(xyz, Atom(1), sc=sc) + lattice = Lattice([no, 1, 1], nsc=nsc) + geom = Geometry(xyz, Atom(1), lattice=lattice) if nsc[0] != 0 and np.any(geom.nsc != nsc): # We have to update the number of supercells! @@ -505,7 +505,7 @@ def write_density_matrix(self, DM, **kwargs): # Ensure shapes (say if only 1 spin) dm.shape = (-1, len(DM.spin)) - nsc = DM.geometry.sc.nsc.astype(np.int32) + nsc = DM.geometry.lattice.nsc.astype(np.int32) _siesta.write_dm(self.file, nsc, csr.ncol, csr.col + 1, _toF(dm, np.float64)) self._fortran_check("write_density_matrix", "could not write density matrix.") @@ -537,8 +537,8 @@ def read_energy_density_matrix(self, **kwargs): # We truly, have no clue, # Just generate a boxed system xyz = [[x, 0, 0] for x in range(no)] - sc = SuperCell([no, 1, 1], nsc=nsc) - geom = Geometry(xyz, Atom(1), sc=sc) + lattice = Lattice([no, 1, 1], nsc=nsc) + geom = Geometry(xyz, Atom(1), lattice=lattice) if nsc[0] != 0 and np.any(geom.nsc != nsc): # We have to update the number of supercells! @@ -632,7 +632,7 @@ def write_density_matrices(self, DM, EDM, Ef=0., **kwargs): else: edm = EDMcsr._D[:, :EDM.S_idx] - nsc = DM.geometry.sc.nsc.astype(np.int32) + nsc = DM.geometry.lattice.nsc.astype(np.int32) _siesta.write_tsde_dm_edm(self.file, nsc, DMcsr.ncol, DMcsr.col + 1, _toF(dm, np.float64), @@ -798,7 +798,7 @@ def sc_from_xij(xij, xyz): n_s = xij.shape[1] // xij.shape[0] if n_s == 1: # easy!! - return SuperCell(xyz.max(axis=0) - xyz.min(axis=0) + 10., nsc=[1] * 3) + return Lattice(xyz.max(axis=0) - xyz.min(axis=0) + 10., nsc=[1] * 3) sc_off = _a.zerosd([n_s, 3]) mark = _a.zerosi(n_s) @@ -910,14 +910,14 @@ def get_nsc(sc_off): cell[i, cart_dir] = xyz[:, cart_dir].max() - xyz[:, cart_dir].min() + 10. i += 1 - return SuperCell(cell, nsc) + return Lattice(cell, nsc) # now we have all orbitals, ensure compatibility with passed geometry if geometry is None: atm_xij = convert_to_atom(geom_handle, xij) xyz = coord_from_xij(atm_xij) - sc = sc_from_xij(atm_xij, xyz) - geometry = Geometry(xyz, geom_handle.atoms, sc) + lattice = sc_from_xij(atm_xij, xyz) + geometry = Geometry(xyz, geom_handle.atoms, lattice) # Move coordinates into unit-cell geometry.xyz[:, :] = (geometry.fxyz % 1.) @ geometry.cell @@ -925,8 +925,8 @@ def get_nsc(sc_off): else: if geometry.n_s != xij.shape[1] // xij.shape[0]: atm_xij = convert_to_atom(geom_handle, xij) - sc = sc_from_xij(atm_xij, coord_from_xij(atm_xij)) - geometry.set_nsc(sc.nsc) + lattice = sc_from_xij(atm_xij, coord_from_xij(atm_xij)) + geometry.set_nsc(lattice.nsc) def conv(orbs, atm): if len(orbs) == len(atm): @@ -1038,8 +1038,8 @@ def _r_geometry_v1(self, **kwargs): cell, nsc, xa, _ = _siesta.read_hsx_geom1(self.file, na) - sc = SuperCell(cell.T * _Bohr2Ang, nsc=nsc) - return Geometry(xa.T * _Bohr2Ang, atoms, sc=sc) + lattice = Lattice(cell.T * _Bohr2Ang, nsc=nsc) + return Geometry(xa.T * _Bohr2Ang, atoms, lattice=lattice) def read_geometry(self, **kwargs): """ Read the geometry from the file @@ -1237,7 +1237,7 @@ class wfsxSileSiesta(SileBinSiesta): geometry : Geometry, optional a geometry contains a cell with corresponding lattice vectors used to convert k [1/Ang] -> [b] - sc : SuperCell, optional + lattice : Lattice, optional a supercell contains the lattice vectors to convert k """ @@ -1249,8 +1249,8 @@ def _setup(self, *args, **kwargs): """ super()._setup(*args, **kwargs) - # default sc - sc = None + # default lattice + lattice = None # In case the instantiation was called with wfsxSileSiesta("path", geometry=geometry) parent = kwargs.get("parent") @@ -1258,36 +1258,36 @@ def _setup(self, *args, **kwargs): geometry = None elif isinstance(parent, Geometry): geometry = parent - elif isinstance(parent, SuperCell): - sc = parent + elif isinstance(parent, Lattice): + lattice = parent else: geometry = parent.geometry geometry = kwargs.get("geometry", geometry) - if geometry is not None and sc is None: - sc = geometry.sc + if geometry is not None and lattice is None: + lattice = geometry.lattice - sc = kwargs.get("sc", sc) - if sc is None and geometry is not None: - raise ValueError(f"{self.__class__.__name__}(geometry=Geometry, sc=None) is not an allowed argument combination.") + lattice = kwargs.get("lattice", kwargs.get("sc", lattice)) + if lattice is None and geometry is not None: + raise ValueError(f"{self.__class__.__name__}(geometry=Geometry, lattice=None) is not an allowed argument combination.") if parent is None: parent = geometry if parent is None: - parent = sc + parent = lattice self._parent = parent self._geometry = geometry - self._sc = sc - if self._parent is None and self._geometry is None and self._sc is None: + self._lattice = lattice + if self._parent is None and self._geometry is None and self._lattice is None: def conv(k): if not np.allclose(k, 0.): warn(f"{self.__class__.__name__} cannot convert stored k-points from 1/Ang to reduced coordinates. " - "Please ensure parent=Hamiltonian, geometry=Geometry, or sc=SuperCell to ensure reduced k.") + "Please ensure parent=Hamiltonian, geometry=Geometry, or lattice=Lattice to ensure reduced k.") return k / _Bohr2Ang else: def conv(k): - return (k @ sc.cell.T) / (2 * np.pi * _Bohr2Ang) + return (k @ lattice.cell.T) / (2 * np.pi * _Bohr2Ang) self._convert_k = conv def _open_wfsx(self, mode, rewind=False): @@ -1554,7 +1554,7 @@ def _read_next_eigenstate(self, ispin, ik): info["spin"] = ispin # `eig` is already in eV - # See onlysSileSiesta.read_supercell to understand why we transpose `state` + # See onlysSileSiesta.read_lattice to understand why we transpose `state` return EigenstateElectron(state.T, eig, parent=self._parent, **info) def read_sizes(self): @@ -1697,13 +1697,13 @@ class _gridSileSiesta(SileBinSiesta): units (Bohr, Ry) to sisl units (Ang, eV) provided the correct extension is present. """ - def read_supercell(self, *args, **kwargs): + def read_lattice(self, *args, **kwargs): r""" Return the cell contained in the file """ cell = _siesta.read_grid_cell(self.file).T * _Bohr2Ang - self._fortran_check("read_supercell", "could not read cell.") + self._fortran_check("read_lattice", "could not read cell.") - return SuperCell(cell) + return Lattice(cell) def read_grid_size(self): r""" Query grid size information such as the grid size and number of spin components @@ -1737,7 +1737,7 @@ def read_grid(self, index=0, dtype=np.float64, *args, **kwargs): index = kwargs.get("spin", index) # Read the sizes and cell nspin, mesh = self.read_grid_size() - sc = self.read_supercell() + lattice = self.read_lattice() grid = _siesta.read_grid(self.file, nspin, mesh[0], mesh[1], mesh[2]) self._fortran_check("read_grid", "could not read grid.") @@ -1748,7 +1748,7 @@ def read_grid(self, index=0, dtype=np.float64, *args, **kwargs): # Simply create the grid (with no information) # We will overwrite the actual grid - g = Grid([1, 1, 1], sc=sc) + g = Grid([1, 1, 1], lattice=lattice) # 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 @@ -2144,7 +2144,7 @@ def write_header(self, bz, E, mu=0., obj=None): if obj is None: obj = bz.parent nspin = len(obj.spin) - cell = obj.geometry.sc.cell + cell = obj.geometry.lattice.cell na_u = obj.geometry.na no_u = obj.geometry.no xa = obj.geometry.xyz @@ -2182,7 +2182,7 @@ def write_header(self, bz, E, mu=0., obj=None): # Now write to it... self._step_counter("write_header", header=True, read=True) - # see onlysSileSiesta.read_supercell for .T + # see onlysSileSiesta.read_lattice for .T _siesta.write_gf_header(self._iu, nspin, _toF(cell.T, np.float64, 1. / _Bohr2Ang), na_u, no_u, no_u, _toF(xa.T, np.float64, 1. / _Bohr2Ang), lasto, bloch, 0, mu * _eV2Ry, _toF(k.T, np.float64), diff --git a/sisl/io/siesta/fdf.py b/sisl/io/siesta/fdf.py index 6cac1d153d..fda6546e55 100644 --- a/sisl/io/siesta/fdf.py +++ b/sisl/io/siesta/fdf.py @@ -36,7 +36,7 @@ from .struct import structSileSiesta from .xv import xvSileSiesta from sisl import Orbital, SphericalOrbital, Atom, AtomGhost, Atoms -from sisl import Geometry, SuperCell, DynamicalMatrix +from sisl import Geometry, Lattice, DynamicalMatrix from sisl.utils.cmd import default_ArgumentParser, default_namespace from sisl.utils.misc import merge_instances @@ -494,12 +494,12 @@ def print(key, value): return s @sile_fh_open() - def write_supercell(self, sc, fmt=".8f", *args, **kwargs): + def write_lattice(self, sc, fmt=".8f", *args, **kwargs): """ Writes the supercell Parameters ---------- - sc : SuperCell + sc : Lattice supercell object to write fmt : str, optional precision used to store the lattice vectors @@ -541,7 +541,7 @@ def write_geometry(self, geometry, fmt=".8f", *args, **kwargs): """ sile_raise_write(self) - self.write_supercell(geometry.sc, fmt, *args, **kwargs) + self.write_lattice(geometry.lattice, fmt, *args, **kwargs) self._write(f"\nNumberOfAtoms {geometry.na}\n") unit = kwargs.get("unit", "Ang").capitalize() @@ -634,7 +634,7 @@ def write_brillouinzone(self, bz): self._write(f" {ip} {point[0]:.5f} {point[1]:.5f} {point[2]:.5f} {name}\n") self._write("%endblock BandLines\n") - def read_supercell_nsc(self, *args, **kwargs): + def read_lattice_nsc(self, *args, **kwargs): """ Read supercell size using any method available Raises @@ -644,30 +644,30 @@ def read_supercell_nsc(self, *args, **kwargs): """ order = _listify_str(kwargs.pop("order", ["nc", "ORB_INDX"])) for f in order: - v = getattr(self, f"_r_supercell_nsc_{f.lower()}")(*args, **kwargs) + v = getattr(self, f"_r_lattice_nsc_{f.lower()}")(*args, **kwargs) if v is not None: - _track(self.read_supercell_nsc, f"found file {f}") + _track(self.read_lattice_nsc, f"found file {f}") return v warn("number of supercells could not be read from output files. Assuming molecule cell " "(no supercell connections)") return _a.onesi(3) - def _r_supercell_nsc_nc(self, *args, **kwargs): + def _r_lattice_nsc_nc(self, *args, **kwargs): f = self.dir_file(self.get("SystemLabel", default="siesta") + ".nc") - _track_file(self._r_supercell_nsc_nc, f) + _track_file(self._r_lattice_nsc_nc, f) if f.is_file(): - return ncSileSiesta(f).read_supercell_nsc() + return ncSileSiesta(f).read_lattice_nsc() return None - def _r_supercell_nsc_orb_indx(self, *args, **kwargs): + def _r_lattice_nsc_orb_indx(self, *args, **kwargs): f = self.dir_file(self.get("SystemLabel", default="siesta") + ".ORB_INDX") - _track_file(self._r_supercell_nsc_orb_indx, f) + _track_file(self._r_lattice_nsc_orb_indx, f) if f.is_file(): - return orbindxSileSiesta(f).read_supercell_nsc() + return orbindxSileSiesta(f).read_lattice_nsc() return None - def read_supercell(self, output=False, *args, **kwargs): - """ Returns SuperCell object by reading fdf or Siesta output related files. + def read_lattice(self, output=False, *args, **kwargs): + """ Returns Lattice object by reading fdf or Siesta output related files. One can limit the tried files to only one file by passing only a single file ending. @@ -685,24 +685,24 @@ def read_supercell(self, output=False, *args, **kwargs): Examples -------- >>> fdf = get_sile("RUN.fdf") - >>> fdf.read_supercell() # read from fdf - >>> fdf.read_supercell(True) # read from [XV, nc, fdf] - >>> fdf.read_supercell(order=["nc"]) # read from [nc] - >>> fdf.read_supercell(True, order=["nc"]) # read from [nc] + >>> fdf.read_lattice() # read from fdf + >>> fdf.read_lattice(True) # read from [XV, nc, fdf] + >>> fdf.read_lattice(order=["nc"]) # read from [nc] + >>> fdf.read_lattice(True, order=["nc"]) # read from [nc] """ if output: order = _listify_str(kwargs.pop("order", ["XV", "nc", "fdf"])) else: order = _listify_str(kwargs.pop("order", ["fdf"])) for f in order: - v = getattr(self, f"_r_supercell_{f.lower()}")(*args, **kwargs) + v = getattr(self, f"_r_lattice_{f.lower()}")(*args, **kwargs) if v is not None: - _track(self.read_supercell, f"found file {f}") + _track(self.read_lattice, f"found file {f}") return v return None - def _r_supercell_fdf(self, *args, **kwargs): - """ Returns `SuperCell` object from the FDF file """ + def _r_lattice_fdf(self, *args, **kwargs): + """ Returns `Lattice` object from the FDF file """ s = self.get("LatticeConstant", unit="Ang") if s is None: raise SileError("Could not find LatticeConstant in file") @@ -718,7 +718,7 @@ def _r_supercell_fdf(self, *args, **kwargs): lc = self.get("LatticeParameters") if lc: tmp = [float(k) for k in lc[0].split()[:6]] - cell = SuperCell.tocell(*tmp) + cell = Lattice.tocell(*tmp) if lc is None: # the fdf file contains neither the latticevectors or parameters raise SileError("Could not find LatticeVectors or LatticeParameters block in file") @@ -727,54 +727,53 @@ def _r_supercell_fdf(self, *args, **kwargs): # When reading from the fdf, the warning should be suppressed with warnings.catch_warnings(): warnings.simplefilter("ignore") - nsc = self.read_supercell_nsc() + nsc = self.read_lattice_nsc() - return SuperCell(cell, nsc=nsc) + return Lattice(cell, nsc=nsc) - def _r_supercell_nc(self): + def _r_lattice_nc(self): # Read supercell from <>.nc file f = self.dir_file(self.get("SystemLabel", default="siesta") + ".nc") - _track_file(self._r_supercell_nc, f) + _track_file(self._r_lattice_nc, f) if f.is_file(): - return ncSileSiesta(f).read_supercell() + return ncSileSiesta(f).read_lattice() return None - def _r_supercell_xv(self, *args, **kwargs): - """ Returns `SuperCell` object from the XV file """ + def _r_lattice_xv(self, *args, **kwargs): + """ Returns `Lattice` object from the XV file """ f = self.dir_file(self.get("SystemLabel", default="siesta") + ".XV") - _track_file(self._r_supercell_xv, f) + _track_file(self._r_lattice_xv, f) if f.is_file(): - nsc = self.read_supercell_nsc() - sc = xvSileSiesta(f).read_supercell() - sc.set_nsc(nsc) - return sc + nsc = self.read_lattice_nsc() + lattice = xvSileSiesta(f).read_lattice() + lattice.set_nsc(nsc) + return lattice return None - def _r_supercell_struct(self, *args, **kwargs): - """ Returns `SuperCell` object from the STRUCT files """ - sc = None + def _r_lattice_struct(self, *args, **kwargs): + """ Returns `Lattice` object from the STRUCT files """ for end in ["STRUCT_NEXT_ITER", "STRUCT_OUT", "STRUCT_IN"]: f = self.dir_file(self.get("SystemLabel", default="siesta") + f".{end}") - _track_file(self._r_supercell_struct, f) + _track_file(self._r_lattice_struct, f) if f.is_file(): - nsc = self.read_supercell_nsc() - sc = structSileSiesta(f).read_supercell() - sc.set_nsc(nsc) - break - return sc + nsc = self.read_lattice_nsc() + lattice = structSileSiesta(f).read_lattice() + lattice.set_nsc(nsc) + return lattice + return None - def _r_supercell_tshs(self, *args, **kwargs): + def _r_lattice_tshs(self, *args, **kwargs): f = self.dir_file(self.get("SystemLabel", default="siesta") + ".TSHS") - _track_file(self._r_supercell_tshs, f) + _track_file(self._r_lattice_tshs, f) if f.is_file(): - return tshsSileSiesta(f).read_supercell() + return tshsSileSiesta(f).read_lattice() return None - def _r_supercell_onlys(self, *args, **kwargs): + def _r_lattice_onlys(self, *args, **kwargs): f = self.dir_file(self.get("SystemLabel", default="siesta") + ".onlyS") - _track_file(self._r_supercell_onlys, f) + _track_file(self._r_lattice_onlys, f) if f.is_file(): - return onlysSileSiesta(f).read_supercell() + return onlysSileSiesta(f).read_lattice() return None def read_force(self, *args, **kwargs): @@ -1077,16 +1076,16 @@ def _dynamical_matrix_from_fc(self, geom, FC, FC_atoms, *args, **kwargs): # We have an actual supercell. Lets try and fix it. # First lets recreate the smallest geometry - sc = geom.sc.cell.copy() - sc[0, :] /= supercell[0] - sc[1, :] /= supercell[1] - sc[2, :] /= supercell[2] + cell = geom.lattice.cell.copy() + cell[0, :] /= supercell[0] + cell[1, :] /= supercell[1] + cell[2, :] /= supercell[2] # Ensure nsc is at least an odd number, later down we will symmetrize the FC matrix nsc = supercell + (supercell + 1) % 2 if R > 0: # Correct for the optional radius - sc_norm = fnorm(sc) + sc_norm = fnorm(cell) # R is already "twice" the "orbital" range nsc_R = 1 + 2 * np.ceil(R / sc_norm).astype(np.int32) for i in range(3): @@ -1094,12 +1093,12 @@ def _dynamical_matrix_from_fc(self, geom, FC, FC_atoms, *args, **kwargs): del nsc_R # Construct the minimal unit-cell geometry - sc = SuperCell(sc, nsc=nsc) + lattice = Lattice(cell, nsc=nsc) # TODO check that the coordinates are in the cell - geom_small = Geometry(geom.xyz[FC_atoms], geom.atoms[FC_atoms], sc) + geom_small = Geometry(geom.xyz[FC_atoms], geom.atoms[FC_atoms], lattice) # Convert the big geometry's coordinates to fractional coordinates of the small unit-cell. - isc_xyz = (geom.xyz.dot(geom_small.sc.icell.T) - + isc_xyz = (geom.xyz.dot(geom_small.lattice.icell.T) - np.tile(geom_small.fxyz, (np.product(supercell), 1))) axis_tiling = [] @@ -1251,7 +1250,7 @@ def _dynamical_matrix_from_fc(self, geom, FC, FC_atoms, *args, **kwargs): # When x, y, z are negative we simply look-up from the back of the array # which is exactly what is required - isc_off = geom.sc.isc_off + isc_off = geom.lattice.isc_off nxyz, na = geom.no, geom.na dist = geom.rij @@ -1340,7 +1339,7 @@ def _r_geometry_xv(self, *args, **kwargs): for atom, _ in geom.atoms.iter(True): geom.atoms.replace(atom, basis[atom.Z-1]) geom.reduce() - nsc = self.read_supercell_nsc() + nsc = self.read_lattice_nsc() geom.set_nsc(nsc) return geom @@ -1361,7 +1360,7 @@ def _r_geometry_struct(self, *args, **kwargs): for atom, _ in geom.atoms.iter(True): geom.atoms.replace(atom, basis[atom.Z-1]) geom.reduce() - nsc = self.read_supercell_nsc() + nsc = self.read_lattice_nsc() geom.set_nsc(nsc) break return geom @@ -1397,7 +1396,7 @@ def _r_geometry_fdf(self, *args, **kwargs): NOTE: Interaction range of the Atoms are currently not read. """ - sc = self.read_supercell(order="fdf") + lattice = self.read_lattice(order="fdf") # No fractional coordinates is_frac = False @@ -1457,7 +1456,7 @@ def _r_geometry_fdf(self, *args, **kwargs): xyz[ia, :] = [float(k) for k in l[:3]] species[ia] = int(l[3]) - 1 if is_frac: - xyz = np.dot(xyz, sc.cell) + xyz = np.dot(xyz, lattice.cell) xyz *= s # Read the block (not strictly needed, if so we simply set all atoms to H) @@ -1474,12 +1473,12 @@ def _r_geometry_fdf(self, *args, **kwargs): if isinstance(origin, str): opt = origin if opt.startswith("cop"): - origin = sc.cell.sum(0) * 0.5 - np.average(xyz, 0) + origin = lattice.cell.sum(0) * 0.5 - np.average(xyz, 0) elif opt.startswith("com"): # TODO for ghost atoms its mass should not be used w = atoms.mass w /= w.sum() - origin = sc.cell.sum(0) * 0.5 - np.average(xyz, 0, weights=w) + origin = lattice.cell.sum(0) * 0.5 - np.average(xyz, 0, weights=w) elif opt.startswith("min"): origin = - np.amin(xyz, 0) if len(opt) > 4: @@ -1499,10 +1498,10 @@ def _r_geometry_fdf(self, *args, **kwargs): # create geometry xyz += origin - geom = Geometry(xyz, atoms, sc=sc) + geom = Geometry(xyz, atoms, lattice=lattice) # and finally check for supercell constructs - supercell = self.get("SuperCell") + supercell = self.get("Lattice") if supercell is not None: # we need to expand # check that we are only dealing with an orthogonal supercell @@ -1514,7 +1513,7 @@ def _r_geometry_fdf(self, *args, **kwargs): diag = np.diag(supercell) if not np.allclose(supercell - np.diag(diag), 0): - raise SileError("SuperCell input is not diagonal, currently not implemented in sisl") + raise SileError("Lattice input is not diagonal, currently not implemented in sisl") # now tile it for axis, nt in enumerate(diag): diff --git a/sisl/io/siesta/kp.py b/sisl/io/siesta/kp.py index 5adeb2a97f..67f2de795a 100644 --- a/sisl/io/siesta/kp.py +++ b/sisl/io/siesta/kp.py @@ -6,6 +6,7 @@ from ..sile import add_sile, sile_fh_open, sile_raise_write from .sile import SileSiesta +from sisl.messages import deprecate_argument from sisl._internal import set_module from sisl.unit.siesta import unit_convert @@ -20,12 +21,13 @@ class kpSileSiesta(SileSiesta): """ k-points file in 1/Bohr units """ @sile_fh_open() - def read_data(self, sc=None): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def read_data(self, lattice=None): """ Returns K-points from the file (note that these are in reciprocal units) Parameters ---------- - sc : SuperCellChild, optional + lattice : LatticeChild, optional if supplied the returned k-points will be in reduced coordinates Returns @@ -45,9 +47,9 @@ def read_data(self, sc=None): # Correct units to 1/Ang k /= Bohr2Ang - if sc is None: + if lattice is None: return k, w - return np.dot(k, sc.cell.T / (2 * np.pi)), w + return np.dot(k, lattice.cell.T / (2 * np.pi)), w @sile_fh_open() def write_data(self, k, weight, fmt='.9e'): @@ -72,22 +74,23 @@ def write_data(self, k, weight, fmt='.9e'): self._write(_fmt.format(i + 1, kk[0], kk[1], kk[2], w)) @sile_fh_open() - def read_brillouinzone(self, sc): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def read_brillouinzone(self, lattice): """ Returns K-points from the file (note that these are in reciprocal units) Parameters ---------- - sc : SuperCellChild + lattice : LatticeChild required supercell for the BrillouinZone object Returns ------- bz : BrillouinZone """ - k, w = self.read_data(sc) + k, w = self.read_data(lattice) from sisl.physics.brillouinzone import BrillouinZone - bz = BrillouinZone(sc) + bz = BrillouinZone(lattice) bz._k = k bz._w = w return bz @@ -137,12 +140,13 @@ def read_data(self): return k, w @sile_fh_open() - def read_brillouinzone(self, sc): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def read_brillouinzone(self, lattice): """ Returns K-points from the file Parameters ---------- - sc : SuperCellChild + lattice : LatticeChild required supercell for the BrillouinZone object Returns @@ -152,7 +156,7 @@ def read_brillouinzone(self, sc): k, w = self.read_data() from sisl.physics.brillouinzone import BrillouinZone - bz = BrillouinZone(sc) + bz = BrillouinZone(lattice) bz._k = k bz._w = w return bz diff --git a/sisl/io/siesta/orb_indx.py b/sisl/io/siesta/orb_indx.py index ae374f457f..5a6970955b 100644 --- a/sisl/io/siesta/orb_indx.py +++ b/sisl/io/siesta/orb_indx.py @@ -22,7 +22,7 @@ class orbindxSileSiesta(SileSiesta): """ Orbital information file """ @sile_fh_open() - def read_supercell_nsc(self): + def read_lattice_nsc(self): """ Reads the supercell number of supercell information """ # First line contains no no_s line = self.readline().split() diff --git a/sisl/io/siesta/out.py b/sisl/io/siesta/out.py index 8a0170b2f7..62c9c2816d 100644 --- a/sisl/io/siesta/out.py +++ b/sisl/io/siesta/out.py @@ -11,7 +11,7 @@ from sisl._common import Opt from sisl._internal import set_module import sisl._array as _a -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl.utils import PropertyDict from sisl.utils.cmd import * from sisl.unit.siesta import unit_convert @@ -116,13 +116,13 @@ def read_basis(self): return [Atom(**atoms[tag]) for tag in order] - def _r_supercell_outcell(self): + def _r_lattice_outcell(self): """ Wrapper for reading the unit-cell from the outcoor block """ # Read until outcell is found found, line = self.step_to("outcell: Unit cell vectors") if not found: - raise ValueError(f"{self.__class__.__name__}._r_supercell_outcell did not find outcell key") + raise ValueError(f"{self.__class__.__name__}._r_lattice_outcell did not find outcell key") Ang = 'Ang' in line @@ -139,7 +139,7 @@ def _r_supercell_outcell(self): if not Ang: cell *= Bohr2Ang - return SuperCell(cell) + return Lattice(cell) def _r_geometry_outcoor(self, line, atoms=None): """ Wrapper for reading the geometry as in the outcoor output """ @@ -168,7 +168,7 @@ def _r_geometry_outcoor(self, line, atoms=None): # Retrieve the unit-cell (but do not skip file-descriptor position) # This is because the current unit-cell is not always written. pos = self.fh.tell() - cell = self._r_supercell_outcell() + cell = self._r_lattice_outcell() if is_final and self.fh.tell() < pos: # we have wrapped around the file self.fh.seek(pos, os.SEEK_SET) @@ -185,7 +185,7 @@ def _r_geometry_outcoor(self, line, atoms=None): elif not Ang: xyz *= Bohr2Ang - return Geometry(xyz, atoms, sc=cell) + return Geometry(xyz, atoms, lattice=cell) def _r_geometry_atomic(self, line, atoms=None): """ Wrapper for reading the geometry as in the outcoor output """ @@ -207,7 +207,7 @@ def _r_geometry_atomic(self, line, atoms=None): # Retrieve the unit-cell (but do not skip file-descriptor position) # This is because the current unit-cell is not always written. pos = self.fh.tell() - cell = self._r_supercell_outcell() + cell = self._r_lattice_outcell() self.fh.seek(pos, os.SEEK_SET) # Convert xyz @@ -215,7 +215,7 @@ def _r_geometry_atomic(self, line, atoms=None): if not Ang: xyz *= Bohr2Ang - return Geometry(xyz, atoms, sc=cell) + return Geometry(xyz, atoms, lattice=cell) @sile_fh_open() def read_geometry(self, last=True, all=False): diff --git a/sisl/io/siesta/siesta_grid.py b/sisl/io/siesta/siesta_grid.py index cd2fe34e93..dc05ae1890 100644 --- a/sisl/io/siesta/siesta_grid.py +++ b/sisl/io/siesta/siesta_grid.py @@ -9,8 +9,8 @@ from ..sile import add_sile, sile_raise_write, SileError from sisl._internal import set_module -from sisl.messages import info -from sisl import SuperCell, Grid +from sisl.messages import info, deprecate_argument +from sisl import Lattice, Grid from sisl.unit.siesta import unit_convert @@ -28,17 +28,18 @@ class gridncSileSiesta(SileCDFSiesta): The grid sile will automatically convert the units from Siesta units (Bohr, Ry) to sisl units (Ang, eV) provided the correct extension is present. """ - def read_supercell(self): - """ Returns a SuperCell object from a Siesta.grid.nc file + def read_lattice(self): + """ Returns a Lattice object from a Siesta.grid.nc file """ cell = np.array(self._value('cell'), np.float64) # Yes, this is ugly, I really should implement my unit-conversion tool cell *= Bohr2Ang cell.shape = (3, 3) - return SuperCell(cell) + return Lattice(cell) - def write_supercell(self, sc): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice): """ Write a supercell to the grid.nc file """ sile_raise_write(self) @@ -49,7 +50,7 @@ def write_supercell(self, sc): v = self._crt_var(self, 'cell', 'f8', ('abc', 'xyz')) v.info = 'Unit cell' v.unit = 'Bohr' - v[:, :] = sc.cell[:, :] / Bohr2Ang + v[:, :] = lattice.cell[:, :] / Bohr2Ang def read_grid(self, index=0, name='gridfunc', *args, **kwargs): """ Reads a grid in the current Siesta.grid.nc file @@ -107,7 +108,7 @@ def read_grid(self, index=0, name='gridfunc', *args, **kwargs): show_info = False # Swap as we swap back in the end - sc = self.read_supercell().swapaxes(0, 2) + lattice = self.read_lattice().swapaxes(0, 2) # Create the grid nx = len(self._dimension('n1')) @@ -120,7 +121,7 @@ def read_grid(self, index=0, name='gridfunc', *args, **kwargs): v = self._variable(name) # Create the grid, Siesta uses periodic, always - grid = Grid([nz, ny, nx], bc=Grid.PERIODIC, sc=sc, dtype=v.dtype, + grid = Grid([nz, ny, nx], bc=Grid.PERIODIC, lattice=lattice, dtype=v.dtype, geometry=kwargs.get("geometry", None)) if v.ndim == 3: @@ -144,7 +145,7 @@ def write_grid(self, grid, spin=0, nspin=None, **kwargs): # Default to *index* variable spin = kwargs.get('index', spin) - self.write_supercell(grid.sc) + self.write_lattice(grid.lattice) if nspin is not None: self._crt_dim(self, 'spin', nspin) diff --git a/sisl/io/siesta/siesta_nc.py b/sisl/io/siesta/siesta_nc.py index aae4558d5d..ccabe5cb9d 100644 --- a/sisl/io/siesta/siesta_nc.py +++ b/sisl/io/siesta/siesta_nc.py @@ -11,7 +11,7 @@ from sisl._internal import set_module from sisl._array import aranged, array_arange from sisl.unit.siesta import unit_convert -from sisl import Geometry, Atom, AtomGhost, Atoms, SuperCell, Grid, SphericalOrbital +from sisl import Geometry, Atom, AtomGhost, Atoms, Lattice, Grid, SphericalOrbital from sisl.sparse import _ncol_to_indptr from sisl.physics import SparseOrbitalBZ from sisl.physics import DensityMatrix, EnergyDensityMatrix @@ -37,21 +37,21 @@ class ncSileSiesta(SileCDFSiesta): """ Generic NetCDF output file containing a large variety of information """ @lru_cache(maxsize=1) - def read_supercell_nsc(self): + def read_lattice_nsc(self): """ Returns number of supercell connections """ return np.array(self._value('nsc'), np.int32) @lru_cache(maxsize=1) - def read_supercell(self): - """ Returns a SuperCell object from a Siesta.nc file """ + def read_lattice(self): + """ Returns a Lattice object from a Siesta.nc file """ cell = np.array(self._value('cell'), np.float64) # Yes, this is ugly, I really should implement my unit-conversion tool cell *= Bohr2Ang cell.shape = (3, 3) - nsc = self.read_supercell_nsc() + nsc = self.read_lattice_nsc() - return SuperCell(cell, nsc=nsc) + return Lattice(cell, nsc=nsc) @lru_cache(maxsize=1) def read_basis(self): @@ -136,7 +136,7 @@ def read_geometry(self): """ Returns Geometry object from a Siesta.nc file """ # Read supercell - sc = self.read_supercell() + lattice = self.read_lattice() xyz = np.array(self._value('xa'), np.float64) xyz.shape = (-1, 3) @@ -151,7 +151,7 @@ def read_geometry(self): xyz *= Bohr2Ang # Create and return geometry object - geom = Geometry(xyz, atom, sc=sc) + geom = Geometry(xyz, atom, lattice=lattice) return geom @lru_cache(maxsize=1) diff --git a/sisl/io/siesta/struct.py b/sisl/io/siesta/struct.py index 934d87f86e..223c1b1e99 100644 --- a/sisl/io/siesta/struct.py +++ b/sisl/io/siesta/struct.py @@ -7,7 +7,7 @@ from .sile import SileSiesta from sisl._internal import set_module -from sisl import Geometry, Atom, AtomGhost, AtomUnknown, Atoms, SuperCell +from sisl import Geometry, Atom, AtomGhost, AtomUnknown, Atoms, Lattice from sisl.unit.siesta import unit_convert @@ -52,14 +52,14 @@ def write_geometry(self, geometry, fmt='.9f'): self._write(fmt_str.format(ips + 1, a.Z, *fxyz[ia])) @sile_fh_open() - def read_supercell(self): - """ Returns `SuperCell` object from the STRUCT file """ + def read_lattice(self): + """ Returns `Lattice` object from the STRUCT file """ cell = np.empty([3, 3], np.float64) for i in range(3): cell[i, :] = list(map(float, self.readline().split()[:3])) - return SuperCell(cell) + return Lattice(cell) @sile_fh_open() def read_geometry(self, species_Z=False): @@ -75,7 +75,7 @@ def read_geometry(self, species_Z=False): ------- Geometry """ - sc = self.read_supercell() + lattice = self.read_lattice() # Read number of atoms na = int(self.readline()) @@ -91,7 +91,7 @@ def read_geometry(self, species_Z=False): atms[ia] = Atom(int(line[1])) xyz[ia, :] = line[2:5] - xyz = xyz @ sc.cell + xyz = xyz @ lattice.cell # Ensure correct sorting max_s = sp.max() @@ -106,7 +106,7 @@ def read_geometry(self, species_Z=False): else: atms2[idx] = atms[idx[0]] - return Geometry(xyz, atms2.reduce(), sc=sc) + return Geometry(xyz, atms2.reduce(), lattice=lattice) def ArgumentParser(self, p=None, *args, **kwargs): """ Returns the arguments that is available for this Sile """ diff --git a/sisl/io/siesta/tests/test_ani.py b/sisl/io/siesta/tests/test_ani.py index 26d77f7a01..a248f2c5cd 100644 --- a/sisl/io/siesta/tests/test_ani.py +++ b/sisl/io/siesta/tests/test_ani.py @@ -69,4 +69,4 @@ def test_ani(sisl_tmp): g = a.read_geometry(start=1, stop=3, step=2, all=True) assert g[0].na == 2 and len(g) == 1 - g = a.read_geometry(sc=None, atoms=None) + g = a.read_geometry(lattice=None, atoms=None) diff --git a/sisl/io/siesta/tests/test_fdf.py b/sisl/io/siesta/tests/test_fdf.py index 7555fb6670..d5cc527fa3 100644 --- a/sisl/io/siesta/tests/test_fdf.py +++ b/sisl/io/siesta/tests/test_fdf.py @@ -34,7 +34,7 @@ def test_fdf1(sisl_tmp, sisl_system): assert fdf.get('LatticeConstant') > 0. assert fdf.get('LatticeConstant') > 0. - fdf.read_supercell() + fdf.read_lattice() fdf.read_geometry() @@ -66,7 +66,7 @@ def test_fdf_units(sisl_tmp, sisl_system): assert g.atoms[ia].tag == g2.atoms[ia].tag -def test_supercell(sisl_tmp): +def test_lattice(sisl_tmp): f = sisl_tmp('file.fdf', _dir) lines = [ 'Latticeconstant 1. Ang', @@ -80,8 +80,8 @@ def test_supercell(sisl_tmp): fh.write('\n'.join(lines)) cell = np.array([[1.]*3, [0, 0, 1], [1, 0, 1]]) - sc = fdfSileSiesta(f).read_supercell() - assert np.allclose(sc.cell, cell) + lattice = fdfSileSiesta(f).read_lattice() + assert np.allclose(lattice.cell, cell) lines = [ 'Latticeconstant 1. Bohr', @@ -94,8 +94,8 @@ def test_supercell(sisl_tmp): with open(f, 'w') as fh: fh.write('\n'.join(lines)) - sc = fdfSileSiesta(f).read_supercell() - assert np.allclose(sc.cell, cell * unit_convert('Bohr', 'Ang')) + lattice = fdfSileSiesta(f).read_lattice() + assert np.allclose(lattice.cell, cell * unit_convert('Bohr', 'Ang')) cell = np.diag([2.] * 3) lines = [ @@ -107,11 +107,11 @@ def test_supercell(sisl_tmp): with open(f, 'w') as fh: fh.write('\n'.join(lines)) - sc = fdfSileSiesta(f).read_supercell() - assert np.allclose(sc.cell, cell) + lattice = fdfSileSiesta(f).read_lattice() + assert np.allclose(lattice.cell, cell) -def test_supercell_fail(sisl_tmp): +def test_lattice_fail(sisl_tmp): f = sisl_tmp('file.fdf', _dir) lines = [ '%block Latticevectors', @@ -123,7 +123,7 @@ def test_supercell_fail(sisl_tmp): with open(f, 'w') as fh: fh.write('\n'.join(lines)) with pytest.raises(SileError): - fdfSileSiesta(f).read_supercell() + fdfSileSiesta(f).read_lattice() def test_geometry(sisl_tmp): @@ -292,9 +292,9 @@ def test_xv_preference(sisl_tmp): g.xyz[0, 0] += 1. g.write(sisl_tmp('siesta.XV', _dir)) - sc = fdfSileSiesta(sisl_tmp('file.fdf', _dir)).read_supercell(True) + lattice = fdfSileSiesta(sisl_tmp('file.fdf', _dir)).read_lattice(True) g2 = fdfSileSiesta(sisl_tmp('file.fdf', _dir)).read_geometry(True) - assert np.allclose(sc.cell, g.cell) + assert np.allclose(lattice.cell, g.cell) assert np.allclose(g.cell, g2.cell) assert np.allclose(g.xyz, g2.xyz) @@ -368,16 +368,16 @@ def test_dry_read(sisl_tmp): read_methods = set(m for m in dir(fdf) if m.startswith("read_")) output = dict(output=True) kwargs = { - "supercell": output, + "lattice": output, "geometry": output, "grid": dict(name="rho"), } with pytest.warns(SislWarning): - assert np.allclose(fdf.read_supercell_nsc(), (1, 1, 1)) - read_methods.remove("read_supercell_nsc") + assert np.allclose(fdf.read_lattice_nsc(), (1, 1, 1)) + read_methods.remove("read_lattice_nsc") - geom_methods = set(f"read_{x}" for x in ("basis", "supercell", "geometry")) + geom_methods = set(f"read_{x}" for x in ("basis", "lattice", "geometry")) read_methods -= geom_methods for methodname in read_methods: diff --git a/sisl/io/siesta/tests/test_grid.py b/sisl/io/siesta/tests/test_grid.py index 09acababd7..942cbd533b 100644 --- a/sisl/io/siesta/tests/test_grid.py +++ b/sisl/io/siesta/tests/test_grid.py @@ -18,7 +18,7 @@ def test_si_pdos_kgrid_grid(sisl_files): def test_si_pdos_kgrid_grid_cell(sisl_files): si = sisl.get_sile(sisl_files(_dir, 'si_pdos_kgrid.VT')) - si.read_supercell() + si.read_lattice() def test_si_pdos_kgrid_grid_fractions(sisl_files): diff --git a/sisl/io/siesta/tests/test_hsx.py b/sisl/io/siesta/tests/test_hsx.py index 6b927c9436..b8dcaffaf8 100644 --- a/sisl/io/siesta/tests/test_hsx.py +++ b/sisl/io/siesta/tests/test_hsx.py @@ -124,6 +124,6 @@ def test_si_pdos_kgrid_hsx_1_same_tshs(sisl_files, sisl_tmp): gx = HSX.geometry gt = TSHS.geometry - assert np.allclose(gx.sc.cell, gt.sc.cell) + assert np.allclose(gx.lattice.cell, gt.lattice.cell) assert np.allclose(gx.xyz, gt.xyz) assert np.allclose(gx.nsc, gt.nsc) diff --git a/sisl/io/siesta/tests/test_kp.py b/sisl/io/siesta/tests/test_kp.py index de4a2f4a3f..9bdeac7d2c 100644 --- a/sisl/io/siesta/tests/test_kp.py +++ b/sisl/io/siesta/tests/test_kp.py @@ -26,7 +26,7 @@ def test_kp_read_write(sisl_tmp): assert np.allclose(kpoints, bz.tocartesian(bz.k)) assert np.allclose(weights, bz.weight) - bz2 = kpSileSiesta(f).read_brillouinzone(g.sc) + bz2 = kpSileSiesta(f).read_brillouinzone(g.lattice) assert np.allclose(bz2.k, bz.k) assert np.allclose(bz2.weight, bz.weight) @@ -41,6 +41,6 @@ def test_rkp_read_write(sisl_tmp): assert np.allclose(kpoints, bz.k) assert np.allclose(weights, bz.weight) - bz2 = rkpSileSiesta(f).read_brillouinzone(g.sc) + bz2 = rkpSileSiesta(f).read_brillouinzone(g.lattice) assert np.allclose(bz2.k, bz.k) assert np.allclose(bz2.weight, bz.weight) diff --git a/sisl/io/siesta/tests/test_orb_indx.py b/sisl/io/siesta/tests/test_orb_indx.py index 63f9e1f6bd..dcd6611381 100644 --- a/sisl/io/siesta/tests/test_orb_indx.py +++ b/sisl/io/siesta/tests/test_orb_indx.py @@ -13,7 +13,7 @@ def test_si_pdos_kgrid_orb_indx(sisl_files): f = sisl_files(_dir, 'si_pdos_kgrid.ORB_INDX') - nsc = orbindxSileSiesta(f).read_supercell_nsc() + nsc = orbindxSileSiesta(f).read_lattice_nsc() assert np.all(nsc > 1) atoms = orbindxSileSiesta(f).read_basis() @@ -25,7 +25,7 @@ def test_si_pdos_kgrid_orb_indx(sisl_files): def test_sih_orb_indx(sisl_files): f = sisl_files(_dir, 'sih.ORB_INDX') - nsc = orbindxSileSiesta(f).read_supercell_nsc() + nsc = orbindxSileSiesta(f).read_lattice_nsc() assert np.all(nsc == 1) atoms = orbindxSileSiesta(f).read_basis() diff --git a/sisl/io/siesta/tests/test_struct.py b/sisl/io/siesta/tests/test_struct.py index 2864b7d945..09abfc16df 100644 --- a/sisl/io/siesta/tests/test_struct.py +++ b/sisl/io/siesta/tests/test_struct.py @@ -63,7 +63,7 @@ def test_si_pdos_kgrid_struct_out(sisl_files): assert np.allclose(struct_geom.cell, fdf_geom.cell) assert np.allclose(struct_geom.xyz, fdf_geom.xyz) - struct_sc = struct.read_supercell() - fdf_sc = fdf.read_supercell(order='STRUCT') + struct_sc = struct.read_lattice() + fdf_sc = fdf.read_lattice(order='STRUCT') assert np.allclose(struct_sc.cell, fdf_sc.cell) diff --git a/sisl/io/siesta/tests/test_tshs.py b/sisl/io/siesta/tests/test_tshs.py index cc5d3aa5ca..fe955b9cae 100644 --- a/sisl/io/siesta/tests/test_tshs.py +++ b/sisl/io/siesta/tests/test_tshs.py @@ -80,9 +80,9 @@ def test_tshs_soc_pt2_xx(sisl_files, sisl_tmp): def test_tshs_soc_pt2_xx_pdos(sisl_files): fdf = sisl.get_sile(sisl_files(_dir, 'SOC_Pt2_xx.fdf'), base=sisl_files(_dir)) - sc = fdf.read_supercell(order='TSHS') + sc = fdf.read_lattice(order='TSHS') HS = fdf.read_hamiltonian() - assert np.allclose(sc.cell, HS.geometry.sc.cell) + assert np.allclose(sc.cell, HS.geometry.lattice.cell) HS.eigenstate().PDOS(np.linspace(-2, 2, 400)) @@ -97,7 +97,7 @@ def test_tshs_warn(sisl_files): # check cell geom = si.read_geometry() - geom.sc.cell[:, :] = 1. + geom.lattice.cell[:, :] = 1. with pytest.warns(sisl.SislWarning, match='lattice vectors'): si.read_hamiltonian(geometry=geom) @@ -174,8 +174,8 @@ def test_tshs_spin_orbit_tshs2nc2tshs(sisl_tmp): "SystemLabel tmp1" ]) fdf = sisl.get_sile(fdf_file) - assert np.allclose(fdf.read_supercell(order='nc').cell, - fdf.read_supercell(order='TSHS').cell) + assert np.allclose(fdf.read_lattice(order='nc').cell, + fdf.read_lattice(order='TSHS').cell) assert H1._csr.spsame(H2._csr) assert np.allclose(H1._csr._D, H2._csr._D) assert H1._csr.spsame(H3._csr) diff --git a/sisl/io/siesta/transiesta_grid.py b/sisl/io/siesta/transiesta_grid.py index 2733bf0b1b..de45ea47f8 100644 --- a/sisl/io/siesta/transiesta_grid.py +++ b/sisl/io/siesta/transiesta_grid.py @@ -33,7 +33,7 @@ class tsvncSileSiesta(gridncSileSiesta): def read_grid(self, *args, **kwargs): """ Reads the TranSiesta potential input grid """ - sc = self.read_supercell().swapaxes(0, 2) + lattice = self.read_lattice().swapaxes(0, 2) # Create the grid na = len(self._dimension('a')) @@ -43,7 +43,7 @@ def read_grid(self, *args, **kwargs): v = self._variable('V') # Create the grid, Siesta uses periodic, always - grid = Grid([nc, nb, na], bc=Grid.PERIODIC, sc=sc, dtype=v.dtype) + grid = Grid([nc, nb, na], bc=Grid.PERIODIC, lattice=lattice, dtype=v.dtype) grid.grid[:, :, :] = v[:, :, :] * _Ry2eV @@ -55,7 +55,7 @@ def write_grid(self, grid): """ Write the Poisson solution to the TSV.nc file """ sile_raise_write(self) - self.write_supercell(grid.sc) + self.write_lattice(grid.lattice) self._crt_dim(self, 'one', 1) self._crt_dim(self, 'a', grid.shape[0]) diff --git a/sisl/io/siesta/xv.py b/sisl/io/siesta/xv.py index febc29f798..091620a56f 100644 --- a/sisl/io/siesta/xv.py +++ b/sisl/io/siesta/xv.py @@ -7,7 +7,7 @@ from .sile import SileSiesta from sisl._internal import set_module -from sisl import Geometry, Atom, AtomGhost, AtomUnknown, Atoms, SuperCell +from sisl import Geometry, Atom, AtomGhost, AtomUnknown, Atoms, Lattice from sisl.unit.siesta import unit_convert __all__ = ['xvSileSiesta'] @@ -66,15 +66,15 @@ def write_geometry(self, geometry, fmt='.9f', velocity=None): self._write(fmt_str.format(ips + 1, a.Z, *tmp)) @sile_fh_open() - def read_supercell(self): - """ Returns `SuperCell` object from the XV file """ + def read_lattice(self): + """ Returns `Lattice` object from the XV file """ cell = np.empty([3, 3], np.float64) for i in range(3): cell[i, :] = list(map(float, self.readline().split()[:3])) cell *= Bohr2Ang - return SuperCell(cell) + return Lattice(cell) @sile_fh_open() def read_geometry(self, velocity=False, species_Z=False): @@ -93,7 +93,7 @@ def read_geometry(self, velocity=False, species_Z=False): Geometry velocity : only if `velocity` is true. """ - sc = self.read_supercell() + lattice = self.read_lattice() # Read number of atoms na = int(self.readline()) @@ -127,7 +127,7 @@ def read_geometry(self, velocity=False, species_Z=False): else: atms2[idx] = atms[idx[0]] - geom = Geometry(xyz, atms2.reduce(), sc=sc) + geom = Geometry(xyz, atms2.reduce(), lattice=lattice) if velocity: return geom, vel return geom @@ -140,7 +140,7 @@ def read_velocity(self): ------- velocity : """ - self.read_supercell() + self.read_lattice() na = int(self.readline()) vel = np.empty([na, 3], np.float64) for ia in range(na): diff --git a/sisl/io/sile.py b/sisl/io/sile.py index 113c3fff51..270ee0d3ba 100644 --- a/sisl/io/sile.py +++ b/sisl/io/sile.py @@ -9,7 +9,7 @@ from pathlib import Path from sisl._internal import set_module -from sisl.messages import SislWarning, SislInfo +from sisl.messages import SislWarning, SislInfo, deprecate from sisl.utils.misc import str_spec from ._help import * @@ -477,6 +477,12 @@ def __getattr__(self, name): """ Override to check the handle """ if name == 'fh': raise AttributeError(f"The filehandle for {self.file} has not been opened yet...") + if name == "read_supercell" and hasattr(self, "read_lattice"): + deprecate(f"{self.__class__.__name__}.read_supercell is deprecated in favor of read_lattice", "0.15") + return getattr(self, "read_lattice") + if name == "write_supercell" and hasattr(self, "write_lattice"): + deprecate(f"{self.__class__.__name__}.write_supercell is deprecated in favor of write_lattice", "0.15") + return getattr(self, "write_lattice") return getattr(self.fh, name) @classmethod diff --git a/sisl/io/tbtrans/_cdf.py b/sisl/io/tbtrans/_cdf.py index b345940749..4dd59a87be 100644 --- a/sisl/io/tbtrans/_cdf.py +++ b/sisl/io/tbtrans/_cdf.py @@ -15,7 +15,7 @@ from sisl._indices import indices # Import the geometry object -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl.unit.siesta import unit_convert from sisl.physics.distribution import fermi_dirac @@ -33,22 +33,22 @@ class _ncSileTBtrans(SileCDFTBtrans): r""" Common TBtrans NetCDF file object due to a lot of the files having common entries - This enables easy read of the Geometry and SuperCells etc. + This enables easy read of the Geometry and Lattices etc. """ @lru_cache(maxsize=1) - def read_supercell(self): - """ Returns `SuperCell` object from this file """ + def read_lattice(self): + """ Returns `Lattice` object from this file """ cell = _a.arrayd(np.copy(self.cell)) cell.shape = (3, 3) nsc = self._value('nsc') - sc = SuperCell(cell, nsc=nsc) - sc.sc_off = self._value('isc_off') - return sc + lattice = Lattice(cell, nsc=nsc) + lattice.sc_off = self._value('isc_off') + return lattice def read_geometry(self, *args, **kwargs): """ Returns `Geometry` object from this file """ - sc = self.read_supercell() + lattice = self.read_lattice() xyz = _a.arrayd(np.copy(self.xa)) xyz.shape = (-1, 3) @@ -74,7 +74,7 @@ def read_geometry(self, *args, **kwargs): atms = [Atom('H', [-1] * o) for o in nos] # Create and return geometry object - geom = Geometry(xyz, atms, sc=sc) + geom = Geometry(xyz, atms, lattice=lattice) return geom diff --git a/sisl/io/tbtrans/delta.py b/sisl/io/tbtrans/delta.py index e6679aa1d2..e634fbb71a 100644 --- a/sisl/io/tbtrans/delta.py +++ b/sisl/io/tbtrans/delta.py @@ -11,10 +11,10 @@ from .sile import SileCDFTBtrans # Import the geometry object -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl import SparseOrbitalBZSpin from sisl.sparse import _ncol_to_indptr -from sisl.messages import warn +from sisl.messages import warn, deprecate_argument from sisl.unit.siesta import unit_convert from ..siesta._help import _csr_to_siesta, _csr_from_sc_off, _mat_spin_convert from ..siesta._siesta import siesta_sc_off @@ -194,24 +194,24 @@ def has_level(self, ilvl): """ return f"LEVEL-{ilvl}" in self.groups - def read_supercell(self): - """ Returns the `SuperCell` object from this file """ + def read_lattice(self): + """ Returns the `Lattice` object from this file """ cell = _a.arrayd(np.copy(self._value('cell'))) * Bohr2Ang cell.shape = (3, 3) nsc = self._value('nsc') - sc = SuperCell(cell, nsc=nsc) + lattice = Lattice(cell, nsc=nsc) try: - sc.sc_off = self._value('isc_off') + lattice.sc_off = self._value('isc_off') except Exception: # This is ok, we simply do not have the supercell offsets pass - return sc + return lattice def read_geometry(self, *args, **kwargs): """ Returns the `Geometry` object from this file """ - sc = self.read_supercell() + lattice = self.read_lattice() xyz = _a.arrayd(np.copy(self._value('xa'))) * Bohr2Ang xyz.shape = (-1, 3) @@ -237,30 +237,31 @@ def read_geometry(self, *args, **kwargs): atms = [Atom('H', [-1] * o) for o in nos] # Create and return geometry object - geom = Geometry(xyz, atms, sc=sc) + geom = Geometry(xyz, atms, lattice=lattice) return geom - def write_supercell(self, sc): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice): """ Creates the NetCDF file and writes the supercell information """ sile_raise_write(self) # Create initial dimensions self._crt_dim(self, 'one', 1) - self._crt_dim(self, 'n_s', np.prod(sc.nsc)) + self._crt_dim(self, 'n_s', np.prod(lattice.nsc)) self._crt_dim(self, 'xyz', 3) # Create initial geometry v = self._crt_var(self, 'nsc', 'i4', ('xyz',)) v.info = 'Number of supercells in each unit-cell direction' - v[:] = sc.nsc[:] + v[:] = lattice.nsc[:] v = self._crt_var(self, 'isc_off', 'i4', ('n_s', 'xyz')) v.info = "Index of supercell coordinates" - v[:] = sc.sc_off[:, :] + v[:] = lattice.sc_off[:, :] v = self._crt_var(self, 'cell', 'f8', ('xyz', 'xyz')) v.info = 'Unit cell' v.unit = 'Bohr' - v[:] = sc.cell[:, :] / Bohr2Ang + v[:] = lattice.cell[:, :] / Bohr2Ang # Create designation of the creation self.method = 'sisl' @@ -270,7 +271,7 @@ def write_geometry(self, geometry): sile_raise_write(self) # Create initial dimensions - self.write_supercell(geometry.sc) + self.write_lattice(geometry.lattice) self._crt_dim(self, 'no_s', np.prod(geometry.nsc) * geometry.no) self._crt_dim(self, 'no_u', geometry.no) self._crt_dim(self, 'na_u', geometry.na) @@ -441,7 +442,7 @@ def write_delta(self, delta, **kwargs): if np.any(lvl.variables['list_col'][:] != csr.col[:]+1): raise ValueError("The sparsity pattern stored in delta *MUST* be equivalent for " "all delta entries [list_col].") - if np.any(lvl.variables['isc_off'][:] != siesta_sc_off(*delta.geometry.sc.nsc).T): + if np.any(lvl.variables['isc_off'][:] != siesta_sc_off(*delta.geometry.lattice.nsc).T): raise ValueError("The sparsity pattern stored in delta *MUST* be equivalent for " "all delta entries [sc_off].") else: @@ -455,7 +456,7 @@ def write_delta(self, delta, **kwargs): v[:] = csr.col[:] + 1 # correct for fortran indices v = self._crt_var(lvl, 'isc_off', 'i4', ('n_s', 'xyz')) v.info = "Index of supercell coordinates" - v[:] = siesta_sc_off(*delta.geometry.sc.nsc).T + v[:] = siesta_sc_off(*delta.geometry.lattice.nsc).T warn_E = True if ilvl in (3, 4): diff --git a/sisl/io/tbtrans/tests/test_tbt.py b/sisl/io/tbtrans/tests/test_tbt.py index baed51e02f..fe25ebd8b4 100644 --- a/sisl/io/tbtrans/tests/test_tbt.py +++ b/sisl/io/tbtrans/tests/test_tbt.py @@ -540,7 +540,7 @@ def test_1_graphene_all_sparse_data_isc_request(sisl_files): tbt = sisl.get_sile(sisl_files(_dir, '1_graphene_all.TBT.nc')) # get supercell with isc - sc = tbt.read_supercell() + sc = tbt.read_lattice() # request the full matrix for elec in [0, 1]: diff --git a/sisl/io/tests/test_cube.py b/sisl/io/tests/test_cube.py index 456debae22..68a90c5f50 100644 --- a/sisl/io/tests/test_cube.py +++ b/sisl/io/tests/test_cube.py @@ -25,7 +25,7 @@ def test_default(sisl_tmp): def test_default_size(sisl_tmp): f = sisl_tmp('GRID.cube', _dir) - grid = Grid(0.2, sc=2.0) + grid = Grid(0.2, lattice=2.0) grid.grid = np.random.rand(*grid.shape) grid.write(f) read = grid.read(f) @@ -36,7 +36,7 @@ def test_default_size(sisl_tmp): 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]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[10, 10, 10, 45, 60, 90]) grid = Grid(0.2, geometry=geom) grid.grid = np.random.rand(*grid.shape) grid.write(f) @@ -58,7 +58,7 @@ def test_geometry(sisl_tmp): 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]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[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) @@ -81,7 +81,7 @@ def test_imaginary(sisl_tmp): def test_imaginary_fail_shape(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]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[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) @@ -96,7 +96,7 @@ def test_imaginary_fail_shape(sisl_tmp): 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]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[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) diff --git a/sisl/io/tests/test_object.py b/sisl/io/tests/test_object.py index e14110e1d0..9a03f091aa 100644 --- a/sisl/io/tests/test_object.py +++ b/sisl/io/tests/test_object.py @@ -12,7 +12,7 @@ from sisl.io.siesta.binaries import _gfSileSiesta from sisl.io.tbtrans._cdf import * from sisl.io.vasp import chgSileVASP -from sisl import Geometry, GeometryCollection, Grid, Hamiltonian +from sisl import Lattice, Geometry, GeometryCollection, Grid, Hamiltonian from sisl import DensityMatrix, EnergyDensityMatrix @@ -233,6 +233,55 @@ def test_write(self, sisl_tmp, sisl_system): # Write sile(f, mode="w").write_geometry(G) + @pytest.mark.parametrize("sile", _my_intersect(["read_lattice"], ["write_lattice"])) + def test_read_write_lattice(self, sisl_tmp, sisl_system, sile): + L = sisl_system.g.rotate(-30, sisl_system.g.cell[2, :], what="xyz+abc").lattice + L.set_nsc([1, 1, 1]) + f = sisl_tmp("test_read_write_geom.win", _dir) + # These files does not store the atomic species + if issubclass(sile, (_ncSileTBtrans, deltancSileTBtrans)): + return + if sys.platform.startswith("win") and issubclass(sile, chgSileVASP): + pytest.xfail("Windows reading/writing supercell fails for some unknown reason") + + # Write + sile(f, mode="w").write_lattice(L) + # Read 1 + try: + with sile(f, mode='r') as s: + l = s.read_lattice() + assert l.equal(L, tol=1e-3) # pdb files have 8.3 for atomic coordinates + except UnicodeDecodeError as e: + pass + # Read 2 + try: + with sile(f, mode='r') as s: + l = Lattice.read(s) + assert l.equal(L, tol=1e-3) + except UnicodeDecodeError as e: + pass + + @pytest.mark.parametrize("sile", _my_intersect(["read_lattice"], ["write_lattice"])) + def test_read_write_supercell(self, sisl_tmp, sisl_system, sile): + L = sisl_system.g.rotate(-30, sisl_system.g.cell[2, :], what="xyz+abc").lattice + L.set_nsc([1, 1, 1]) + f = sisl_tmp("test_read_write_geom.win", _dir) + # These files does not store the atomic species + if issubclass(sile, (_ncSileTBtrans, deltancSileTBtrans)): + return + if sys.platform.startswith("win") and issubclass(sile, chgSileVASP): + pytest.xfail("Windows reading/writing supercell fails for some unknown reason") + + # Write + sile(f, mode="w").write_supercell(L) + # Read 1 + try: + with sile(f, mode='r') as s: + l = s.read_supercell() + assert l.equal(L, tol=1e-3) # pdb files have 8.3 for atomic coordinates + except UnicodeDecodeError as e: + pass + @pytest.mark.parametrize("sile", _my_intersect(["read_geometry"], ["write_geometry"])) def test_read_write_geometry(self, sisl_tmp, sisl_system, sile): G = sisl_system.g.rotate(-30, sisl_system.g.cell[2, :], what="xyz+abc") diff --git a/sisl/io/tests/test_xsf.py b/sisl/io/tests/test_xsf.py index d1762c7997..cb19fa07a6 100644 --- a/sisl/io/tests/test_xsf.py +++ b/sisl/io/tests/test_xsf.py @@ -23,7 +23,7 @@ def test_default(sisl_tmp): def test_default_size(sisl_tmp): f = sisl_tmp('GRID_default_size.xsf', _dir) - grid = Grid(0.2, sc=2.0) + grid = Grid(0.2, lattice=2.0) grid.grid = np.random.rand(*grid.shape) grid.write(f) assert grid.geometry is None @@ -31,7 +31,7 @@ def test_default_size(sisl_tmp): def test_geometry(sisl_tmp): f = sisl_tmp('GRID_geometry.xsf', _dir) - geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[10, 10, 10, 45, 60, 90]) grid = Grid(0.2, geometry=geom) grid.grid = np.random.rand(*grid.shape) grid.write(f) @@ -40,7 +40,7 @@ def test_geometry(sisl_tmp): def test_imaginary(sisl_tmp): f = sisl_tmp('GRID_imag.xsf', _dir) - geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[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) @@ -49,7 +49,7 @@ def test_imaginary(sisl_tmp): def test_axsf_geoms(sisl_tmp): f = sisl_tmp('multigeom_nodata.axsf', _dir) - geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[10, 10, 10, 45, 60, 90]) geoms = [geom.move((i/10, i/10, i/10)) for i in range(3)] with xsfSile(f, "w", steps=3) as s: @@ -87,7 +87,7 @@ def test_axsf_geoms(sisl_tmp): def test_axsf_data(sisl_tmp): f = sisl_tmp('multigeom_data.axsf', _dir) - geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), sc=[10, 10, 10, 45, 60, 90]) + geom = Geometry(np.random.rand(10, 3), np.random.randint(1, 70, 10), lattice=[10, 10, 10, 45, 60, 90]) geoms = [geom.move((i/10, i/10, i/10)) for i in range(3)] data = np.random.rand(3, 10, 3) diff --git a/sisl/io/tests/test_xyz.py b/sisl/io/tests/test_xyz.py index d0cbdbe769..0ca9df4b00 100644 --- a/sisl/io/tests/test_xyz.py +++ b/sisl/io/tests/test_xyz.py @@ -20,7 +20,7 @@ def test_xyz1(sisl_tmp, sisl_system): assert np.allclose(g.cell, sisl_system.g.cell) assert np.allclose(g.xyz, sisl_system.g.xyz) assert sisl_system.g.atoms.equal(g.atoms, R=False) - g = xyzSile(f).read_geometry(sc=g.sc) + g = xyzSile(f).read_geometry(lattice=g.lattice) assert np.allclose(g.cell, sisl_system.g.cell) @@ -43,7 +43,7 @@ def test_xyz_sisl(sisl_tmp): assert np.allclose(g.xyz[:, 2], 0.) assert np.allclose(g.nsc, [1, 1, 3]) - g = xyzSile(f).read_geometry(sc=[10, 11, 13]) + g = xyzSile(f).read_geometry(lattice=[10, 11, 13]) assert np.allclose(g.cell, [[10, 0, 0], [0, 11, 0], [0, 0, 13]]) @@ -128,4 +128,4 @@ def test_xyz_multiple(sisl_tmp): assert g[0].na == 2 and g[1].na == 3 # ensure it works with other arguments - g = xyzSile(f).read_geometry(sc=None, atoms=None) + g = xyzSile(f).read_geometry(lattice=None, atoms=None) diff --git a/sisl/io/vasp/car.py b/sisl/io/vasp/car.py index 5a90600e84..2552e61418 100644 --- a/sisl/io/vasp/car.py +++ b/sisl/io/vasp/car.py @@ -10,7 +10,7 @@ from sisl._internal import set_module import sisl._array as _a from sisl.messages import warn -from sisl import Geometry, PeriodicTable, Atom, SuperCell +from sisl import Geometry, PeriodicTable, Atom, Lattice __all__ = ['carSileVASP'] @@ -119,8 +119,8 @@ def todyn(fix): self._write(fmt.format(*geometry.xyz[ia, :]) + todyn(dynamic[idx[ia]])) @sile_fh_open(True) - def read_supercell(self): - """ Returns `SuperCell` object from the CONTCAR/POSCAR file """ + def read_lattice(self): + """ Returns `Lattice` object from the CONTCAR/POSCAR file """ # read first line self.readline() # LABEL @@ -133,7 +133,7 @@ def read_supercell(self): cell[i, :] = list(map(float, self.readline().split()[:3])) cell *= self._scale - return SuperCell(cell) + return Lattice(cell) @sile_fh_open() def read_geometry(self, ret_dynamic=False): @@ -147,7 +147,7 @@ def read_geometry(self, ret_dynamic=False): also return selective dynamics (if present), if not, None will be returned. """ - sc = self.read_supercell() + lattice = self.read_lattice() # The species labels are not always included in *CAR line1 = self.readline().split() @@ -204,10 +204,10 @@ def read_geometry(self, ret_dynamic=False): # The unit of the coordinates are cartesian xyz *= self._scale else: - xyz = xyz.dot(sc.cell) + xyz = xyz.dot(lattice.cell) # The POT/CONT-CAR does not contain information on the atomic species - geom = Geometry(xyz=xyz, atoms=atom, sc=sc) + geom = Geometry(xyz=xyz, atoms=atom, lattice=lattice) if ret_dynamic: return geom, dynamic return geom diff --git a/sisl/io/vasp/chg.py b/sisl/io/vasp/chg.py index 1d41f8f78c..5b016d1210 100644 --- a/sisl/io/vasp/chg.py +++ b/sisl/io/vasp/chg.py @@ -45,7 +45,7 @@ def read_grid(self, index=0, dtype=np.float64, **kwargs): """ index = kwargs.get("spin", index) geom = self.read_geometry() - V = geom.sc.volume + V = geom.lattice.volume rl = self.readline diff --git a/sisl/io/vasp/locpot.py b/sisl/io/vasp/locpot.py index 7f638266f8..93a32fc276 100644 --- a/sisl/io/vasp/locpot.py +++ b/sisl/io/vasp/locpot.py @@ -46,7 +46,7 @@ def read_grid(self, index=0, dtype=np.float64, **kwargs): """ index = kwargs.get("spin", index) geom = self.read_geometry() - V = geom.sc.volume + V = geom.lattice.volume # Now we are past the cell and geometry # We can now read the size of LOCPOT diff --git a/sisl/io/wannier90/seedname.py b/sisl/io/wannier90/seedname.py index 02a7f77ee2..a1638d6712 100644 --- a/sisl/io/wannier90/seedname.py +++ b/sisl/io/wannier90/seedname.py @@ -12,8 +12,8 @@ from .sile import SileWannier90 from ..sile import * -# Import the geometry object -from sisl import Geometry, SuperCell +from sisl.messages import deprecate_argument +from sisl import Geometry, Lattice from sisl.physics import Hamiltonian from sisl.unit import unit_convert @@ -70,7 +70,7 @@ def _set_file(self, suffix=None): self._file = Path(self._seed + suffix) @sile_fh_open() - def _read_supercell(self): + def _read_lattice(self): """ Deferred routine """ f, l = self.step_to('unit_cell_cart', case=False) @@ -97,14 +97,14 @@ def _read_supercell(self): for i in [0, 1, 2]: cell[i, :] = [float(x) for x in lines[i].split()] - return SuperCell(cell * unit) + return Lattice(cell * unit) - def read_supercell(self): - """ Reads a `SuperCell` and creates the Wannier90 cell """ + def read_lattice(self): + """ Reads a `Lattice` and creates the Wannier90 cell """ # Reset self._set_file() - return self._read_supercell() + return self._read_lattice() @sile_fh_open() def _read_geometry_centres(self, *args, **kwargs): @@ -128,7 +128,7 @@ def _read_geometry_centres(self, *args, **kwargs): return Geometry(xyz[:na, :], atoms='H') @sile_fh_open() - def _read_geometry(self, sc, *args, **kwargs): + def _read_geometry(self, lattice, *args, **kwargs): """ Defered routine """ is_frac = True @@ -170,32 +170,33 @@ def _read_geometry(self, sc, *args, **kwargs): xyz = np.array(xyz, np.float64) * unit if is_frac: - xyz = np.dot(sc.cell.T, xyz.T).T + xyz = np.dot(lattice.cell.T, xyz.T).T - return Geometry(xyz, atoms=s, sc=sc) + return Geometry(xyz, atoms=s, lattice=lattice) + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") def read_geometry(self, *args, **kwargs): """ Reads a `Geometry` and creates the Wannier90 cell """ # Read in the super-cell - sc = self.read_supercell() + lattice = self.read_lattice() self._set_file('_centres.xyz') if self.file.is_file(): geom = self._read_geometry_centres() else: self._set_file() - geom = self._read_geometry(sc, *args, **kwargs) + geom = self._read_geometry(lattice, *args, **kwargs) # Reset file self._set_file() # Specify the supercell and return - geom.set_sc(sc) + geom.set_lattice(lattice) return geom @sile_fh_open() - def _write_supercell(self, sc, fmt='.8f', *args, **kwargs): + def _write_lattice(self, lattice, fmt='.8f', *args, **kwargs): """ Writes the supercel to the contained file """ # Check that we can write to the file sile_raise_write(self) @@ -204,15 +205,16 @@ def _write_supercell(self, sc, fmt='.8f', *args, **kwargs): self._write('begin unit_cell_cart\n') self._write(' Ang\n') - self._write(fmt_str.format(*sc.cell[0, :])) - self._write(fmt_str.format(*sc.cell[1, :])) - self._write(fmt_str.format(*sc.cell[2, :])) + self._write(fmt_str.format(*lattice.cell[0, :])) + self._write(fmt_str.format(*lattice.cell[1, :])) + self._write(fmt_str.format(*lattice.cell[2, :])) self._write('end unit_cell_cart\n') - def write_supercell(self, sc, fmt='.8f', *args, **kwargs): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice, fmt='.8f', *args, **kwargs): """ Writes the supercell to the contained file """ self._set_file() - self._write_supercell(sc, fmt, *args, **kwargs) + self._write_lattice(lattice, fmt, *args, **kwargs) @sile_fh_open() def _write_geometry(self, geom, fmt='.8f', *args, **kwargs): @@ -220,10 +222,10 @@ def _write_geometry(self, geom, fmt='.8f', *args, **kwargs): # Check that we can write to the file sile_raise_write(self) - # We have to have the _write_supercell here + # We have to have the _write_lattice here # due to the open function re-instantiating the mode, # and if it isn't 'a', then it cleans it... :( - self._write_supercell(geom.sc, fmt, *args, **kwargs) + self._write_lattice(geom.lattice, fmt, *args, **kwargs) fmt_str = ' {{1:2s}} {{2:{0}}} {{3:{0}}} {{4:{0}}} # {{0}}\n'.format(fmt) diff --git a/sisl/io/xsf.py b/sisl/io/xsf.py index 3c7e6f7a34..5b6237e4ba 100644 --- a/sisl/io/xsf.py +++ b/sisl/io/xsf.py @@ -8,10 +8,11 @@ # Import sile objects from .sile import * +from sisl.messages import deprecate_argument from sisl._internal import set_module from sisl import PeriodicTable, Grid from sisl._collection import Collection -from sisl import Geometry, GeometryCollection, AtomUnknown, SuperCell +from sisl import Geometry, GeometryCollection, AtomUnknown, Lattice from sisl.utils import str_spec import sisl._array as _a @@ -105,12 +106,13 @@ def _write_animsteps(self): self._write(f"ANIMSTEPS {self._geometry_max}\n") @sile_fh_open(reset=reset_values(("_geometry_write", 0), animsteps=True)) - def write_supercell(self, sc, fmt='.8f'): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def write_lattice(self, lattice, fmt='.8f'): """ Writes the supercell to the contained file Parameters ---------- - sc : SuperCell + lattice : Lattice the supercell to be written fmt : str, optional used format for the precision of the data @@ -122,11 +124,11 @@ def write_supercell(self, sc, fmt='.8f'): from time import gmtime, strftime self._write_once('# File created by: sisl {}\n#\n'.format(strftime("%Y-%m-%d", gmtime()))) - if all(sc.nsc == 1): + if all(lattice.nsc == 1): self._write_once("MOLECULE\n#\n") - elif all(sc.nsc[:2] > 1): + elif all(lattice.nsc[:2] > 1): self._write_once("SLAB\n#\n") - elif sc.nsc[0] > 1: + elif lattice.nsc[0] > 1: self._write_once("POLYMER\n#\n") else: self._write_once('CRYSTAL\n#\n') @@ -137,14 +139,14 @@ def write_supercell(self, sc, fmt='.8f'): # We write the cell coordinates as the cell coordinates fmt_str = f'{{:{fmt}}} ' * 3 + '\n' for i in (0, 1, 2): - self._write(fmt_str.format(*sc.cell[i, :])) + self._write(fmt_str.format(*lattice.cell[i, :])) # Convert the unit cell to a conventional cell (90-90-90)) # It seems this simply allows to store both formats in # the same file. However the below stuff is not correct. #self._write_once('#\n# Conventional lattice vectors:\n#\n') #self._write_key_index('CONVVEC') - #convcell = sc.toCuboid(True)._v + #convcell = lattice.toCuboid(True)._v #for i in [0, 1, 2]: # self._write(fmt_str.format(*convcell[i, :])) @@ -162,7 +164,7 @@ def write_geometry(self, geometry, fmt='.8f', data=None): auxiliary data associated with the geometry to be saved along side. Internally in XCrySDen this data is named *Forces* """ - self.write_supercell(geometry.sc, fmt) + self.write_lattice(geometry.lattice, fmt) has_data = data is not None if has_data: @@ -190,10 +192,10 @@ def write_geometry(self, geometry, fmt='.8f', data=None): self._write(fmt_str.format(geometry.atoms[ia].Z, *geometry.xyz[ia, :])) @sile_fh_open() - def _r_geometry_next(self, sc=None, atoms=None, ret_data=False): - if sc is None: + def _r_geometry_next(self, lattice=None, atoms=None, ret_data=False): + if lattice is None: # fetch the prior read cell value - sc = self._read_cell + lattice = self._read_cell # initialize all things cell = None @@ -288,12 +290,12 @@ def next(): cell = None if primvec is not None: - cell = SuperCell(primvec, nsc=nsc) - elif sc is not None: - cell = sc + cell = Lattice(primvec, nsc=nsc) + elif lattice is not None: + cell = lattice elif typ == "MOLECULE": - cell = SuperCell(np.diag(xyz.max(0) - xyz.min(0) + 10.)) + cell = Lattice(np.diag(xyz.max(0) - xyz.min(0) + 10.)) if cell is None: raise ValueError(f"{self.__class__.__name__} could not find lattice parameters.") @@ -311,18 +313,19 @@ def next(): return None, None return None - geom = Geometry(xyz, atoms=atoms, sc=cell) + geom = Geometry(xyz, atoms=atoms, lattice=cell) if ret_data: return geom, _a.arrayd(data) return geom @sile_read_multiple(postprocess=postprocess(GeometryCollection, Collection)) - def read_geometry(self, sc=None, atoms=None, ret_data=False): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def read_geometry(self, lattice=None, atoms=None, ret_data=False): """ Geometry contained in file, and optionally the associated data Parameters ---------- - sc : SuperCell, optional + lattice : Lattice, optional the supercell in case the lattice vectors are not present in the current block. atoms : Atoms, optional @@ -330,7 +333,7 @@ def read_geometry(self, sc=None, atoms=None, ret_data=False): ret_data : bool, optional in case the the file has auxiliary data, return that as well. """ - return self._r_geometry_next(sc=sc, atoms=atoms, ret_data=ret_data) + return self._r_geometry_next(lattice=lattice, atoms=atoms, ret_data=ret_data) @sile_fh_open() def write_grid(self, *args, **kwargs): @@ -338,8 +341,8 @@ def write_grid(self, *args, **kwargs): Examples -------- - >>> g1 = Grid(0.1, sc=2.) - >>> g2 = Grid(0.1, sc=2.) + >>> g1 = Grid(0.1, lattice=2.) + >>> g2 = Grid(0.1, lattice=2.) >>> get_sile('output.xsf', 'w').write_grid(g1, g2) Parameters @@ -364,7 +367,7 @@ def write_grid(self, *args, **kwargs): geom = kwargs.get('geometry', args[0].geometry) if geom is None: - geom = Geometry([0, 0, 0], AtomUnknown(999), sc=args[0].sc) + geom = Geometry([0, 0, 0], AtomUnknown(999), lattice=args[0].lattice) self.write_geometry(geom) # Buffer size for writing diff --git a/sisl/io/xyz.py b/sisl/io/xyz.py index c21dada12a..c1395809fb 100644 --- a/sisl/io/xyz.py +++ b/sisl/io/xyz.py @@ -10,9 +10,9 @@ from ._help import header_to_dict from .sile import * +from sisl.messages import warn, deprecate_argument from sisl._internal import set_module -from sisl import Geometry, SuperCell, GeometryCollection -from sisl.messages import warn +from sisl import Geometry, Lattice, GeometryCollection import sisl._array as _a @@ -57,35 +57,34 @@ def write_geometry(self, geometry, fmt='.8f', comment=None): s = {'fa': 'Ds'}.get(a.symbol, a.symbol) self._write(fmt_str.format(s, *geometry.xyz[ia, :])) - def _r_geometry_sisl(self, na, header, sp, xyz, sc): + def _r_geometry_sisl(self, na, header, sp, xyz, lattice): """ Read the geometry as though it was created with sisl """ # Default version of the header is 1 #v = int(header.get("sisl-version", 1)) nsc = list(map(int, header.pop("nsc").split())) cell = _a.fromiterd(header.pop("cell").split()).reshape(3, 3) - if sc is None: - sc = SuperCell(cell, nsc=nsc) - return Geometry(xyz, atoms=sp, sc=sc) + if lattice is None: + lattice = Lattice(cell, nsc=nsc) + return Geometry(xyz, atoms=sp, lattice=lattice) - def _r_geometry_ase(self, na, header, sp, xyz, sc): + def _r_geometry_ase(self, na, header, sp, xyz, lattice): """ Read the geometry as though it was created with ASE """ # Convert F T to nsc # F = 1 # T = 3 nsc = list(map(lambda x: "FT".index(x) * 2 + 1, header.pop("pbc").strip('"').split())) cell = _a.fromiterd(header.pop("Lattice").strip('"').split()).reshape(3, 3) - if sc is None: - sc = SuperCell(cell, nsc=nsc) + if lattice is None: + lattice = Lattice(cell, nsc=nsc) + return Geometry(xyz, atoms=sp, lattice=lattice) - return Geometry(xyz, atoms=sp, sc=sc) - - def _r_geometry(self, na, sp, xyz, sc): + def _r_geometry(self, na, sp, xyz, lattice): """ Read the geometry for a generic xyz file (not sisl, nor ASE) """ # The cell dimensions isn't defined, we are going to create a molecule box cell = xyz.max(0) - xyz.min(0) + 10. - if sc is None: - sc = SuperCell(cell, nsc=[1] * 3) - return Geometry(xyz, atoms=sp, sc=sc) + if lattice is None: + lattice = Lattice(cell, nsc=[1] * 3) + return Geometry(xyz, atoms=sp, lattice=lattice) def _r_geometry_skip(self, *args, **kwargs): """ Read the geometry for a generic xyz file (not sisl, nor ASE) """ @@ -102,15 +101,16 @@ def _r_geometry_skip(self, *args, **kwargs): @sile_fh_open() @sile_read_multiple(skip_call=_r_geometry_skip, postprocess=GeometryCollection) - def read_geometry(self, atoms=None, sc=None): + @deprecate_argument("sc", "lattice", "use lattice= instead of sc=", from_version="0.15") + def read_geometry(self, atoms=None, lattice=None): """ Returns Geometry object from the XYZ file Parameters ---------- atoms : Atoms, optional the atoms to be associated with the Geometry - sc : SuperCell, optional - the supercell to be associated with the geometry + lattice : Lattice, optional + the lattice to be associated with the geometry """ line = self.readline() if line == '': @@ -142,10 +142,10 @@ def _has_keys(d, *keys): return True if _has_keys(kv, "cell", "nsc"): - return self._r_geometry_sisl(na, kv, sp, xyz, sc) + return self._r_geometry_sisl(na, kv, sp, xyz, lattice) elif _has_keys(kv, "Properties", "Lattice", "pbc"): - return self._r_geometry_ase(na, kv, sp, xyz, sc) - return self._r_geometry(na, sp, xyz, sc) + return self._r_geometry_ase(na, kv, sp, xyz, lattice) + return self._r_geometry(na, sp, xyz, lattice) def ArgumentParser(self, p=None, *args, **kwargs): """ Returns the arguments that is available for this Sile """ diff --git a/sisl/supercell.py b/sisl/lattice.py similarity index 89% rename from sisl/supercell.py rename to sisl/lattice.py index 29370ecd98..9791e97a26 100644 --- a/sisl/supercell.py +++ b/sisl/lattice.py @@ -1,7 +1,7 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. -""" Define a supercell +""" Define a lattice with cell-parameters and supercells This class is the basis of many different objects. """ @@ -22,14 +22,14 @@ from .shape.prism4 import Cuboid from .quaternion import Quaternion from ._math_small import cross3, dot3 -from ._supercell import cell_invert, cell_reciprocal +from ._lattice import cell_invert, cell_reciprocal -__all__ = ['SuperCell', 'SuperCellChild'] +__all__ = ["Lattice", "SuperCell", "LatticeChild"] @set_module("sisl") -class SuperCell: +class Lattice: r""" A cell class to retain lattice vectors and a supercell structure The supercell structure is comprising the *primary* unit-cell and neighbouring @@ -50,7 +50,7 @@ class SuperCell: the origin of the supercell. """ - # We limit the scope of this SuperCell object. + # We limit the scope of this Lattice object. __slots__ = ('cell', '_origin', 'nsc', 'n_s', '_sc_off', '_isc_off') def __init__(self, cell, nsc=None, origin=None): @@ -173,7 +173,7 @@ def _fill(self, non_filled, dtype=None): # Fill in zeros # This will purposefully raise an exception - # if the dimensions of the periodic ones + # if the dimensions of the periodic one # are not consistent. if dtype is None: try: @@ -382,7 +382,7 @@ def fit(self, xyz, axis=None, tol=0.05): def swapaxes(self, axes_a: Union[int, str], axes_b: Union[int, str], - what: str="abc") -> SuperCell: + what: str="abc") -> Lattice: r""" Swaps axes `axes_a` and `axes_b` Swapaxes is a versatile method for changing the order @@ -504,26 +504,26 @@ def plane(self, ax1, ax2, origin=True): All 6 faces of the supercell can be retrieved like this: - >>> sc = SuperCell(4) - >>> n1, p1 = sc.plane(0, 1, True) - >>> n2, p2 = sc.plane(0, 1, False) - >>> n3, p3 = sc.plane(0, 2, True) - >>> n4, p4 = sc.plane(0, 2, False) - >>> n5, p5 = sc.plane(1, 2, True) - >>> n6, p6 = sc.plane(1, 2, False) + >>> lattice = Lattice(4) + >>> n1, p1 = lattice.plane(0, 1, True) + >>> n2, p2 = lattice.plane(0, 1, False) + >>> n3, p3 = lattice.plane(0, 2, True) + >>> n4, p4 = lattice.plane(0, 2, False) + >>> n5, p5 = lattice.plane(1, 2, True) + >>> n6, p6 = lattice.plane(1, 2, False) However, for performance critical calculations it may be advantageous to do this: - >>> sc = SuperCell(4) - >>> uc = sc.cell.sum(0) - >>> n1, p1 = sc.plane(0, 1) + >>> lattice = Lattice(4) + >>> uc = lattice.cell.sum(0) + >>> n1, p1 = lattice.plane(0, 1) >>> n2 = -n1 >>> p2 = p1 + uc - >>> n3, p3 = sc.plane(0, 2) + >>> n3, p3 = lattice.plane(0, 2) >>> n4 = -n3 >>> p4 = p3 + uc - >>> n5, p5 = sc.plane(1, 2) + >>> n5, p5 = lattice.plane(1, 2) >>> n6 = -n5 >>> p6 = p5 + uc @@ -562,21 +562,21 @@ def __mul__(self, m): Returns ------- - SuperCell + Lattice enlarged supercell """ # Simple form if isinstance(m, Integral): return self.tile(m, 0).tile(m, 1).tile(m, 2) - sc = self.copy() + lattice = self.copy() for i, r in enumerate(m): - sc = sc.tile(r, i) - return sc + lattice = lattice.tile(r, i) + return lattice @property def icell(self): - """ Returns the reciprocal (inverse) cell for the `SuperCell`. + """ Returns the reciprocal (inverse) cell for the `Lattice`. Note: The returned vectors are still in ``[0, :]`` format and not as returned by an inverse LAPACK algorithm. @@ -585,7 +585,7 @@ def icell(self): @property def rcell(self): - """ Returns the reciprocal cell for the `SuperCell` with ``2*np.pi`` + """ Returns the reciprocal cell for the `Lattice` with ``2*np.pi`` Note: The returned vectors are still in [0, :] format and not as returned by an inverse LAPACK algorithm. @@ -628,7 +628,7 @@ def cell2length(self, length, axes=(0, 1, 2)) -> ndarray: "0.14.0") def rotate(self, angle, v, rad: bool=False, - what: str="abc") -> SuperCell: + what: str="abc") -> Lattice: """ Rotates the supercell, in-place by the angle around the vector One can control which cell vectors are rotated by designating them @@ -675,11 +675,11 @@ def add(self, other): Parameters ---------- - other : SuperCell, array_like + other : Lattice, array_like the lattice vectors of the other supercell to add """ - if not isinstance(other, SuperCell): - other = SuperCell(other) + if not isinstance(other, Lattice): + other = Lattice(other) cell = self.cell + other.cell origin = self.origin + other.origin nsc = np.where(self.nsc > other.nsc, self.nsc, other.nsc) @@ -839,7 +839,12 @@ def repeat(self, reps, axis): return self.tile(reps, axis) def untile(self, reps, axis): - """Reverses a `SuperCell.tile` and returns the segmented version + """Reverses a `Lattice.tile` and returns the segmented version + + Notes + ----- + Untiling will not correctly re-calculate nsc since it has no + knowledge of connections. See Also -------- @@ -852,15 +857,16 @@ def untile(self, reps, axis): unrepeat = untile def append(self, other, axis): - """ Appends other `SuperCell` to this grid along axis """ + """ Appends other `Lattice` to this grid along axis """ cell = np.copy(self.cell) cell[axis, :] += other.cell[axis, :] + # TODO fix nsc here return self.copy(cell) def prepend(self, other, axis): - """ Prepends other `SuperCell` to this grid along axis + """ Prepends other `Lattice` to this grid along axis - For a `SuperCell` object this is equivalent to `append`. + For a `Lattice` object this is equivalent to `append`. """ return self.append(other, axis) @@ -878,7 +884,7 @@ def translate(self, v): move = translate def center(self, axis=None): - """ Returns center of the `SuperCell`, possibly with respect to an axis """ + """ Returns center of the `Lattice`, possibly with respect to an axis """ if axis is None: return self.cell.sum(0) * 0.5 return self.cell[axis, :] * 0.5 @@ -911,9 +917,9 @@ def tocell(cls, *args): Examples -------- - >>> cell_1_1_1 = SuperCell.tocell(1.) - >>> cell_1_2_3 = SuperCell.tocell(1., 2., 3.) - >>> cell_1_2_3 = SuperCell.tocell([1., 2., 3.]) # same as above + >>> cell_1_1_1 = Lattice.tocell(1.) + >>> cell_1_2_3 = Lattice.tocell(1., 2., 3.) + >>> cell_1_2_3 = Lattice.tocell([1., 2., 3.]) # same as above """ # Convert into true array (flattened) args = _a.asarrayd(args).ravel() @@ -1002,7 +1008,7 @@ def parallel(self, other, axis=(0, 1, 2)): Parameters ---------- - other : SuperCell + other : Lattice the other object to check whether the axis are parallel axis : int or array_like only check the specified axis (default to all) @@ -1036,7 +1042,7 @@ def angle(self, i, j, rad=False): @staticmethod def read(sile, *args, **kwargs): - """ Reads the supercell from the `Sile` using ``Sile.read_supercell`` + """ Reads the supercell from the `Sile` using ``Sile.read_lattice`` Parameters ---------- @@ -1048,10 +1054,10 @@ def read(sile, *args, **kwargs): # have been imported previously from sisl.io import get_sile, BaseSile if isinstance(sile, BaseSile): - return sile.read_supercell(*args, **kwargs) + return sile.read_lattice(*args, **kwargs) else: with get_sile(sile, mode='r') as fh: - return fh.read_supercell(*args, **kwargs) + return fh.read_lattice(*args, **kwargs) def equal(self, other, tol=1e-4): """ Check whether two supercell are equivalent @@ -1061,7 +1067,7 @@ def equal(self, other, tol=1e-4): tol : float, optional tolerance value for the cell vectors and origin """ - if not isinstance(other, (SuperCell, SuperCellChild)): + if not isinstance(other, (Lattice, LatticeChild)): return False same = np.allclose(self.cell, other.cell, atol=tol) same = same and np.allclose(self.nsc, other.nsc) @@ -1157,40 +1163,44 @@ def __plot__(self, axis=None, axes=False, *args, **kwargs): return axes -class SuperCellChild: - """ Class to be inherited by using the ``self.sc`` as a `SuperCell` object +# same reference +SuperCell = Lattice - Initialize by a `SuperCell` object and get access to several different - routines directly related to the `SuperCell` class. + +class LatticeChild: + """ Class to be inherited by using the ``self.lattice`` as a `Lattice` object + + Initialize by a `Lattice` object and get access to several different + routines directly related to the `Lattice` class. """ def set_nsc(self, *args, **kwargs): - """ Set the number of super-cells in the `SuperCell` object + """ Set the number of super-cells in the `Lattice` object See `set_nsc` for allowed parameters. See Also -------- - SuperCell.set_nsc : the underlying called method + Lattice.set_nsc : the underlying called method """ - self.sc.set_nsc(*args, **kwargs) + self.lattice.set_nsc(*args, **kwargs) - def set_supercell(self, sc): + def set_lattice(self, lattice): """ Overwrites the local supercell """ - if sc is None: + if lattice is None: # Default supercell is a simple # 1x1x1 unit-cell - self.sc = SuperCell([1., 1., 1.]) - elif isinstance(sc, SuperCell): - self.sc = sc - elif isinstance(sc, SuperCellChild): - self.sc = sc.sc + self.lattice = Lattice([1., 1., 1.]) + elif isinstance(lattice, Lattice): + self.lattice = lattice + elif isinstance(lattice, LatticeChild): + self.lattice = lattice.lattice else: # The supercell is given as a cell - self.sc = SuperCell(sc) + self.lattice = Lattice(lattice) # Loop over attributes in this class - # if it inherits SuperCellChild, we call + # if it inherits LatticeChild, we call # set_sc on that too. # Sadly, getattr fails for @property methods # which forces us to use try ... except @@ -1198,96 +1208,69 @@ def set_supercell(self, sc): warnings.simplefilter("ignore") for a in dir(self): try: - if isinstance(getattr(self, a), SuperCellChild): - getattr(self, a).set_supercell(self.sc) + if isinstance(getattr(self, a), LatticeChild): + getattr(self, a).set_lattice(self.lattice) except Exception: pass - set_sc = deprecate_method("set_sc is deprecated; prefer to use set_supercell instead", "0.14")(set_supercell) + set_sc = deprecate_method("set_sc is deprecated; prefer to use set_lattice instead", "0.14")(set_lattice) + set_supercell = deprecate_method("set_sc is deprecated; prefer to use set_lattice instead", "0.15")(set_lattice) @property def length(self): - """ Returns the inherent `SuperCell` objects `length` """ - return self.sc.length + """ Returns the inherent `Lattice` objects `length` """ + return self.lattice.length @property def volume(self): - """ Returns the inherent `SuperCell` objects `volume` """ - return self.sc.volume + """ Returns the inherent `Lattice` objects `volume` """ + return self.lattice.volume def area(self, ax0, ax1): """ Calculate the area spanned by the two axis `ax0` and `ax1` """ - return self.sc.area(ax0, ax1) + return self.lattice.area(ax0, ax1) @property def cell(self): - """ Returns the inherent `SuperCell` objects `cell` """ - return self.sc.cell + """ Returns the inherent `Lattice` objects `cell` """ + return self.lattice.cell @property def icell(self): - """ Returns the inherent `SuperCell` objects `icell` """ - return self.sc.icell + """ Returns the inherent `Lattice` objects `icell` """ + return self.lattice.icell @property def rcell(self): - """ Returns the inherent `SuperCell` objects `rcell` """ - return self.sc.rcell + """ Returns the inherent `Lattice` objects `rcell` """ + return self.lattice.rcell @property def origin(self): - """ Returns the inherent `SuperCell` objects `origin` """ - return self.sc.origin - - @property - def origo(self): - """ Returns the inherent `SuperCell` objects `origin` """ - return self.sc.origo + """ Returns the inherent `Lattice` objects `origin` """ + return self.lattice.origin @property def n_s(self): - """ Returns the inherent `SuperCell` objects `n_s` """ - return self.sc.n_s + """ Returns the inherent `Lattice` objects `n_s` """ + return self.lattice.n_s @property def nsc(self): - """ Returns the inherent `SuperCell` objects `nsc` """ - return self.sc.nsc + """ Returns the inherent `Lattice` objects `nsc` """ + return self.lattice.nsc @property def sc_off(self): - """ Returns the inherent `SuperCell` objects `sc_off` """ - return self.sc.sc_off + """ Returns the inherent `Lattice` objects `sc_off` """ + return self.lattice.sc_off @property def isc_off(self): - """ Returns the inherent `SuperCell` objects `isc_off` """ - return self.sc.isc_off - - def add_vacuum(self, vacuum, axis): - """ Add vacuum along the `axis` lattice vector - - Parameters - ---------- - vacuum : float - amount of vacuum added, in Ang - axis : int - the lattice vector to add vacuum along - """ - copy = self.copy() - copy.set_supercell(self.sc.add_vacuum(vacuum, axis)) - return copy - - def _fill(self, non_filled, dtype=None): - return self.sc._fill(non_filled, dtype) - - def _fill_sc(self, supercell_index): - return self.sc._fill_sc(supercell_index) + """ Returns the inherent `Lattice` objects `isc_off` """ + return self.lattice.isc_off def sc_index(self, *args, **kwargs): - """ Call local `SuperCell` object `sc_index` function """ - return self.sc.sc_index(*args, **kwargs) + """ Call local `Lattice` object `sc_index` function """ + return self.lattice.sc_index(*args, **kwargs) - def is_orthogonal(self): - """ Return true if all cell vectors are linearly independent""" - return self.sc.is_orthogonal() diff --git a/sisl/orbital.py b/sisl/orbital.py index ec48c79ec0..db04fa4795 100644 --- a/sisl/orbital.py +++ b/sisl/orbital.py @@ -292,17 +292,17 @@ def toGrid(self, precision=0.05, c=1., R=None, dtype=np.float64, atom=1): # Since all these things depend on other elements # we will simply import them here. - from .supercell import SuperCell + from .lattice import Lattice from .geometry import Geometry from .grid import Grid from .atom import Atom from .physics.electron import wavefunction - sc = SuperCell(R*2, origin=[-R] * 3) + lattice = Lattice(R*2, origin=[-R] * 3) if isinstance(atom, Atom): atom = atom.copy(orbitals=self) else: atom = Atom(atom, self) - g = Geometry([0] * 3, atom, sc=sc) + g = Geometry([0] * 3, atom, lattice=lattice) G = Grid(precision, dtype=dtype, geometry=g) wavefunction(np.full(1, c), G, geometry=g) return G diff --git a/sisl/physics/_brillouinzone_apply.py b/sisl/physics/_brillouinzone_apply.py index 692cc82258..73f048582c 100644 --- a/sisl/physics/_brillouinzone_apply.py +++ b/sisl/physics/_brillouinzone_apply.py @@ -25,7 +25,7 @@ from sisl.oplist import oplist import sisl._array as _a from sisl.messages import progressbar, SislError -from sisl.supercell import SuperCell +from sisl.lattice import Lattice from sisl.grid import Grid from sisl.unit import units @@ -556,7 +556,7 @@ def k2idx(k): if grid_unit == 'b': cell = np.diag(mp._size) else: - cell = parent.sc.rcell * mp._size.reshape(1, -1) / units("Ang", grid_unit) + cell = parent.lattice.rcell * mp._size.reshape(1, -1) / units("Ang", grid_unit) # Find the grid origin origin = -(cell * 0.5).sum(0) @@ -598,8 +598,8 @@ def k2idx(k): centered=mp._centered, trs=True)[1]) # Create the grid in the reciprocal cell - sc = SuperCell(cell, origin=origin) - grid = Grid(diag, sc=sc, dtype=v.dtype) + lattice = Lattice(cell, origin=origin) + grid = Grid(diag, lattice=lattice, dtype=v.dtype) if data_axis is None: grid[k2idx(k[0])] = v else: diff --git a/sisl/physics/brillouinzone.py b/sisl/physics/brillouinzone.py index 044601c9c3..bc37615071 100644 --- a/sisl/physics/brillouinzone.py +++ b/sisl/physics/brillouinzone.py @@ -152,7 +152,7 @@ from sisl.utils import batched_indices import sisl._array as _a from sisl.messages import info, warn, SislError, progressbar -from sisl.supercell import SuperCell +from sisl.lattice import Lattice from sisl.grid import Grid from sisl._dispatcher import ClassDispatcher @@ -254,14 +254,14 @@ class BrillouinZone: 2. `rcell` which is the reciprocal lattice vectors. The object may also be an array of floats in which case an internal - `SuperCell` object will be created from the cell vectors (see `SuperCell` for + `Lattice` object will be created from the cell vectors (see `Lattice` for details). Parameters ---------- parent : object or array_like An object with associated ``parent.cell`` and ``parent.rcell`` or - an array of floats which may be turned into a `SuperCell` + an array of floats which may be turned into a `Lattice` k : array_like, optional k-points that this Brillouin zone represents weight : scalar or array_like, optional @@ -303,15 +303,15 @@ def set_parent(self, parent): parent.rcell self.parent = parent except Exception: - self.parent = SuperCell(parent) + self.parent = Lattice(parent) def __str__(self): """ String representation of the BrillouinZone """ parent = self.parent - if isinstance(parent, SuperCell): + if isinstance(parent, Lattice): parent = str(parent).replace("\n", "\n ") else: - parent = str(parent.sc).replace("\n", "\n ") + parent = str(parent.lattice).replace("\n", "\n ") return f"{self.__class__.__name__}{{nk: {len(self)},\n {parent}\n}}" def __getstate__(self): @@ -426,7 +426,7 @@ def parametrize(parent, func, N, *args, **kwargs): Parameters ---------- - parent : SuperCell, or SuperCellChild + parent : Lattice, or LatticeChild the object that the returned object will contain as parent func : callable method that parameterizes the k-points, *must* at least accept three arguments, @@ -487,7 +487,7 @@ def param_circle(parent, N_or_dk, kR, normal, origin, loop=False): Parameters ---------- - parent : SuperCell, or SuperCellChild + parent : Lattice, or LatticeChild the parent object N_or_dk : int number of k-points generated using the parameterization (if an integer), @@ -506,13 +506,13 @@ def param_circle(parent, N_or_dk, kR, normal, origin, loop=False): Examples -------- - >>> sc = SuperCell([1, 1, 10, 90, 90, 60]) - >>> bz = BrillouinZone.param_circle(sc, 10, 0.05, [0, 0, 1], [1./3, 2./3, 0]) + >>> lattice = Lattice([1, 1, 10, 90, 90, 60]) + >>> bz = BrillouinZone.param_circle(lattice, 10, 0.05, [0, 0, 1], [1./3, 2./3, 0]) To generate a circular set of k-points in reduced coordinates (reciprocal - >>> sc = SuperCell([1, 1, 10, 90, 90, 60]) - >>> bz = BrillouinZone.param_circle(sc, 10, 0.05, [0, 0, 1], [1./3, 2./3, 0]) + >>> lattice = Lattice([1, 1, 10, 90, 90, 60]) + >>> bz = BrillouinZone.param_circle(lattice, 10, 0.05, [0, 0, 1], [1./3, 2./3, 0]) >>> bz_rec = BrillouinZone.param_circle(2*np.pi, 10, 0.05, [0, 0, 1], [1./3, 2./3, 0]) >>> bz.k[:, :] = bz_rec.k[:, :] @@ -698,7 +698,7 @@ class MonkhorstPack(BrillouinZone): ---------- parent : object or array_like An object with associated `parent.cell` and `parent.rcell` or - an array of floats which may be turned into a `SuperCell` + an array of floats which may be turned into a `Lattice` nkpt : array_like of ints a list of number of k-points along each cell direction displacement : float or array_like of float, optional @@ -718,10 +718,10 @@ class MonkhorstPack(BrillouinZone): Examples -------- - >>> sc = SuperCell(3.) - >>> MonkhorstPack(sc, 10) # 10 x 10 x 10 (with TRS) - >>> MonkhorstPack(sc, [10, 5, 5]) # 10 x 5 x 5 (with TRS) - >>> MonkhorstPack(sc, [10, 5, 5], trs=False) # 10 x 5 x 5 (without TRS) + >>> lattice = Lattice(3.) + >>> MonkhorstPack(lattice, 10) # 10 x 10 x 10 (with TRS) + >>> MonkhorstPack(lattice, [10, 5, 5]) # 10 x 5 x 5 (with TRS) + >>> MonkhorstPack(lattice, [10, 5, 5], trs=False) # 10 x 5 x 5 (without TRS) """ def __init__(self, parent, nkpt, displacement=None, size=None, centered=True, trs=True): @@ -850,15 +850,15 @@ def __init__(self, parent, nkpt, displacement=None, size=None, centered=True, tr def __str__(self): """ String representation of MonkhorstPack """ - if isinstance(self.parent, SuperCell): + if isinstance(self.parent, Lattice): p = self.parent else: - p = self.parent.sc + p = self.parent.lattice return ('{cls}{{nk: {nk:d}, size: [{size[0]:.5f} {size[1]:.5f} {size[0]:.5f}], trs: {trs},' '\n diagonal: [{diag[0]:d} {diag[1]:d} {diag[2]:d}], displacement: [{disp[0]:.5f} {disp[1]:.5f} {disp[2]:.5f}],' - '\n {sc}\n}}').format(cls=self.__class__.__name__, nk=len(self), + '\n {lattice}\n}}').format(cls=self.__class__.__name__, nk=len(self), size=self._size, trs={0: 'A', 1: 'B', 2: 'C'}.get(self._trs, 'no'), - diag=self._diag, disp=self._displ, sc=str(p).replace('\n', '\n ')) + diag=self._diag, disp=self._displ, lattice=str(p).replace('\n', '\n ')) def __getstate__(self): """ Return dictionary with the current state """ @@ -1018,23 +1018,23 @@ def replace(self, k, mp, displacement=False, as_index=False, check_vol=True): This example creates a zoomed-in view of the :math:`\Gamma`-point by replacing it with a 3x3x3 Monkhorst-Pack grid. - >>> sc = SuperCell(1.) - >>> mp = MonkhorstPack(sc, [3, 3, 3]) - >>> mp.replace([0, 0, 0], MonkhorstPack(sc, [3, 3, 3], size=1./3)) + >>> lattice = Lattice(1.) + >>> mp = MonkhorstPack(lattice, [3, 3, 3]) + >>> mp.replace([0, 0, 0], MonkhorstPack(lattice, [3, 3, 3], size=1./3)) This example creates a zoomed-in view of the :math:`\Gamma`-point by replacing it with a 4x4x4 Monkhorst-Pack grid. - >>> sc = SuperCell(1.) - >>> mp = MonkhorstPack(sc, [3, 3, 3]) - >>> mp.replace([0, 0, 0], MonkhorstPack(sc, [4, 4, 4], size=1./3)) + >>> lattice = Lattice(1.) + >>> mp = MonkhorstPack(lattice, [3, 3, 3]) + >>> mp.replace([0, 0, 0], MonkhorstPack(lattice, [4, 4, 4], size=1./3)) This example creates a zoomed-in view of the :math:`\Gamma`-point by replacing it with a 4x4x1 Monkhorst-Pack grid. - >>> sc = SuperCell(1.) - >>> mp = MonkhorstPack(sc, [3, 3, 3]) - >>> mp.replace([0, 0, 0], MonkhorstPack(sc, [4, 4, 1], size=1./3)) + >>> lattice = Lattice(1.) + >>> mp = MonkhorstPack(lattice, [3, 3, 3]) + >>> mp.replace([0, 0, 0], MonkhorstPack(lattice, [4, 4, 1], size=1./3)) Raises ------ @@ -1145,7 +1145,7 @@ class BandStructure(BrillouinZone): ---------- parent : object or array_like An object with associated `parent.cell` and `parent.rcell` or - an array of floats which may be turned into a `SuperCell` + an array of floats which may be turned into a `Lattice` points : array_like of float a list of points that are the *corners* of the path divisions : int or array_like of int @@ -1168,16 +1168,16 @@ class BandStructure(BrillouinZone): Examples -------- - >>> sc = SuperCell(10) - >>> bs = BandStructure(sc, [[0] * 3, [0.5] * 3], 200) - >>> bs = BandStructure(sc, [[0] * 3, [0.5] * 3, [1.] * 3], 200) - >>> bs = BandStructure(sc, [[0] * 3, [0.5] * 3, [1.] * 3], 200, ['Gamma', 'M', 'Gamma']) + >>> lattice = Lattice(10) + >>> bs = BandStructure(lattice, [[0] * 3, [0.5] * 3], 200) + >>> bs = BandStructure(lattice, [[0] * 3, [0.5] * 3, [1.] * 3], 200) + >>> bs = BandStructure(lattice, [[0] * 3, [0.5] * 3, [1.] * 3], 200, ['Gamma', 'M', 'Gamma']) A disconnected band structure may be created by either having a point of 0 length, or None. Note that the number of names does not contain the empty points (they are simply removed). Such a band-structure may be useful when one is not interested in a fully connected band structure. - >>> bs = BandStructure(sc, [[0, 0, 0], [0, 0.5, 0], None, [0.5, 0, 0], [0.5, 0.5, 0]], 200) + >>> bs = BandStructure(lattice, [[0, 0, 0], [0, 0.5, 0], None, [0.5, 0, 0], [0.5, 0.5, 0]], 200) """ def __init__(self, parent, *args, **kwargs): diff --git a/sisl/physics/densitymatrix.py b/sisl/physics/densitymatrix.py index 3bb8c71998..e18e03781b 100644 --- a/sisl/physics/densitymatrix.py +++ b/sisl/physics/densitymatrix.py @@ -11,8 +11,7 @@ from scipy.sparse import hstack as ss_hstack from sisl._internal import set_module -from sisl.geometry import Geometry -from sisl.supercell import SuperCell +from sisl import Geometry, Lattice import sisl._array as _a from sisl._indices import indices_le, indices_fabs_le from sisl._math_small import xyz_to_spherical_cos_phi @@ -535,14 +534,14 @@ def density(self, grid, spinor=None, tol=1e-7, eta=None): csrDM.prune() # 1. Ensure the grid has a geometry associated with it - sc = grid.sc.copy() + lattice = grid.lattice.copy() # Find the periodic directions pbc = [bc == grid.PERIODIC or geometry.nsc[i] > 1 for i, bc in enumerate(grid.bc[:, 0])] if grid.geometry is None: # Create the actual geometry that encompass the grid - ia, xyz, _ = geometry.within_inf(sc, periodic=pbc) + ia, xyz, _ = geometry.within_inf(lattice, periodic=pbc) if len(ia) > 0: - grid.set_geometry(Geometry(xyz, geometry.atoms[ia], sc=sc)) + grid.set_geometry(Geometry(xyz, geometry.atoms[ia], lattice=lattice)) # Instead of looping all atoms in the supercell we find the exact atoms # and their supercell indices. @@ -551,13 +550,13 @@ def density(self, grid, spinor=None, tol=1e-7, eta=None): # supercell by add_R in each direction. # For extremely skewed lattices this will be way too much, hence we make # them square. - o = sc.toCuboid(True) - sc = SuperCell(o._v + np.diag(2 * add_R), origin=o.origin - add_R) + o = lattice.toCuboid(True) + lattice = Lattice(o._v + np.diag(2 * add_R), origin=o.origin - add_R) # Retrieve all atoms within the grid supercell # (and the neighbours that connect into the cell) - IA, XYZ, ISC = geometry.within_inf(sc, periodic=pbc) - XYZ -= grid.sc.origin.reshape(1, 3) + IA, XYZ, ISC = geometry.within_inf(lattice, periodic=pbc) + XYZ -= grid.lattice.origin.reshape(1, 3) # Retrieve progressbar eta = progressbar(len(IA), f"{self.__class__.__name__}.density", "atom", eta) diff --git a/sisl/physics/dynamicalmatrix.py b/sisl/physics/dynamicalmatrix.py index fbb37d6cf8..ea98562efa 100644 --- a/sisl/physics/dynamicalmatrix.py +++ b/sisl/physics/dynamicalmatrix.py @@ -206,7 +206,7 @@ def apply_newton(self): no = self.no d_uc = lil_matrix((no, no), dtype=dyn_sc.dtype) - for i, _ in self.sc: + for i, _ in self.lattice: d_uc[:, :] += dyn_sc[:, i*no: (i+1)*no] # A CSC matrix is faster to slice for columns diff --git a/sisl/physics/electron.py b/sisl/physics/electron.py index b6d5eb0cce..4c249b275c 100644 --- a/sisl/physics/electron.py +++ b/sisl/physics/electron.py @@ -54,7 +54,7 @@ from scipy.sparse import identity, csr_matrix, hstack, isspmatrix from sisl._internal import set_module -from sisl import units, constant, Grid, SuperCell, Geometry +from sisl import units, constant, Grid, Lattice, Geometry from sisl._indices import indices_le from sisl.oplist import oplist from sisl._math_small import xyz_to_spherical_cos_phi @@ -1098,7 +1098,7 @@ def wavefunction(v, grid, geometry=None, k=None, spinor=0, spin=None, eta=None): raise SislError("wavefunction: did not find a usable Geometry through keywords or the Grid!") # Ensure coordinates are in the primary unit-cell, regardless of origin etc. geometry = geometry.copy() - geometry.xyz = (geometry.fxyz % 1) @ geometry.sc.cell + geometry.xyz = (geometry.fxyz % 1) @ geometry.lattice.cell # In case the user has passed several vectors we sum them to plot the summed state if v.ndim == 2: @@ -1142,7 +1142,7 @@ def wavefunction(v, grid, geometry=None, k=None, spinor=0, spin=None, eta=None): # Extract sub variables used throughout the loop shape = _a.asarrayi(grid.shape) dcell = grid.dcell - ic_shape = grid.sc.icell * shape.reshape(3, 1) + ic_shape = grid.lattice.icell * shape.reshape(3, 1) # Convert the geometry (hosting the wavefunction coefficients) coordinates into # grid-fractionals X grid-shape to get index-offsets in the grid for the geometry @@ -1193,7 +1193,7 @@ def idx2spherical(ix, iy, iz, offset, dc, R): del ctheta_sphi, stheta_sphi, cphi, idx, rxyz, nrxyz # Fast loop (only per specie) - origin = grid.sc.origin.reshape(1, 3) + origin = grid.lattice.origin.reshape(1, 3) idx_mm = _a.emptyd([geometry.na, 2, 3]) all_negative_R = True for atom, ia in geometry.atoms.iter(True): @@ -1226,14 +1226,14 @@ def idx2spherical(ix, iy, iz, offset, dc, R): # In case this grid does not have a Geometry associated # We can *perhaps* easily attach a geometry with the given # atoms in the unit-cell - sc = grid.sc.copy() + lattice = grid.lattice.copy() # Find the periodic directions pbc = [bc == grid.PERIODIC or geometry.nsc[i] > 1 for i, bc in enumerate(grid.bc[:, 0])] if grid.geometry is None: # Create the actual geometry that encompass the grid - ia, xyz, _ = geometry.within_inf(sc, periodic=pbc) + ia, xyz, _ = geometry.within_inf(lattice, periodic=pbc) if len(ia) > 0: - grid.set_geometry(Geometry(xyz, geometry.atoms[ia], sc=sc)) + grid.set_geometry(Geometry(xyz, geometry.atoms[ia], lattice=lattice)) # Instead of looping all atoms in the supercell we find the exact atoms # and their supercell indices. @@ -1243,17 +1243,17 @@ def idx2spherical(ix, iy, iz, offset, dc, R): # For extremely skewed lattices this will be way too much, hence we make # them square. - o = sc.toCuboid(True) - sc = SuperCell(o._v + np.diag(2 * add_R), origin=o.origin - add_R) + o = lattice.toCuboid(True) + lattice = Lattice(o._v + np.diag(2 * add_R), origin=o.origin - add_R) # Retrieve all atoms within the grid supercell # (and the neighbours that connect into the cell) # Note that we cannot pass the "moved" origin because then ISC would be wrong - IA, XYZ, ISC = geometry.within_inf(sc, periodic=pbc) + IA, XYZ, ISC = geometry.within_inf(lattice, periodic=pbc) # We need to revert the grid supercell origin as that is not subtracted in the `within_inf` returned # coordinates (and the below loop expects positions with respect to the origin of the plotting # grid). - XYZ -= grid.sc.origin.reshape(1, 3) + XYZ -= grid.lattice.origin.reshape(1, 3) phk = k * 2 * np.pi phase = 1 diff --git a/sisl/physics/self_energy.py b/sisl/physics/self_energy.py index a38e2408a1..4362b118a4 100644 --- a/sisl/physics/self_energy.py +++ b/sisl/physics/self_energy.py @@ -194,7 +194,7 @@ def __init__(self, spgeom, infinite, eta=1e-4): raise ValueError(f"{self.__class__.__name__} infinite keyword does not end with `A`, `B` or `C`.") # Check that the Hamiltonian does have a non-zero V along the semi-infinite direction - if spgeom.geometry.sc.nsc[self.semi_inf] == 1: + if spgeom.geometry.lattice.nsc[self.semi_inf] == 1: warn("Creating a semi-infinite self-energy with no couplings along the semi-infinite direction") # Finalize the setup by calling the class specific routine @@ -229,7 +229,7 @@ def _setup(self, spgeom): # Create spgeom0 and spgeom1 self.spgeom0 = spgeom.copy() - nsc = np.copy(spgeom.geometry.sc.nsc) + nsc = np.copy(spgeom.geometry.lattice.nsc) nsc[self.semi_inf] = 1 self.spgeom0.set_nsc(nsc) @@ -245,14 +245,14 @@ def _setup(self, spgeom): "These values will be forced to 0 as the principal cell-interaction is a requirement") # I.e. we will delete all interactions that are un-important - n_s = self.spgeom1.geometry.sc.n_s + n_s = self.spgeom1.geometry.lattice.n_s n = self.spgeom1.shape[0] # Figure out the matrix columns we should set to zero nsc = [None] * 3 nsc[self.semi_inf] = self.semi_inf_dir # Get all supercell indices that we should delete idx = np.delete(_a.arangei(n_s), - _a.arrayi(self.spgeom1.geometry.sc.sc_index(nsc))) * n + _a.arrayi(self.spgeom1.geometry.lattice.sc_index(nsc))) * n cols = _a.array_arange(idx, idx + n) # Delete all values in columns, but keep them to retain the supercell information @@ -780,7 +780,7 @@ def real_space_coupling(self, ret_indices=False): # Remove all inner-cell couplings (0, 0, 0) to figure out the # elements that couple out of the real-space region n = PC.shape[0] - idx = g.sc.sc_index([0, 0, 0]) + idx = g.lattice.sc_index([0, 0, 0]) cols = _a.arangei(idx * n, (idx + 1) * n) csr = PC._csr.copy([0]) # we just want the sparse pattern, so forget about the other elements csr.delete_columns(cols, keep_shape=True) @@ -841,11 +841,11 @@ def initialize(self): if self._options["bz"] is None: # Update the integration grid # Note this integration grid is based on the big system. - sc = self.parent.sc * self._unfold - rcell = fnorm(sc.rcell)[k_ax] + lattice = self.parent.lattice * self._unfold + rcell = fnorm(lattice.rcell)[k_ax] nk = _a.onesi(3) nk[k_ax] = np.ceil(self._options["dk"] * rcell).astype(np.int32) - self._options["bz"] = MonkhorstPack(sc, nk, trs=self._options["trs"]) + self._options["bz"] = MonkhorstPack(lattice, nk, trs=self._options["trs"]) def self_energy(self, E, k=(0, 0, 0), bulk=False, coupling=False, dtype=None, **kwargs): r""" Calculate the real-space self-energy @@ -1167,7 +1167,7 @@ def __init__(self, semi, surface, k_axes, unfold=(1, 1, 1), **options): self.semi = semi self.surface = surface - if not self.semi.sc.parallel(surface.sc): + if not self.semi.lattice.parallel(surface.lattice): raise ValueError(f"{self.__class__.__name__} requires semi and surface to have parallel " "lattice vectors.") @@ -1355,7 +1355,7 @@ def get_connections(PC, nrep=1, na=0, na_off=0): # Remove all inner-cell couplings (0, 0, 0) to figure out the # elements that couple out of the real-space region n = PC.shape[0] - idx = g.sc.sc_index([0, 0, 0]) + idx = g.lattice.sc_index([0, 0, 0]) cols = _a.arangei(idx * n, (idx + 1) * n) csr = PC._csr.copy([0]) # we just want the sparse pattern, so forget about the other elements csr.delete_columns(cols, keep_shape=True) @@ -1436,11 +1436,11 @@ def initialize(self): if self._options["bz"] is None: # Update the integration grid # Note this integration grid is based on the big system. - sc = self.surface.sc * self._unfold - rcell = fnorm(sc.rcell)[self._k_axes] + lattice = self.surface.lattice * self._unfold + rcell = fnorm(lattice.rcell)[self._k_axes] nk = _a.onesi(3) nk[self._k_axes] = np.ceil(self._options["dk"] * rcell).astype(np.int32) - self._options["bz"] = MonkhorstPack(sc, nk, trs=self._options["trs"]) + self._options["bz"] = MonkhorstPack(lattice, nk, trs=self._options["trs"]) def self_energy(self, E, k=(0, 0, 0), bulk=False, coupling=False, dtype=None, **kwargs): r""" Calculate real-space surface self-energy diff --git a/sisl/physics/sparse.py b/sisl/physics/sparse.py index 1249365ae5..9b74fe4eb0 100644 --- a/sisl/physics/sparse.py +++ b/sisl/physics/sparse.py @@ -215,7 +215,7 @@ def _Pk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr", _dim=0): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_k(gauge, self, _dim, self.sc, k, dtype, format) + return matrix_k(gauge, self, _dim, self.lattice, k, dtype, format) def _dPk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr", _dim=0): r""" Sparse matrix (``scipy.sparse.csr_matrix``) at `k` differentiated with respect to `k` for a polarized system @@ -230,7 +230,7 @@ def _dPk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr", _dim=0): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_dk(gauge, self, _dim, self.sc, k, dtype, format) + return matrix_dk(gauge, self, _dim, self.lattice, k, dtype, format) def _ddPk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr", _dim=0): r""" Sparse matrix (``scipy.sparse.csr_matrix``) at `k` double differentiated with respect to `k` for a polarized system @@ -245,7 +245,7 @@ def _ddPk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr", _dim=0): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_ddk(gauge, self, _dim, self.sc, k, dtype, format) + return matrix_ddk(gauge, self, _dim, self.lattice, k, dtype, format) def Sk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr", *args, **kwargs): # pylint: disable=E0202 r""" Setup the overlap matrix for a given k-point @@ -416,7 +416,7 @@ def _dSk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_dk_nc_diag(gauge, self, self.S_idx, self.sc, k, dtype, format) + return matrix_dk_nc_diag(gauge, self, self.S_idx, self.lattice, k, dtype, format) def ddSk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr", *args, **kwargs): # pylint: disable=E0202 r""" Setup the double :math:`k`-derivatie of the overlap matrix for a given k-point @@ -496,7 +496,7 @@ def _ddSk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_ddk_nc_diag(gauge, self, self.S_idx, self.sc, k, dtype, format) + return matrix_ddk_nc_diag(gauge, self, self.S_idx, self.lattice, k, dtype, format) def eig(self, k=(0, 0, 0), gauge="R", eigvals_only=True, **kwargs): r""" Returns the eigenvalues of the physical quantity (using the non-Hermitian solver) @@ -875,7 +875,7 @@ def _Pk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_k_nc(gauge, self, self.sc, k, dtype, format) + return matrix_k_nc(gauge, self, self.lattice, k, dtype, format) def _Pk_spin_orbit(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): r""" Sparse matrix (``scipy.sparse.csr_matrix``) at `k` for a spin-orbit system @@ -890,7 +890,7 @@ def _Pk_spin_orbit(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_k_so(gauge, self, self.sc, k, dtype, format) + return matrix_k_so(gauge, self, self.lattice, k, dtype, format) def _dPk_unpolarized(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): r""" Tuple of sparse matrix (``scipy.sparse.csr_matrix``) at `k`, differentiated with respect to `k` @@ -935,7 +935,7 @@ def _dPk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_dk_nc(gauge, self, self.sc, k, dtype, format) + return matrix_dk_nc(gauge, self, self.lattice, k, dtype, format) def _dPk_spin_orbit(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): r""" Tuple of sparse matrix (``scipy.sparse.csr_matrix``) at `k` for a non-collinear system, differentiated with respect to `k` @@ -950,7 +950,7 @@ def _dPk_spin_orbit(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_dk_so(gauge, self, self.sc, k, dtype, format) + return matrix_dk_so(gauge, self, self.lattice, k, dtype, format) def _ddPk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): r""" Tuple of sparse matrix (``scipy.sparse.csr_matrix``) at `k` for a non-collinear system, differentiated with respect to `k` twice @@ -965,7 +965,7 @@ def _ddPk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_ddk_nc(gauge, self, self.sc, k, dtype, format) + return matrix_ddk_nc(gauge, self, self.lattice, k, dtype, format) def _ddPk_spin_orbit(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): r""" Tuple of sparse matrix (``scipy.sparse.csr_matrix``) at `k` for a non-collinear system, differentiated with respect to `k` @@ -980,7 +980,7 @@ def _ddPk_spin_orbit(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_ddk_so(gauge, self, self.sc, k, dtype, format) + return matrix_ddk_so(gauge, self, self.lattice, k, dtype, format) def _Sk(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): r""" Overlap matrix in a ``scipy.sparse.csr_matrix`` at `k`. @@ -1009,7 +1009,7 @@ def _Sk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_k_nc_diag(gauge, self, self.S_idx, self.sc, k, dtype, format) + return matrix_k_nc_diag(gauge, self, self.S_idx, self.lattice, k, dtype, format) def _dSk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): r""" Overlap matrix (``scipy.sparse.csr_matrix``) at `k` for a non-collinear system @@ -1024,7 +1024,7 @@ def _dSk_non_colinear(self, k=(0, 0, 0), dtype=None, gauge="R", format="csr"): chosen gauge """ k = _a.asarrayd(k).ravel() - return matrix_dk_nc_diag(gauge, self, self.S_idx, self.sc, k, dtype, format) + return matrix_dk_nc_diag(gauge, self, self.S_idx, self.lattice, k, dtype, format) def eig(self, k=(0, 0, 0), gauge="R", eigvals_only=True, **kwargs): r""" Returns the eigenvalues of the physical quantity (using the non-Hermitian solver) diff --git a/sisl/physics/tests/test_brillouinzone.py b/sisl/physics/tests/test_brillouinzone.py index 1fdab5fde4..df21a92105 100644 --- a/sisl/physics/tests/test_brillouinzone.py +++ b/sisl/physics/tests/test_brillouinzone.py @@ -8,7 +8,7 @@ import numpy as np from sisl import SislError, geom -from sisl import Geometry, Atom, SuperCell, SuperCellChild +from sisl import Geometry, Atom, Lattice, LatticeChild from sisl import BrillouinZone, BandStructure from sisl import MonkhorstPack @@ -20,16 +20,16 @@ def setup(): class t(): def __init__(self): - self.s1 = SuperCell(1, nsc=[3, 3, 1]) - self.s2 = SuperCell([2, 2, 10, 90, 90, 60], [5, 5, 1]) + self.s1 = Lattice(1, nsc=[3, 3, 1]) + self.s2 = Lattice([2, 2, 10, 90, 90, 60], [5, 5, 1]) return t() class TestBrillouinZone: def setUp(self, setup): - setup.s1 = SuperCell(1, nsc=[3, 3, 1]) - setup.s2 = SuperCell([2, 2, 10, 90, 90, 60], [5, 5, 1]) + setup.s1 = Lattice(1, nsc=[3, 3, 1]) + setup.s2 = Lattice([2, 2, 10, 90, 90, 60], [5, 5, 1]) def test_bz1(self, setup): bz = BrillouinZone(1.) @@ -67,11 +67,11 @@ def test_weight_automatic(self, setup): def test_volume_self(self): bz = BrillouinZone(1.) assert bz.volume(True)[1] == 0 - bz = BrillouinZone(SuperCell(1, nsc=[3, 1, 1])) + bz = BrillouinZone(Lattice(1, nsc=[3, 1, 1])) assert bz.volume(True)[1] == 1 - bz = BrillouinZone(SuperCell(1, nsc=[3, 3, 1])) + bz = BrillouinZone(Lattice(1, nsc=[3, 3, 1])) assert bz.volume(True)[1] == 2 - bz = BrillouinZone(SuperCell(1, nsc=[3, 3, 3])) + bz = BrillouinZone(Lattice(1, nsc=[3, 3, 3])) assert bz.volume(True)[1] == 3 def test_volume_direct(self): @@ -94,9 +94,9 @@ def test_to_reduced(self, setup): assert np.allclose(rec, k) def test_class1(self, setup): - class Test(SuperCellChild): - def __init__(self, sc): - self.set_supercell(sc) + class Test(LatticeChild): + def __init__(self, lattice): + self.set_lattice(lattice) def eigh(self, k, *args, **kwargs): return np.arange(3) def eig(self, k, *args, **kwargs): @@ -108,9 +108,9 @@ def eig(self, k, *args, **kwargs): assert np.allclose(bz_arr.eig(), np.arange(3)-1) def test_class2(self, setup): - class Test(SuperCellChild): - def __init__(self, sc): - self.set_supercell(sc) + class Test(LatticeChild): + def __init__(self, lattice): + self.set_lattice(lattice) def eigh(self, k, *args, **kwargs): return np.arange(3) def eig(self, k, *args, **kwargs): @@ -167,7 +167,7 @@ def test_pickle(self, setup): def test_param_circle(self, n): bz = BrillouinZone.param_circle(1, 10, 0.1, n, [1/2] * 3) assert len(bz) == 10 - sc = SuperCell(1) + sc = Lattice(1) bz_loop = BrillouinZone.param_circle(sc, 10, 0.1, n, [1/2] * 3, True) assert len(bz_loop) == 10 assert not np.allclose(bz.k, bz_loop.k) @@ -244,13 +244,13 @@ def test_merge_scales_scalar(self): class TestMonkhorstPack: def setUp(self, setup): - setup.s1 = SuperCell(1, nsc=[3, 3, 1]) - setup.s2 = SuperCell([2, 2, 10, 90, 90, 60], [5, 5, 1]) + setup.s1 = Lattice(1, nsc=[3, 3, 1]) + setup.s2 = Lattice([2, 2, 10, 90, 90, 60], [5, 5, 1]) def test_class(self, setup): - class Test(SuperCellChild): - def __init__(self, sc): - self.set_supercell(sc) + class Test(LatticeChild): + def __init__(self, lattice): + self.set_lattice(lattice) def eigh(self, k, *args, **kwargs): return np.arange(3) def eig(self, k, *args, **kwargs): @@ -278,9 +278,9 @@ def test_pickle(self, setup): @pytest.mark.parametrize("N", [2, 3, 4, 5, 7]) @pytest.mark.parametrize("centered", [True, False]) def test_asgrid(self, setup, N, centered): - class Test(SuperCellChild): - def __init__(self, sc): - self.set_supercell(sc) + class Test(LatticeChild): + def __init__(self, lattice): + self.set_lattice(lattice) def eigh(self, k, *args, **kwargs): return np.arange(3) bz = MonkhorstPack(Test(setup.s1), [2] * 3).apply.grid @@ -301,9 +301,9 @@ def eigh(self, k, *args, **kwargs): assert np.allclose(grid.shape, shape) def test_asgrid_fail(self, setup): - class Test(SuperCellChild): - def __init__(self, sc): - self.set_supercell(sc) + class Test(LatticeChild): + def __init__(self, lattice): + self.set_lattice(lattice) def eigh(self, k, *args, **kwargs): return np.arange(3) bz = MonkhorstPack(Test(setup.s1), [2] * 3, displacement=[0.1] * 3).apply.grid @@ -662,8 +662,8 @@ def test_in_primitive(self): class TestBandStructure: def setUp(self, setup): - setup.s1 = SuperCell(1, nsc=[3, 3, 1]) - setup.s2 = SuperCell([2, 2, 10, 90, 90, 60], [5, 5, 1]) + setup.s1 = Lattice(1, nsc=[3, 3, 1]) + setup.s2 = Lattice([2, 2, 10, 90, 90, 60], [5, 5, 1]) def test_pbz1(self, setup): bz = BandStructure(setup.s1, [[0]*3, [.5]*3], 300) diff --git a/sisl/physics/tests/test_density_matrix.py b/sisl/physics/tests/test_density_matrix.py index 2dca8adfe8..ec4f20b246 100644 --- a/sisl/physics/tests/test_density_matrix.py +++ b/sisl/physics/tests/test_density_matrix.py @@ -6,7 +6,7 @@ import math as m import numpy as np -from sisl import Geometry, Atom, SphericalOrbital, AtomicOrbital, SuperCell +from sisl import Geometry, Atom, SphericalOrbital, AtomicOrbital, Lattice from sisl import Grid, Spin from sisl import DensityMatrix @@ -17,9 +17,9 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) n = 60 rf = np.linspace(0, bond * 1.01, n) @@ -28,7 +28,7 @@ def __init__(self): C = Atom(6, orb.toAtomicOrbital()) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.D = DensityMatrix(self.g) self.DS = DensityMatrix(self.g, orthogonal=False) @@ -130,7 +130,7 @@ def test_rho1(self, setup): def test_rho2(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -141,7 +141,7 @@ def test_rho2(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g) D.construct([[0.1, bond + 0.01], [1., 0.1]]) grid = Grid(0.2, geometry=D.geometry) @@ -174,7 +174,7 @@ def test_rho2(self, setup): def test_orbital_momentum(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -182,7 +182,7 @@ def test_orbital_momentum(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('SO')) D.construct([[0.1, bond + 0.01], [(1., 0.5, 0.01, 0.01, 0.01, 0.01, 0., 0.), (0.1, 0.1, 0.1, 0.1, 0., 0., 0., 0.)]]) D.orbital_momentum("atom") @@ -191,7 +191,7 @@ def test_orbital_momentum(self, setup): def test_spin_align_pol(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -199,7 +199,7 @@ def test_spin_align_pol(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('p')) D.construct([[0.1, bond + 0.01], [(1., 0.5), (0.1, 0.2)]]) D_mull = D.mulliken() @@ -216,7 +216,7 @@ def test_spin_align_pol(self, setup): def test_spin_align_nc(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -224,7 +224,7 @@ def test_spin_align_nc(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('nc')) D.construct([[0.1, bond + 0.01], [(1., 0.5, 0.01, 0.01), (0.1, 0.2, 0.1, 0.1)]]) D_mull = D.mulliken() @@ -238,7 +238,7 @@ def test_spin_align_nc(self, setup): def test_spin_align_so(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -246,7 +246,7 @@ def test_spin_align_so(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('SO')) D.construct([[0.1, bond + 0.01], [(1., 0.5, 0.01, 0.01, 0.01, 0.01, 0.2, 0.2), (0.1, 0.2, 0.1, 0.1, 0., 0.1, 0.2, 0.3)]]) D_mull = D.mulliken() @@ -259,7 +259,7 @@ def test_spin_align_so(self, setup): def test_spin_rotate_pol(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -267,7 +267,7 @@ def test_spin_rotate_pol(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('p')) D.construct([[0.1, bond + 0.01], [(1., 0.5), (0.1, 0.2)]]) @@ -284,7 +284,7 @@ def test_spin_rotate_pol(self, setup): def test_spin_rotate_nc(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -292,7 +292,7 @@ def test_spin_rotate_nc(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('nc')) D.construct([[0.1, bond + 0.01], [(1., 0.5, 0.01, 0.01), (0.1, 0.2, 0.1, 0.1)]]) @@ -308,7 +308,7 @@ def test_spin_rotate_nc(self, setup): def test_spin_rotate_so(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -316,7 +316,7 @@ def test_spin_rotate_so(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('SO')) D.construct([[0.1, bond + 0.01], [(1., 0.5, 0.01, 0.01, 0.01, 0.01, 0.2, 0.2), (0.1, 0.2, 0.1, 0.1, 0., 0.1, 0.2, 0.3)]]) D_mull = D.mulliken() @@ -334,14 +334,14 @@ def test_rho_eta(self, setup): def test_rho_smaller_grid1(self, setup): D = setup.D.copy() D.construct(setup.func) - sc = setup.D.geometry.cell.copy() / 2 - grid = Grid(0.2, geometry=setup.D.geometry.copy(), sc=sc) + lattice = setup.D.geometry.cell.copy() / 2 + grid = Grid(0.2, geometry=setup.D.geometry.copy(), lattice=lattice) D.density(grid) def test_rho_fail_p(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -352,7 +352,7 @@ def test_rho_fail_p(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('P')) D.construct([[0.1, bond + 0.01], [(1., 0.5), (0.1, 0.1)]]) @@ -363,7 +363,7 @@ def test_rho_fail_p(self, setup): def test_rho_fail_nc(self, setup): bond = 1.42 sq3h = 3.**.5 * 0.5 - sc = SuperCell(np.array([[1.5, sq3h, 0.], + lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) @@ -374,7 +374,7 @@ def test_rho_fail_nc(self, setup): C = Atom(6, orb) g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=sc) + atoms=C, lattice=lattice) D = DensityMatrix(g, spin=Spin('NC')) D.construct([[0.1, bond + 0.01], [(1., 0.5, 0.01, 0.01), (0.1, 0.1, 0.1, 0.1)]]) diff --git a/sisl/physics/tests/test_dynamical_matrix.py b/sisl/physics/tests/test_dynamical_matrix.py index d0ea9ec337..ee62c7dae9 100644 --- a/sisl/physics/tests/test_dynamical_matrix.py +++ b/sisl/physics/tests/test_dynamical_matrix.py @@ -6,7 +6,7 @@ import math as m import numpy as np -from sisl import Geometry, Atom, SuperCell, DynamicalMatrix +from sisl import Geometry, Atom, Lattice, DynamicalMatrix pytestmark = [pytest.mark.physics, pytest.mark.dynamicalmatrix] @@ -18,14 +18,14 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) C = Atom(Z=6, R=[bond * 1.01] * 3) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.D = DynamicalMatrix(self.g) def func(D, ia, idxs, idxs_xyz): diff --git a/sisl/physics/tests/test_energy_density_matrix.py b/sisl/physics/tests/test_energy_density_matrix.py index 417c4a9ab1..e0e78541b9 100644 --- a/sisl/physics/tests/test_energy_density_matrix.py +++ b/sisl/physics/tests/test_energy_density_matrix.py @@ -6,7 +6,7 @@ import math as m import numpy as np -from sisl import Geometry, Atom, SuperCell, EnergyDensityMatrix, Spin +from sisl import Geometry, Atom, Lattice, EnergyDensityMatrix, Spin @pytest.fixture @@ -15,14 +15,14 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) C = Atom(Z=6, R=[bond * 1.01] * 3) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.E = EnergyDensityMatrix(self.g) self.ES = EnergyDensityMatrix(self.g, orthogonal=False) diff --git a/sisl/physics/tests/test_feature.py b/sisl/physics/tests/test_feature.py index d0ae54629a..d455dae722 100644 --- a/sisl/physics/tests/test_feature.py +++ b/sisl/physics/tests/test_feature.py @@ -5,7 +5,7 @@ import numpy as np -from sisl import Geometry, Atom, SuperCell, Hamiltonian +from sisl import Geometry, Atom, Lattice, Hamiltonian from sisl.physics import yield_manifolds @@ -13,7 +13,7 @@ def test_yield_manifolds_eigenvalues(): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell([10, 1, 5.], nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice([10, 1, 5.], nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64) H.construct([(0.1, 1.5), (1., 0.1)]) diff --git a/sisl/physics/tests/test_hamiltonian.py b/sisl/physics/tests/test_hamiltonian.py index e0ba8d94ee..c42edafed3 100644 --- a/sisl/physics/tests/test_hamiltonian.py +++ b/sisl/physics/tests/test_hamiltonian.py @@ -9,7 +9,7 @@ from scipy.linalg import block_diag from scipy.sparse import SparseEfficiencyWarning, isspmatrix -from sisl import Geometry, Atom, SuperCell, Hamiltonian, Spin, BandStructure, MonkhorstPack, BrillouinZone +from sisl import Geometry, Atom, Lattice, Hamiltonian, Spin, BandStructure, MonkhorstPack, BrillouinZone from sisl import get_distribution from sisl import oplist from sisl import Grid, SphericalOrbital, SislError @@ -26,21 +26,21 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) C = Atom(Z=6, R=[bond * 1.01]) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.H = Hamiltonian(self.g) self.HS = Hamiltonian(self.g, orthogonal=False) C = Atom(Z=6, R=[bond * 1.01] * 2) self.g2 = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.H2 = Hamiltonian(self.g2) self.HS2 = Hamiltonian(self.g2, orthogonal=False) return t() @@ -225,7 +225,7 @@ def test_Hk_format(self, setup, k): @pytest.mark.parametrize("spin", ["unpolarized", "polarized", "non-collinear", "spin-orbit"]) @pytest.mark.parametrize("dtype", [np.complex64, np.complex128]) def test_format_sc(self, orthogonal, gauge, spin, dtype): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell([10, 1, 5.], nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice([10, 1, 5.], nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, orthogonal=orthogonal, spin=Spin(spin)) nd = H._csr._D.shape[-1] # this will correctly account for the double size for NC/SOC @@ -244,7 +244,7 @@ def test_format_sc(self, orthogonal, gauge, spin, dtype): allclose = partial(np.allclose, atol=atol, rtol=rtol) H = (H + H.transpose(hermitian=True)) / 2 - n_s = H.geometry.sc.n_s + n_s = H.geometry.lattice.n_s for k in [[0, 0, 0], [0.15, 0.1, 0.05]]: for attr, kwargs in [("Hk", {"gauge": gauge}), ("Sk", {})]: @@ -316,7 +316,7 @@ def test_fromsp3(self, setup): assert H.spsame(h) def test_op1(self, setup): - g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), sc=[100]) + g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), lattice=[100]) H = Hamiltonian(g, dtype=np.int32) for i in range(10): j = range(i*4, i*4+3) @@ -353,7 +353,7 @@ def test_op1(self, setup): assert H[1, jj] == 0 def test_op2(self, setup): - g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), sc=[100]) + g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), lattice=[100]) H = Hamiltonian(g, dtype=np.int32) for i in range(10): j = range(i*4, i*4+3) @@ -409,7 +409,7 @@ def test_op2(self, setup): assert s[1, jj] == 0 def test_op3(self, setup): - g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), sc=[100]) + g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), lattice=[100]) H = Hamiltonian(g, dtype=np.int32) Hc = H.copy() del Hc @@ -452,7 +452,7 @@ def test_op3(self, setup): assert h.dtype == np.complex128 def test_op4(self, setup): - g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), sc=[100]) + g = Geometry([[i, 0, 0] for i in range(100)], Atom(6, R=1.01), lattice=[100]) H = Hamiltonian(g, dtype=np.int32) # Create initial stuff for i in range(10): @@ -789,7 +789,7 @@ def test_berry_phase(self, setup): def test_berry_phase_fail_sc(self, setup): g = setup.g.tile(2, 0).tile(2, 1).tile(2, 2) H = Hamiltonian(g) - bz = BandStructure.param_circle(H.geometry.sc, 20, 0.01, [0, 0, 1], [1/3] * 3) + bz = BandStructure.param_circle(H.geometry.lattice, 20, 0.01, [0, 0, 1], [1/3] * 3) with pytest.raises(SislError): berry_phase(bz) @@ -823,7 +823,7 @@ def test_berry_phase_orthogonal_spin_down(self, setup): def test_berry_phase_zak_x_topological(self): # SSH model, topological cell # |t2| < |t1| - g = Geometry([[0, 0, 0], [1.2, 0, 0]], Atom(1, 1.001), sc=[2, 10, 10]) + g = Geometry([[0, 0, 0], [1.2, 0, 0]], Atom(1, 1.001), lattice=[2, 10, 10]) g.set_nsc([3, 1, 1]) H = Hamiltonian(g) H.construct([(0.1, 1.0, 1.5), (0, 1., 0.5)]) @@ -838,7 +838,7 @@ def func(parent, N, i): def test_berry_phase_zak_x_topological_non_orthogonal(self): # SSH model, topological cell # |t2| < |t1| - g = Geometry([[0, 0, 0], [1.2, 0, 0]], Atom(1, 1.001), sc=[2, 10, 10]) + g = Geometry([[0, 0, 0], [1.2, 0, 0]], Atom(1, 1.001), lattice=[2, 10, 10]) g.set_nsc([3, 1, 1]) H = Hamiltonian(g, orthogonal=False) H.construct([(0.1, 1.0, 1.5), ((0, 1), (1., 0.25), (0.5, 0.1))]) @@ -853,7 +853,7 @@ def func(parent, N, i): def test_berry_phase_zak_x_trivial(self): # SSH model, trivial cell # |t2| > |t1| - g = Geometry([[0, 0, 0], [1.2, 0, 0]], Atom(1, 1.001), sc=[2, 10, 10]) + g = Geometry([[0, 0, 0], [1.2, 0, 0]], Atom(1, 1.001), lattice=[2, 10, 10]) g.set_nsc([3, 1, 1]) H = Hamiltonian(g) H.construct([(0.1, 1.0, 1.5), (0, 0.5, 1.)]) @@ -867,7 +867,7 @@ def func(parent, N, i): def test_berry_phase_zak_y(self): # SSH model, topological cell - g = Geometry([[0, -.6, 0], [0, 0.6, 0]], Atom(1, 1.001), sc=[10, 2, 10]) + g = Geometry([[0, -.6, 0], [0, 0.6, 0]], Atom(1, 1.001), lattice=[10, 2, 10]) g.set_nsc([1, 3, 1]) H = Hamiltonian(g) H.construct([(0.1, 1.0, 1.5), (0, 1., 0.5)]) @@ -881,7 +881,7 @@ def func(parent, N, i): def test_berry_phase_zak_offset(self): # SSH model, topological cell - g = Geometry([[0., 0, 0], [1.2, 0, 0]], Atom(1, 1.001), sc=[2, 10, 10]) + g = Geometry([[0., 0, 0], [1.2, 0, 0]], Atom(1, 1.001), lattice=[2, 10, 10]) g.set_nsc([3, 1, 1]) H = Hamiltonian(g) H.construct([(0.1, 1.0, 1.5), (0, 1., 0.5)]) @@ -894,7 +894,7 @@ def func(parent, N, i): def test_berry_phase_method_fail(self): # wrong method keyword - g = Geometry([[-.6, 0, 0], [0.6, 0, 0]], Atom(1, 1.001), sc=[2, 10, 10]) + g = Geometry([[-.6, 0, 0], [0.6, 0, 0]], Atom(1, 1.001), lattice=[2, 10, 10]) g.set_nsc([3, 1, 1]) H = Hamiltonian(g) def func(parent, N, i): @@ -1240,7 +1240,7 @@ def test_coop_sp_vs_np(self, setup): assert np.allclose(c_sp.toarray(), c_np) def test_spin1(self, setup): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.int32, spin=Spin.POLARIZED) for i in range(10): j = range(i*2, i*2+3) @@ -1253,7 +1253,7 @@ def test_spin1(self, setup): assert H.spsame(H2) def test_spin2(self, setup): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.int32, spin=Spin.POLARIZED) for i in range(10): j = range(i*2, i*2+3) @@ -1278,7 +1278,7 @@ def test_spin2(self, setup): assert H.spsame(H2) def test_transform_up(self): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, spin=Spin.UNPOLARIZED) for i in range(10): H[0, i] = i + 0.1 @@ -1297,7 +1297,7 @@ def test_transform_up(self): assert np.abs(Hcsr[0] - Ht.tocsr(1)).sum() == 0 def test_transform_up_nonortho(self): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, spin=Spin.UNPOLARIZED, orthogonal=False) for i in range(10): H[0, i] = (i + 0.1, 1.) @@ -1324,7 +1324,7 @@ def test_transform_up_nonortho(self): assert np.abs(Hcsr[-1] - Ht.tocsr(-1)).sum() == 0 def test_transform_down(self): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, spin=Spin.SPINORBIT) for i in range(10): for j in range(8): @@ -1345,7 +1345,7 @@ def test_transform_down(self): assert np.abs(Hcsr[3] - Ht.tocsr(3)).sum() == 0 def test_transform_down_nonortho(self): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, spin=Spin.SPINORBIT, orthogonal=False) for i in range(10): for j in range(8): @@ -1371,7 +1371,7 @@ def test_transform_down_nonortho(self): @pytest.mark.parametrize("k", [[0, 0, 0], [0.1, 0, 0]]) def test_spin_squared(self, setup, k): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(1, nsc=[3, 1, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(1, nsc=[3, 1, 1])) H = Hamiltonian(g, spin=Spin.POLARIZED) H.construct(([0.1, 1.1], [[0, 0.1], [1, 1.1]])) H[0, 0] = (0.1, 0.) @@ -1411,7 +1411,7 @@ def test_spin_squared(self, setup, k): assert len(sdn) == 1 def test_non_colinear_orthogonal(self, setup): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, spin=Spin.NONCOLINEAR) for i in range(10): j = range(i*2, i*2+3) @@ -1482,7 +1482,7 @@ def test_non_colinear_orthogonal(self, setup): es.change_gauge('r') def test_non_colinear_non_orthogonal(self): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, orthogonal=False, spin=Spin.NONCOLINEAR) for i in range(10): j = range(i*2, i*2+3) @@ -1545,7 +1545,7 @@ def test_non_colinear_non_orthogonal(self): es.change_gauge('r') def test_spin_orbit_orthogonal(self): - g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), sc=SuperCell(100, nsc=[3, 3, 1])) + g = Geometry([[i, 0, 0] for i in range(10)], Atom(6, R=1.01), lattice=Lattice(100, nsc=[3, 3, 1])) H = Hamiltonian(g, dtype=np.float64, spin=Spin.SPINORBIT) for i in range(10): j = range(i*2, i*2+3) @@ -1661,7 +1661,7 @@ def test_tile3(self, setup): R, param = [0.1, 1.1, 2.1, 3.1], [1., 2., 3., 4.] # Create reference - g = Geometry([[0] * 3], Atom('H', R=[4.]), sc=[1.] * 3) + g = Geometry([[0] * 3], Atom('H', R=[4.]), lattice=[1.] * 3) g.set_nsc([7] * 3) # Now create bigger geometry @@ -1744,7 +1744,7 @@ def test_repeat3(self, setup): R, param = [0.1, 1.1, 2.1, 3.1], [1., 2., 3., 4.] # Create reference - g = Geometry([[0] * 3], Atom('H', R=[4.]), sc=[1.] * 3) + g = Geometry([[0] * 3], Atom('H', R=[4.]), lattice=[1.] * 3) g.set_nsc([7] * 3) # Now create bigger geometry @@ -1963,7 +1963,7 @@ def func(self, ia, atoms, atoms_xyz=None): def test_wavefunction1(): N = 50 o1 = SphericalOrbital(0, (np.linspace(0, 2, N), np.exp(-np.linspace(0, 100, N)))) - G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), sc=[4, 4, 4]) + G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), lattice=[4, 4, 4]) H = Hamiltonian(G) R, param = [0.1, 1.5], [1., 0.1] H.construct([R, param]) @@ -1977,14 +1977,14 @@ def test_wavefunction1(): def test_wavefunction2(): N = 50 o1 = SphericalOrbital(0, (np.linspace(0, 2, N), np.exp(-np.linspace(0, 100, N)))) - G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), sc=[4, 4, 4]) + G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), lattice=[4, 4, 4]) H = Hamiltonian(G) R, param = [0.1, 1.5], [1., 0.1] H.construct([R, param]) ES = H.eigenstate(dtype=np.float64) # This is effectively plotting outside where no atoms exists # (there could however still be psi weight). - grid = Grid(0.1, sc=SuperCell([2, 2, 2], origin=[2] * 3)) + grid = Grid(0.1, lattice=Lattice([2, 2, 2], origin=[2] * 3)) grid.fill(0.) ES.sub(0).wavefunction(grid) @@ -1992,14 +1992,14 @@ def test_wavefunction2(): def test_wavefunction3(): N = 50 o1 = SphericalOrbital(0, (np.linspace(0, 2, N), np.exp(-np.linspace(0, 100, N)))) - G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), sc=[4, 4, 4]) + G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), lattice=[4, 4, 4]) H = Hamiltonian(G, spin=Spin('nc')) R, param = [0.1, 1.5], [[0., 0., 0.1, -0.1], [1., 1., 0.1, -0.1]] H.construct([R, param]) ES = H.eigenstate() # Plot in the full thing - grid = Grid(0.1, dtype=np.complex128, sc=SuperCell([2, 2, 2], origin=[-1] * 3)) + grid = Grid(0.1, dtype=np.complex128, lattice=Lattice([2, 2, 2], origin=[-1] * 3)) grid.fill(0.) ES.sub(0).wavefunction(grid) @@ -2007,13 +2007,13 @@ def test_wavefunction3(): def test_wavefunction_eta(): N = 50 o1 = SphericalOrbital(0, (np.linspace(0, 2, N), np.exp(-np.linspace(0, 100, N)))) - G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), sc=[4, 4, 4]) + G = Geometry([[1] * 3, [2] * 3], Atom(6, o1), lattice=[4, 4, 4]) H = Hamiltonian(G, spin=Spin('nc')) R, param = [0.1, 1.5], [[0., 0., 0.1, -0.1], [1., 1., 0.1, -0.1]] H.construct([R, param]) ES = H.eigenstate() # Plot in the full thing - grid = Grid(0.1, dtype=np.complex128, sc=SuperCell([2, 2, 2], origin=[-1] * 3)) + grid = Grid(0.1, dtype=np.complex128, lattice=Lattice([2, 2, 2], origin=[-1] * 3)) grid.fill(0.) ES.sub(0).wavefunction(grid, eta=True) diff --git a/sisl/physics/tests/test_overlap.py b/sisl/physics/tests/test_overlap.py index 25237ae70b..d8bf5d401e 100644 --- a/sisl/physics/tests/test_overlap.py +++ b/sisl/physics/tests/test_overlap.py @@ -5,7 +5,7 @@ import numpy as np -from sisl import Geometry, Atom, SphericalOrbital, AtomicOrbital, SuperCell +from sisl import Geometry, Atom, SphericalOrbital, AtomicOrbital, Lattice from sisl import Grid, Spin from sisl.physics.overlap import Overlap @@ -19,9 +19,9 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) n = 60 rf = np.linspace(0, bond * 1.01, n) @@ -30,7 +30,7 @@ def __init__(self): C = Atom(6, orb.toAtomicOrbital()) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.S = Overlap(self.g) return t() diff --git a/sisl/physics/tests/test_physics_sparse.py b/sisl/physics/tests/test_physics_sparse.py index a1dac7adf6..23009496ba 100644 --- a/sisl/physics/tests/test_physics_sparse.py +++ b/sisl/physics/tests/test_physics_sparse.py @@ -120,7 +120,7 @@ def test_sparse_orbital_bz_hermitian(n0, n1, n2): # Figure out the transposed supercell indices of the edges isc = - s.geometry.o2isc(edges) # Convert to supercell - IO = s.geometry.sc.sc_index(isc) * no + io + IO = s.geometry.lattice.sc_index(isc) * no + io # Figure out if 'io' is also in the back-edges for jo, edge in zip(IO, edges % no): assert jo in s.edges(edge) diff --git a/sisl/physics/tests/test_self_energy.py b/sisl/physics/tests/test_self_energy.py index f9ba7fb17e..c6d0f0d220 100644 --- a/sisl/physics/tests/test_self_energy.py +++ b/sisl/physics/tests/test_self_energy.py @@ -8,7 +8,7 @@ import numpy as np from scipy.sparse import SparseEfficiencyWarning -from sisl import Geometry, Atom, SuperCell, Hamiltonian +from sisl import Geometry, Atom, Lattice, Hamiltonian from sisl import BrillouinZone, Bloch from sisl import SelfEnergy, WideBandSE, SemiInfinite, RecursiveSI from sisl import RealSpaceSE, RealSpaceSI @@ -24,14 +24,14 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) - + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + C = Atom(Z=6, R=[bond * 1.01]) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.H = Hamiltonian(self.g) func = self.H.create_construct([0.1, bond+0.1], [0., -2.7]) self.H.construct(func) @@ -195,9 +195,9 @@ def test_real_space_H(setup, k_axes, semi_axis, trs, bz, unfold): def test_real_space_H_3d(): - sc = SuperCell(1., nsc=[3] * 3) + lattice = Lattice(1., nsc=[3] * 3) H = Atom(Z=1, R=[1.001]) - geom = Geometry([0] * 3, atoms=H, sc=sc) + geom = Geometry([0] * 3, atoms=H, lattice=lattice) H = Hamiltonian(geom) H.construct(([0.001, 1.01], (0, -1))) RSE = RealSpaceSE(H, 0, [1, 2], (3, 4, 2)) diff --git a/sisl/sparse_geometry.py b/sisl/sparse_geometry.py index 395c979509..927ecc3ce4 100644 --- a/sisl/sparse_geometry.py +++ b/sisl/sparse_geometry.py @@ -238,16 +238,16 @@ def set_nsc(self, size, *args, **kwargs): If one reduces the number of supercells, *any* sparse element that references the supercell will be deleted. - See `SuperCell.set_nsc` for allowed parameters. + See `Lattice.set_nsc` for allowed parameters. See Also -------- - SuperCell.set_nsc : the underlying called method + Lattice.set_nsc : the underlying called method """ - sc = self.sc.copy() + lattice = self.lattice.copy() # Try first in the new one, then we figure out what to do - sc.set_nsc(*args, **kwargs) - if allclose(sc.nsc, self.sc.nsc): + lattice.set_nsc(*args, **kwargs) + if allclose(lattice.nsc, self.lattice.nsc): return # Create an array of all things that should be translated @@ -255,10 +255,10 @@ def set_nsc(self, size, *args, **kwargs): new = [] deleted = np.empty(self.n_s, np.bool_) deleted[:] = True - for i, sc_off in sc: + for i, sc_off in lattice: try: # Luckily there are *only* one time wrap-arounds - j = self.sc.sc_index(sc_off) + j = self.lattice.sc_index(sc_off) # Now do translation old.append(j) new.append(i) @@ -274,11 +274,11 @@ def set_nsc(self, size, *args, **kwargs): old.append(j) # Move to the end (*HAS* to be higher than the number of # cells in the new supercell structure) - new.append(max(self.n_s, sc.n_s) + i) + new.append(max(self.n_s, lattice.n_s) + i) # Check that we will translate all indices in the old # sparsity pattern to the new one - if len(old) not in [self.n_s, sc.n_s]: + if len(old) not in [self.n_s, lattice.n_s]: raise SislError("Not all supercells are accounted for") old = _a.arrayi(old) @@ -312,13 +312,13 @@ def set_nsc(self, size, *args, **kwargs): else: max_n = 0 # Make sure we delete all column values where we have put fake values - delete = _a.arangei(sc.n_s * size, max(max_n, self.shape[1])) + delete = _a.arangei(lattice.n_s * size, max(max_n, self.shape[1])) if len(delete) > 0: self._csr.delete_columns(delete, keep_shape=True) # Ensure the shape is correct shape = list(self._csr.shape) - shape[1] = size * sc.n_s + shape[1] = size * lattice.n_s self._csr._shape = tuple(shape) self._csr._clean_columns() @@ -367,7 +367,7 @@ def transpose(self, sort=True): T._csr._D = None # Short-links - sc = self.geometry.sc + lattice = self.geometry.lattice # Create "DOK" format indices csr = self._csr @@ -398,10 +398,10 @@ def transpose(self, sort=True): # row, col, _D # Retrieve all sc-indices in the new transposed array - new_sc_off = sc.sc_index(- sc.sc_off) + new_sc_off = lattice.sc_index(- lattice.sc_off) # Calculate the row-offsets in the new sparse geometry - row += new_sc_off[sc.sc_index(sc.sc_off[col // size, :])] * size + row += new_sc_off[lattice.sc_index(lattice.sc_off[col // size, :])] * size # Now convert columns into unit-cell col %= size @@ -681,7 +681,7 @@ def untile(self, prefix, reps, axis, segment=0, *args, sym=True, **kwargs): # create correct linear offset due to the segment. # Further below we will take out the linear indices by modulo and integer # division operations. - lsc = tile(self.geometry.sc.sc_off, (1, reps)).reshape(-1, reps, 3) + lsc = tile(self.geometry.lattice.sc_off, (1, reps)).reshape(-1, reps, 3) lsc[:, :, axis] = lsc[:, :, axis] * reps + _a.arangei(reps) - segment lsc.shape = (-1, 3) @@ -1061,11 +1061,11 @@ def set_nsc(self, *args, **kwargs): If one reduces the number of supercells *any* sparse element that references the supercell will be deleted. - See `SuperCell.set_nsc` for allowed parameters. + See `Lattice.set_nsc` for allowed parameters. See Also -------- - SuperCell.set_nsc : the underlying called method + Lattice.set_nsc : the underlying called method """ super().set_nsc(self.na, *args, **kwargs) @@ -1519,11 +1519,11 @@ def set_nsc(self, *args, **kwargs): If one reduces the number of supercells *any* sparse element that references the supercell will be deleted. - See `SuperCell.set_nsc` for allowed parameters. + See `Lattice.set_nsc` for allowed parameters. See Also -------- - SuperCell.set_nsc : the underlying called method + Lattice.set_nsc : the underlying called method """ super().set_nsc(self.no, *args, **kwargs) @@ -2138,7 +2138,7 @@ def add(self, other, axis=None, offset=(0, 0, 0)): transfer_idx += _a.arangei(self.geometry.n_s).reshape(-1, 1) * other.geometry.no # Remove couplings along axis if not axis is None: - idx = (self.geometry.sc.sc_off[:, axis] != 0).nonzero()[0] + idx = (self.geometry.lattice.sc_off[:, axis] != 0).nonzero()[0] # Tell the routine to delete these indices transfer_idx[idx, :] = full_no_s + 1 idx = array_arange(self._csr.ptr[:-1], n=self._csr.ncol) @@ -2153,9 +2153,9 @@ def add(self, other, axis=None, offset=(0, 0, 0)): o_idx = [] s_idx = [] idx_delete = [] - for isc, sc in enumerate(other.geometry.sc.sc_off): + for isc, sc in enumerate(other.geometry.lattice.sc_off): try: - s_idx.append(self.geometry.sc.sc_index(sc)) + s_idx.append(self.geometry.lattice.sc_index(sc)) o_idx.append(isc) except ValueError: idx_delete.append(isc) @@ -2168,16 +2168,16 @@ def add(self, other, axis=None, offset=(0, 0, 0)): # Now figure out if the supercells can be kept, at all... # find SC indices in other corresponding to self - #o_idx_uc = other.geometry.sc.sc_index([0] * 3) - #o_idx_sc = _a.arangei(other.geometry.sc.n_s) + #o_idx_uc = other.geometry.lattice.sc_index([0] * 3) + #o_idx_sc = _a.arangei(other.geometry.lattice.n_s) # Remove couplings along axis for i in range(3): if i == axis: - idx = (other.geometry.sc.sc_off[:, axis] != 0).nonzero()[0] + idx = (other.geometry.lattice.sc_off[:, axis] != 0).nonzero()[0] elif not allclose(geom.cell[i, :], other.cell[i, :]): # This will happen in case `axis` is None - idx = (other.geometry.sc.sc_off[:, i] != 0).nonzero()[0] + idx = (other.geometry.lattice.sc_off[:, i] != 0).nonzero()[0] else: # When axis is not specified and cell parameters # are commensurate, then we will not change couplings @@ -2301,7 +2301,7 @@ def append(self, other, axis, eps=0.005, scale=1): raise ValueError(f"{self.__class__.__name__}.append requires sparse-geometries to have the same " "number of supercells along all directions.") - if not allclose(self.geometry.sc._isc_off, other.geometry.sc._isc_off): + if not allclose(self.geometry.lattice._isc_off, other.geometry.lattice._isc_off): raise ValueError(f"{self.__class__.__name__}.append requires supercell offsets to be the same.") if self.dtype != other.dtype: @@ -2360,8 +2360,8 @@ def append(self, other, axis, eps=0.005, scale=1): # 1. find overlapping atoms along axis idx_s_first, idx_o_first = self.geometry.overlap(other.geometry, eps=eps) idx_s_last, idx_o_last = self.geometry.overlap(other.geometry, eps=eps, - offset=-self.geometry.sc.cell[axis, :], - offset_other=-other.geometry.sc.cell[axis, :]) + offset=-self.geometry.lattice.cell[axis, :], + offset_other=-other.geometry.lattice.cell[axis, :]) # IFF idx_s_* contains duplicates, then we have multiple overlapping atoms which is not # allowed def _test(diff): @@ -2381,8 +2381,8 @@ def _check_edges_and_coordinates(spgeom, atoms, isc, err_help): geom = spgeom.geometry # Find orbitals that we wish to exclude from the orbital connections # This ensures that we only find couplings crossing the supercell boundaries - irrelevant_sc = delete(_a.arangei(geom.sc.n_s), geom.sc.sc_index(isc)) - sc_orbitals = _a.arangei(geom.no_s).reshape(geom.sc.n_s, -1) + irrelevant_sc = delete(_a.arangei(geom.lattice.n_s), geom.lattice.sc_index(isc)) + sc_orbitals = _a.arangei(geom.no_s).reshape(geom.lattice.n_s, -1) exclude = sc_orbitals[irrelevant_sc, :].ravel() # get connections and transfer them to the unit-cell edges_sc = geom.o2a(spgeom.edges(orbitals=_a.arangei(geom.no), exclude=exclude), True) @@ -2402,7 +2402,7 @@ def _check_edges_and_coordinates(spgeom, atoms, isc, err_help): for isc in unique(isc_off): idx = (isc_off == isc).nonzero()[0] sc_off_atoms.append("{k}: {v}".format( - k=str(geom.sc.sc_off[isc]), + k=str(geom.lattice.sc_off[isc]), v=list2str(np.sort(uca[idx])))) sc_off_atoms = "\n ".join(sc_off_atoms) raise ValueError(f"{self.__class__.__name__}.append requires matching coupling elements.\n\n" @@ -2434,13 +2434,13 @@ def _check_edges_and_coordinates(spgeom, atoms, isc, err_help): idx = _a.arangei(geom.n_s).reshape(-1, 1) * geom.no def _sc_index_sort(isc): - idx = geom.sc.sc_index(isc) + idx = geom.lattice.sc_index(isc) # Now sort so that all indices are corresponding one2one # This is important since two different supercell indices # need not be sorted in the same manner. # This ensures that there is a correspondance between # two different sparse elements - off = delete(geom.sc.sc_off[idx].T, axis, axis=0) + off = delete(geom.lattice.sc_off[idx].T, axis, axis=0) return idx[np.lexsort(off)] idx_iscP = idx[_sc_index_sort(isc_forward)] diff --git a/sisl/tests/test_geometry.py b/sisl/tests/test_geometry.py index 45b33dcfaa..d9b95833fd 100644 --- a/sisl/tests/test_geometry.py +++ b/sisl/tests/test_geometry.py @@ -11,7 +11,7 @@ import sisl.geom as sisl_geom from sisl import SislWarning, SislError, SislDeprecation from sisl import Cube, Sphere -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice _dir = osp.join('sisl') @@ -24,15 +24,15 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], [1.5, -sq3h, 0.], [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) C = Atom(Z=6, R=[bond * 1.01]*2) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) - self.mol = Geometry([[i, 0, 0] for i in range(10)], sc=[50]) + self.mol = Geometry([[i, 0, 0] for i in range(10)], lattice=[50]) return t() @@ -49,7 +49,7 @@ def test_objects(self, setup): for ia in setup.g: i += 1 assert i == len(setup.g) - assert setup.g.no_s == 2 * len(setup.g) * np.prod(setup.g.sc.nsc) + assert setup.g.no_s == 2 * len(setup.g) * np.prod(setup.g.lattice.nsc) def test_properties(self, setup): assert 2 == len(setup.g) @@ -99,22 +99,22 @@ def test_tile0(self, setup): t = setup.g.tile(0, 0) def test_tile1(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[0, :] *= 2 t = setup.g.tile(2, 0) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) cell[1, :] *= 2 t = t.tile(2, 1) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) cell[2, :] *= 2 t = t.tile(2, 2) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) def test_tile2(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[:, :] *= 2 t = setup.g.tile(2, 0).tile(2, 1).tile(2, 2) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) def test_sort(self, setup): t = setup.g.tile(2, 0).tile(2, 1).tile(2, 2) @@ -124,35 +124,35 @@ def test_sort(self, setup): assert np.allclose(ts.xyz, tS.xyz) def test_tile3(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[:, :] *= 2 t1 = setup.g * 2 - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[0, :] *= 2 t1 = setup.g * (2, 0) - assert np.allclose(cell, t1.sc.cell) + assert np.allclose(cell, t1.lattice.cell) t = setup.g * ((2, 0), 'tile') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) cell[1, :] *= 2 t1 = t * (2, 1) - assert np.allclose(cell, t1.sc.cell) + assert np.allclose(cell, t1.lattice.cell) t = t * ((2, 1), 'tile') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) cell[2, :] *= 2 t1 = t * (2, 2) - assert np.allclose(cell, t1.sc.cell) + assert np.allclose(cell, t1.lattice.cell) t = t * ((2, 2), 'tile') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) # Full t = setup.g * [2, 2, 2] - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) t = setup.g * ([2, 2, 2], 't') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) def test_tile4(self, setup): @@ -169,47 +169,47 @@ def test_repeat0(self, setup): t = setup.g.repeat(0, 0) def test_repeat1(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[0, :] *= 2 t = setup.g.repeat(2, 0) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) cell[1, :] *= 2 t = t.repeat(2, 1) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) cell[2, :] *= 2 t = t.repeat(2, 2) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) def test_repeat2(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[:, :] *= 2 t = setup.g.repeat(2, 0).repeat(2, 1).repeat(2, 2) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) def test_repeat3(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[0, :] *= 2 t1 = setup.g.repeat(2, 0) - assert np.allclose(cell, t1.sc.cell) + assert np.allclose(cell, t1.lattice.cell) t = setup.g * ((2, 0), 'repeat') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) cell[1, :] *= 2 t1 = t.repeat(2, 1) - assert np.allclose(cell, t1.sc.cell) + assert np.allclose(cell, t1.lattice.cell) t = t * ((2, 1), 'r') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) cell[2, :] *= 2 t1 = t.repeat(2, 2) - assert np.allclose(cell, t1.sc.cell) + assert np.allclose(cell, t1.lattice.cell) t = t * ((2, 2), 'repeat') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) # Full t = setup.g * ([2, 2, 2], 'r') - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) assert np.allclose(t1.xyz, t.xyz) def test_repeat4(self, setup): @@ -247,7 +247,7 @@ def test_axyz(self, setup): assert np.allclose(setup.g[0], setup.g.xyz[0, :]) assert np.allclose(setup.g[2], setup.g.axyz(2)) isc = setup.g.a2isc(2) - off = setup.g.sc.offset(isc) + off = setup.g.lattice.offset(isc) assert np.allclose(setup.g.xyz[0] + off, setup.g.axyz(2)) assert np.allclose(setup.g.xyz[0] + off, setup.g.axyz(0, isc)) assert np.allclose(setup.g.xyz[0] + off, setup.g.axyz(isc=isc)[0]) @@ -376,18 +376,18 @@ def test_copy(self, setup): assert setup.g == setup.g.copy() def test_nsc1(self, setup): - sc = setup.g.sc.copy() - nsc = np.copy(sc.nsc) - sc.set_nsc([5, 5, 0]) - assert np.allclose([5, 5, 1], sc.nsc) - assert len(sc.sc_off) == np.prod(sc.nsc) + lattice = setup.g.lattice.copy() + nsc = np.copy(lattice.nsc) + lattice.set_nsc([5, 5, 0]) + assert np.allclose([5, 5, 1], lattice.nsc) + assert len(lattice.sc_off) == np.prod(lattice.nsc) def test_nsc2(self, setup): - sc = setup.g.sc.copy() - nsc = np.copy(sc.nsc) - sc.set_nsc([0, 1, 0]) - assert np.allclose([1, 1, 1], sc.nsc) - assert len(sc.sc_off) == np.prod(sc.nsc) + lattice = setup.g.lattice.copy() + nsc = np.copy(lattice.nsc) + lattice.set_nsc([0, 1, 0]) + assert np.allclose([1, 1, 1], lattice.nsc) + assert len(lattice.sc_off) == np.prod(lattice.nsc) def test_rotate_deprecate(self, setup): rot1 = setup.g.rotate(180, "xz", what="xyz") @@ -399,47 +399,47 @@ def test_rotate_deprecate(self, setup): def test_rotation1(self, setup): rot = setup.g.rotate(180, [0, 0, 1], what="xyz+abc") - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) rot = setup.g.rotate(np.pi, [0, 0, 1], rad=True, what="xyz+abc") - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) rot = rot.rotate(180, "z", what="xyz+abc") - rot.sc.cell[2, 2] *= -1 - assert np.allclose(rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(rot.xyz, setup.g.xyz) def test_rotation2(self, setup): rot = setup.g.rotate(180, "z", what='abc') - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(rot.xyz, setup.g.xyz) rot = setup.g.rotate(np.pi, [0, 0, 1], rad=True, what='abc') - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(rot.xyz, setup.g.xyz) rot = rot.rotate(180, [0, 0, 1], what='abc') - rot.sc.cell[2, 2] *= -1 - assert np.allclose(rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(rot.xyz, setup.g.xyz) def test_rotation3(self, setup): rot = setup.g.rotate(180, [0, 0, 1], what='xyz') - assert np.allclose(rot.sc.cell, setup.g.sc.cell) + assert np.allclose(rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) rot = setup.g.rotate(np.pi, [0, 0, 1], rad=True, what='xyz') - assert np.allclose(rot.sc.cell, setup.g.sc.cell) + assert np.allclose(rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) rot = rot.rotate(180, "z", what='xyz') - assert np.allclose(rot.sc.cell, setup.g.sc.cell) + assert np.allclose(rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(rot.xyz, setup.g.xyz) def test_rotation4(self, setup): @@ -561,11 +561,11 @@ def test_append1(self, setup): assert len(s) == len(setup.g) * 2 assert np.allclose(s.cell[axis, :], setup.g.cell[axis, :]* 2) assert np.allclose(s.cell[axis, :], setup.g.cell[axis, :]* 2) - s = setup.g.append(setup.g.sc, axis) + s = setup.g.append(setup.g.lattice, axis) assert len(s) == len(setup.g) assert np.allclose(s.cell[axis, :], setup.g.cell[axis, :]* 2) assert np.allclose(s.cell[axis, :], setup.g.cell[axis, :]* 2) - s = setup.g.prepend(setup.g.sc, axis) + s = setup.g.prepend(setup.g.lattice, axis) assert len(s) == len(setup.g) assert np.allclose(s.cell[axis, :], setup.g.cell[axis, :]* 2) assert np.allclose(s.cell[axis, :], setup.g.cell[axis, :]* 2) @@ -580,7 +580,7 @@ def test_prepend_raise_valueerror(self, setup): def test_append_prepend_offset(self, setup): for axis in [0, 1, 2]: - t = setup.g.sc.cell[axis, :].copy() + t = setup.g.lattice.cell[axis, :].copy() t *= 10. / (t ** 2).sum() ** 0.5 s1 = setup.g.copy() s2 = setup.g.translate(t) @@ -641,7 +641,7 @@ def test_center_raise(self, setup): def test___add1__(self, setup): n = len(setup.g) - double = setup.g + setup.g + setup.g.sc + double = setup.g + setup.g + setup.g.lattice assert len(double) == n * 2 assert np.allclose(setup.g.cell * 2, double.cell) assert np.allclose(setup.g.xyz[:n, :], double.xyz[:n, :]) @@ -690,7 +690,7 @@ def test_add(self, setup): double = setup.g.add(setup.g) assert len(double) == len(setup.g) * 2 assert np.allclose(setup.g.cell, double.cell) - double = setup.g.add(setup.g).add(setup.g.sc) + double = setup.g.add(setup.g).add(setup.g.lattice) assert len(double) == len(setup.g) * 2 assert np.allclose(setup.g.cell * 2, double.cell) @@ -859,8 +859,8 @@ def test_close_within3(self, setup): def test_within_inf1(self, setup): g = setup.g.translate([0.05] * 3) - sc_3x3 = g.sc.tile(3, 0).tile(3, 1) - assert len(g.within_inf(sc_3x3)[0]) == len(g) * 3 ** 2 + lattice_3x3 = g.lattice.tile(3, 0).tile(3, 1) + assert len(g.within_inf(lattice_3x3)[0]) == len(g) * 3 ** 2 def test_within_inf_nonperiodic(self, setup): g = setup.g.copy() @@ -869,13 +869,13 @@ def test_within_inf_nonperiodic(self, setup): # we should get only the atoms in the unit cell. g.set_nsc([3,3,1]) - ia, xyz, isc = g.within_inf(g.sc, periodic=[False, False, False]) + ia, xyz, isc = g.within_inf(g.lattice, periodic=[False, False, False]) assert len(ia) == g.na assert np.all(isc == 0) # Make sure that it also works with mixed periodic/non periodic directions - ia, xyz, isc = g.within_inf(g.sc, periodic=[True, False, False]) + ia, xyz, isc = g.within_inf(g.lattice, periodic=[True, False, False]) assert len(ia) > g.na assert np.any(isc[:, 0] != 0) @@ -883,18 +883,18 @@ def test_within_inf_nonperiodic(self, setup): def test_within_inf2(self, setup): g = setup.mol.translate([0.05] * 3) - sc = SuperCell(1.5) + lattice = Lattice(1.5) for o in range(10): origin = [o - 0.5, -0.5, -0.5] - sc.origin = origin - idx = g.within_inf(sc)[0] + lattice.origin = origin + idx = g.within_inf(lattice)[0] assert len(idx) == 1 assert idx[0] == o def test_within_inf_duplicates(self, setup): g = setup.g.copy() - sc_3x3 = g.sc.tile(3, 0).tile(3, 1) - assert len(g.within_inf(sc_3x3)[0]) == len(g) * 3 ** 2 + 7 # 3 per vector and 1 in the upper right corner + lattice_3x3 = g.lattice.tile(3, 0).tile(3, 1) + assert len(g.within_inf(lattice_3x3)[0]) == len(g) * 3 ** 2 + 7 # 3 per vector and 1 in the upper right corner def test_close_sizes(self, setup): point = 0 @@ -1100,14 +1100,14 @@ def test_unit_cell_estimation1(self, setup): def test_unit_cell_estimation2(self, setup): # Create new geometry with only the coordinates # and atoms - s1 = SuperCell([2, 2, 2]) - g1 = Geometry([[0, 0, 0], [1, 1, 1]], sc=s1) + s1 = Lattice([2, 2, 2]) + g1 = Geometry([[0, 0, 0], [1, 1, 1]], lattice=s1) g2 = Geometry(np.copy(g1.xyz)) assert np.allclose(g1.cell, g2.cell) # Assert that it correctly calculates the bond-length in the # directions of actual distance - g1 = Geometry([[0, 0, 0], [1, 1, 0]], atoms='H', sc=s1) + g1 = Geometry([[0, 0, 0], [1, 1, 0]], atoms='H', lattice=s1) g2 = Geometry(np.copy(g1.xyz)) for i in range(2): assert np.allclose(g1.cell[i, :], g2.cell[i, :]) @@ -1152,7 +1152,7 @@ def test_distance5(self, setup): def test_distance6(self, setup): # Create a 1D chain - geom = Geometry([0]*3, Atom(1, R=1.), sc=1) + geom = Geometry([0]*3, Atom(1, R=1.), lattice=1) geom.set_nsc([77, 1, 1]) d = geom.distance(0) assert len(d) == 1 @@ -1185,7 +1185,7 @@ def test_distance6(self, setup): def test_distance7(self, setup): # Create a 1D chain - geom = Geometry([0]*3, Atom(1, R=1.), sc=1) + geom = Geometry([0]*3, Atom(1, R=1.), lattice=1) geom.set_nsc([77, 1, 1]) # Try with a short R and a long tolerance list # We know that the tolerance list prevails, because @@ -1194,7 +1194,7 @@ def test_distance7(self, setup): assert np.allclose(d, [1.]) def test_distance8(self, setup): - geom = Geometry([0]*3, Atom(1, R=1.), sc=1) + geom = Geometry([0]*3, Atom(1, R=1.), lattice=1) geom.set_nsc([77, 1, 1]) d = geom.distance(0, method='min') assert len(d) == 1 @@ -1205,7 +1205,7 @@ def test_distance8(self, setup): def test_optimize_nsc1(self, setup): # Create a 1D chain - geom = Geometry([0]*3, Atom(1, R=1.), sc=1) + geom = Geometry([0]*3, Atom(1, R=1.), lattice=1) geom.set_nsc([77, 77, 77]) assert np.allclose(geom.optimize_nsc(), [3, 3, 3]) geom.set_nsc([77, 77, 77]) @@ -1283,13 +1283,21 @@ def test_argumentparser2(self, setup, **kwargs): self.test_argumentparser2(setup, **setup.g._ArgumentParser_args_single()) def test_set_sc(self, setup): - # Create new geometry with only the coordinates - # and atoms - s1 = SuperCell([2, 2, 2]) - g1 = Geometry([[0, 0, 0], [1, 1, 1]], sc=[2, 2, 1]) + # check for deprecation + s1 = Lattice([2, 2, 2]) + g1 = Geometry([[0, 0, 0], [1, 1, 1]], lattice=[2, 2, 1]) with pytest.warns(SislDeprecation) as deps: g1.set_sc(s1) - assert g1.sc == s1 + assert g1.lattice == s1 + assert len(deps) == 1 + + def test_set_supercell(self, setup): + # check for deprecation + s1 = Lattice([2, 2, 2]) + g1 = Geometry([[0, 0, 0], [1, 1, 1]], lattice=[2, 2, 1]) + with pytest.warns(SislDeprecation) as deps: + g1.set_supercell(s1) + assert g1.lattice == s1 assert len(deps) == 1 def test_attach1(self, setup): @@ -1454,7 +1462,7 @@ def test_geometry_sort_simple(): s = bi.sort(axis=i) assert np.all(np.diff(s.xyz[:, i]) >= -atol) s = bi.sort(lattice=i) - assert np.all(np.diff(s.fxyz[:, i] * bi.sc.length[i]) >= -atol) + assert np.all(np.diff(s.fxyz[:, i] * bi.lattice.length[i]) >= -atol) s, idx = bi.sort(axis=0, lattice=1, ret_atoms=True) assert np.all(np.diff(s.xyz[:, 0]) >= -atol) @@ -1465,7 +1473,7 @@ def test_geometry_sort_simple(): assert np.all(np.diff(s.xyz[:, 0]) >= -atol) for ix in idx: # idx is according to bi - assert np.all(np.diff(bi.fxyz[ix, 1] * bi.sc.length[i]) <= atol) + assert np.all(np.diff(bi.fxyz[ix, 1] * bi.lattice.length[i]) <= atol) def test_geometry_sort_int(): @@ -1479,7 +1487,7 @@ def test_geometry_sort_int(): s = bi.sort(axis0=i) assert np.all(np.diff(s.xyz[:, i]) >= -atol) s = bi.sort(lattice3=i) - assert np.all(np.diff(s.fxyz[:, i] * bi.sc.length[i]) >= -atol) + assert np.all(np.diff(s.fxyz[:, i] * bi.lattice.length[i]) >= -atol) s, idx = bi.sort(axis12314=0, lattice0=1, ret_atoms=True) assert np.all(np.diff(s.xyz[:, 0]) >= -atol) @@ -1490,7 +1498,7 @@ def test_geometry_sort_int(): assert np.all(np.diff(s.xyz[:, 0]) >= -atol) for ix in idx: # idx is according to bi - assert np.all(np.diff(bi.fxyz[ix, 1] * bi.sc.length[i]) <= atol) + assert np.all(np.diff(bi.fxyz[ix, 1] * bi.lattice.length[i]) <= atol) def test_geometry_sort_atom(): diff --git a/sisl/tests/test_geometry_return.py b/sisl/tests/test_geometry_return.py index 802d977435..e4e532d806 100644 --- a/sisl/tests/test_geometry_return.py +++ b/sisl/tests/test_geometry_return.py @@ -8,7 +8,7 @@ import numpy as np from sisl import Sphere -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice @pytest.fixture @@ -17,18 +17,18 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) C = Atom(Z=6, R=bond * 1.01) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) C = Atom(Z=6, R=[bond * 1.01] * 2) self.g2 = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) return t() diff --git a/sisl/tests/test_grid.py b/sisl/tests/test_grid.py index f5ab127af5..eeadc91a30 100644 --- a/sisl/tests/test_grid.py +++ b/sisl/tests/test_grid.py @@ -7,7 +7,7 @@ import numpy as np from scipy.sparse import csr_matrix -from sisl import SuperCell, SphericalOrbital, Atom, Geometry +from sisl import Lattice, SphericalOrbital, Atom, Geometry from sisl import Grid from sisl import Ellipsoid, Cuboid @@ -18,10 +18,10 @@ class t(): def __init__(self): alat = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * alat, nsc=[3, 3, 1]) - self.g = Grid([10, 10, 100], sc=self.sc) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * alat, nsc=[3, 3, 1]) + self.g = Grid([10, 10, 100], lattice=self.lattice) self.g.fill(2.) return t() @@ -33,7 +33,7 @@ def test_print(self, setup): str(setup.g) def test_init(self, setup): - Grid(0.1, sc=setup.sc) + Grid(0.1, lattice=setup.lattice) def test_append(self, setup): g = setup.g.append(setup.g, 0) @@ -97,7 +97,7 @@ def test_add2(self, setup): assert np.allclose((g - setup.g).grid, setup.g.grid) def test_add_fail1(self, setup): - g = Grid(np.array(setup.g.shape) // 2 + 1, sc=setup.g.sc.copy()) + g = Grid(np.array(setup.g.shape) // 2 + 1, lattice=setup.g.lattice.copy()) with pytest.raises(ValueError): setup.g + g @@ -192,7 +192,7 @@ 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]]) + grid = Grid(0.1, lattice=[[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) @@ -211,7 +211,7 @@ def test_isosurface_non_orthogonal(self, setup): # 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(0.1, lattice=[[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) @@ -222,7 +222,7 @@ def test_isosurface_non_orthogonal(self, setup): assert np.unique(verts[:, 2]).shape == (2,) def test_smooth_gaussian(self, setup): - g = Grid(0.1, sc=[[2, 0, 0], [0, 2, 0], [0, 0, 2]]) + g = Grid(0.1, lattice=[[2, 0, 0], [0, 2, 0], [0, 0, 2]]) g[10, 10, 10] = 1 # With a sigma of 0.3 Ang, that single value should be propagated @@ -235,7 +235,7 @@ def test_smooth_gaussian(self, setup): assert np.any(smoothed.grid == 0) def test_smooth_uniform(self, setup): - g = Grid(0.1, sc=[[2, 0, 0], [0, 2, 0], [0, 0, 2]]) + g = Grid(0.1, lattice=[[2, 0, 0], [0, 2, 0], [0, 0, 2]]) g[10, 10, 10] = 1 # With a radius of 0.7 Ang, that single value should be propagated @@ -250,10 +250,10 @@ def test_smooth_uniform(self, setup): def test_index_ndim1(self, setup): mid = np.array(setup.g.shape, np.int32) // 2 - 1 v = [0.001, 0., 0.001] - idx = setup.g.index(setup.sc.center() - v) + idx = setup.g.index(setup.lattice.center() - v) assert np.all(mid == idx) for i in range(3): - idx = setup.g.index(setup.sc.center() - v, axis=i) + idx = setup.g.index(setup.lattice.center() - v, axis=i) assert idx == mid[i] def test_index_fail(self, setup): @@ -263,11 +263,11 @@ def test_index_fail(self, setup): def test_index_ndim2(self, setup): mid = np.array(setup.g.shape, np.int32) // 2 - 1 v = [0.001, 0., 0.001] - idx = setup.g.index([[0]*3, setup.sc.center() - v]) + idx = setup.g.index([[0]*3, setup.lattice.center() - v]) assert np.allclose([[0] * 3, mid], idx) for i in range(3): - idx = setup.g.index([[0]*3, setup.sc.center() - v], axis=i) + idx = setup.g.index([[0]*3, setup.lattice.center() - v], axis=i) assert np.allclose([[0, 0, 0][i], mid[i]], idx) def test_index_shape1(self, setup): @@ -343,7 +343,7 @@ def test_remove_part(self, setup): assert setup.g.remove_part(1, i, above=True).shape[i] == 1 def test_sub_fail(self, setup): - g = Grid(np.array(setup.g.shape) // 2 + 1, sc=setup.g.sc.copy()) + g = Grid(np.array(setup.g.shape) // 2 + 1, lattice=setup.g.lattice.copy()) with pytest.raises(ValueError): g.sub([], 0) @@ -474,7 +474,7 @@ def test_grid_tile_sc(): def test_grid_tile_geom(): - grid = Grid([4, 5, 6], geometry=Geometry([0] * 3, Atom[4], sc=4.)) + grid = Grid([4, 5, 6], geometry=Geometry([0] * 3, Atom[4], lattice=4.)) grid2 = grid.tile(2, 2) assert grid.shape[:2] == grid2.shape[:2] assert grid.shape[2] == grid2.shape[2] // 2 diff --git a/sisl/tests/test_lattice.py b/sisl/tests/test_lattice.py new file mode 100644 index 0000000000..41aad842da --- /dev/null +++ b/sisl/tests/test_lattice.py @@ -0,0 +1,457 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +import pytest +from pytest import approx + +import math as m +import numpy as np + +import sisl.linalg as lin +from sisl import Lattice, LatticeChild +from sisl.geom import graphene + + +pytestmark = [pytest.mark.supercell, pytest.mark.sc, pytest.mark.lattice] + + +@pytest.fixture +def setup(): + class t(): + def __init__(self): + alat = 1.42 + sq3h = 3.**.5 * 0.5 + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * alat, nsc=[3, 3, 1]) + return t() + + +class TestLattice: + + def test_str(self, setup): + str(setup.lattice) + str(setup.lattice) + assert setup.lattice != 'Not a Lattice' + + def test_nsc1(self, setup): + lattice = setup.lattice.copy() + lattice.set_nsc([5, 5, 0]) + assert np.allclose([5, 5, 1], lattice.nsc) + assert len(lattice.sc_off) == np.prod(lattice.nsc) + + def test_nsc2(self, setup): + lattice = setup.lattice.copy() + lattice.set_nsc([0, 1, 0]) + assert np.allclose([1, 1, 1], lattice.nsc) + assert len(lattice.sc_off) == np.prod(lattice.nsc) + lattice.set_nsc(a=3) + assert np.allclose([3, 1, 1], lattice.nsc) + assert len(lattice.sc_off) == np.prod(lattice.nsc) + lattice.set_nsc(b=3) + assert np.allclose([3, 3, 1], lattice.nsc) + assert len(lattice.sc_off) == np.prod(lattice.nsc) + lattice.set_nsc(c=5) + assert np.allclose([3, 3, 5], lattice.nsc) + assert len(lattice.sc_off) == np.prod(lattice.nsc) + + def test_nsc3(self, setup): + assert setup.lattice.sc_index([0, 0, 0]) == 0 + for s in range(setup.lattice.n_s): + assert setup.lattice.sc_index(setup.lattice.sc_off[s, :]) == s + arng = np.arange(setup.lattice.n_s) + np.random.seed(42) + np.random.shuffle(arng) + sc_off = setup.lattice.sc_off[arng, :] + assert np.all(setup.lattice.sc_index(sc_off) == arng) + + def test_nsc_fail_even(self, setup): + with pytest.raises(ValueError): + setup.lattice.set_nsc(a=2) + + def test_nsc_fail_even_and_odd(self, setup): + with pytest.raises(ValueError): + setup.lattice.set_nsc([1, 2, 3]) + + def test_area1(self, setup): + setup.lattice.area(0, 1) + + def test_fill(self, setup): + sc = setup.lattice.swapaxes(1, 2) + i = sc._fill([1, 1]) + assert i.dtype == np.int32 + i = sc._fill([1., 1.]) + assert i.dtype == np.float64 + for dt in [np.int32, np.float32, np.float64, np.complex64]: + i = sc._fill([1., 1.], dt) + assert i.dtype == dt + i = sc._fill(np.ones([2], dt)) + assert i.dtype == dt + + def test_add_vacuum1(self, setup): + sc = setup.lattice.copy() + for i in range(3): + s = sc.add_vacuum(10, i) + ax = setup.lattice.cell[i, :] + ax += ax / np.sum(ax ** 2) ** .5 * 10 + assert np.allclose(ax, s.cell[i, :]) + + def test_add1(self, setup): + sc = setup.lattice.copy() + for R in range(1, 10): + s = sc + R + assert np.allclose(s.cell, sc.cell + np.diag([R] * 3)) + + def test_rotation1(self, setup): + rot = setup.lattice.rotate(180, [0, 0, 1]) + rot.cell[2, 2] *= -1 + assert np.allclose(-rot.cell, setup.lattice.cell) + + rot = setup.lattice.rotate(m.pi, [0, 0, 1], rad=True) + rot.cell[2, 2] *= -1 + assert np.allclose(-rot.cell, setup.lattice.cell) + + rot = rot.rotate(180, [0, 0, 1]) + rot.cell[2, 2] *= -1 + assert np.allclose(rot.cell, setup.lattice.cell) + + def test_rotation2(self, setup): + rot = setup.lattice.rotate(180, setup.lattice.cell[2, :]) + rot.cell[2, 2] *= -1 + assert np.allclose(-rot.cell, setup.lattice.cell) + + rot = setup.lattice.rotate(m.pi, setup.lattice.cell[2, :], rad=True) + rot.cell[2, 2] *= -1 + assert np.allclose(-rot.cell, setup.lattice.cell) + + rot = rot.rotate(180, setup.lattice.cell[2, :]) + rot.cell[2, 2] *= -1 + assert np.allclose(rot.cell, setup.lattice.cell) + + @pytest.mark.parametrize("a,b", [[0, 1], [0, 2], [1, 2]]) + def test_swapaxes_lattice_vector(self, setup, a, b): + lattice = setup.lattice + sab = lattice.swapaxes(a, b) + assert np.allclose(lattice.origin, sab.origin) + assert np.allclose(lattice.nsc[[b, a]], sab.nsc[[a, b]]) + assert np.allclose(lattice.cell[[b, a]], sab.cell[[a, b]]) + + # and string input + sab = setup.lattice.swapaxes("abc"[a], "abc"[b]) + assert np.allclose(sab.cell[[b, a]], setup.lattice.cell[[a, b]]) + assert np.allclose(sab.origin, setup.lattice.origin) + assert np.allclose(sab.nsc[[b, a]], setup.lattice.nsc[[a, b]]) + + @pytest.mark.parametrize("a,b", [[0, 1], [0, 2], [1, 2]]) + def test_swapaxes_xyz(self, setup, a, b): + lattice = setup.lattice + sab = lattice.swapaxes(1, 2, "xyz") + assert np.allclose(lattice.nsc, sab.nsc) + assert np.allclose(lattice.origin[[b, a]], sab.origin[[a, b]]) + assert np.allclose(lattice.origin[[b, a]], sab.origin[[a, b]]) + + # and string input + sab = setup.lattice.swapaxes("xyz"[a], "xyz"[b]) + assert np.allclose(lattice.nsc, sab.nsc) + assert np.allclose(lattice.origin[[b, a]], sab.origin[[a, b]]) + assert np.allclose(lattice.origin[[b, a]], sab.origin[[a, b]]) + + def test_swapaxes_complicated(self, setup): + + # swap a couple of lattice vectors and cartesian coordinates + a = "azby" + b = "bxcz" + # this will result in + # 0. abc, xyz + # 1. bac, xyz + # 2. bac, zyx + # 3. bca, zyx + # 4. bca, zxy + sab = setup.lattice.swapaxes(a, b) + idx_abc = [1, 2, 0] + idx_xyz = [2, 0, 1] + assert np.allclose(sab.cell, setup.lattice.cell[idx_abc][:, idx_xyz]) + assert np.allclose(sab.origin, setup.lattice.origin[idx_xyz]) + assert np.allclose(sab.nsc, setup.lattice.nsc[idx_abc]) + + def test_offset1(self, setup): + off = setup.lattice.offset() + assert np.allclose(off, [0, 0, 0]) + off = setup.lattice.offset([1, 1, 1]) + cell = setup.lattice.cell[:, :] + assert np.allclose(off, cell[0, :] + cell[1, :] + cell[2, :]) + + def test_sc_index1(self, setup): + sc_index = setup.lattice.sc_index([0, 0, 0]) + assert sc_index == 0 + sc_index = setup.lattice.sc_index([0, 0, None]) + assert len(sc_index) == setup.lattice.nsc[2] + + def test_sc_index2(self, setup): + sc_index = setup.lattice.sc_index([[0, 0, 0], + [1, 1, 0]]) + s = str(sc_index) + assert len(sc_index) == 2 + + def test_sc_index3(self, setup): + with pytest.raises(Exception): + setup.lattice.sc_index([100, 100, 100]) + + def test_vertices(self, setup): + verts = setup.lattice.vertices() + + assert verts.shape == (2, 2, 2, 3) + assert np.allclose(verts[0, 0, 0], [0, 0, 0]) + assert np.allclose(verts[1, 0, 0], setup.lattice.cell[0]) + assert np.allclose(verts[1, 1, 1], setup.lattice.cell.sum(axis=0)) + + def test_untile1(self, setup): + cut = setup.lattice.untile(2, 0) + assert np.allclose(cut.cell[0, :] * 2, setup.lattice.cell[0, :]) + assert np.allclose(cut.cell[1, :], setup.lattice.cell[1, :]) + + def test_creation1(self, setup): + # full cell + tmp1 = Lattice([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + # diagonal cell + tmp2 = Lattice([1, 1, 1]) + # cell parameters + tmp3 = Lattice([1, 1, 1, 90, 90, 90]) + tmp4 = Lattice([1]) + assert np.allclose(tmp1.cell, tmp2.cell) + assert np.allclose(tmp1.cell, tmp3.cell) + assert np.allclose(tmp1.cell, tmp4.cell) + + def test_creation2(self, setup): + # full cell + class P(LatticeChild): + + def copy(self): + a = P() + a.set_lattice(setup.lattice) + return a + tmp1 = P() + tmp1.set_lattice([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + # diagonal cell + tmp2 = P() + tmp2.set_lattice([1, 1, 1]) + # cell parameters + tmp3 = P() + tmp3.set_lattice([1, 1, 1, 90, 90, 90]) + tmp4 = P() + tmp4.set_lattice([1]) + assert np.allclose(tmp1.cell, tmp2.cell) + assert np.allclose(tmp1.cell, tmp3.cell) + assert np.allclose(tmp1.cell, tmp4.cell) + assert len(tmp1.lattice._fill([0, 0, 0])) == 3 + assert len(tmp1.lattice._fill_sc([0, 0, 0])) == 3 + assert tmp1.lattice.is_orthogonal() + for i in range(3): + t2 = tmp2.lattice.add_vacuum(10, i) + assert tmp1.cell[i, i] + 10 == t2.cell[i, i] + + def test_creation3(self, setup): + with pytest.raises(ValueError): + setup.lattice.tocell([3, 6]) + + def test_creation4(self, setup): + with pytest.raises(ValueError): + setup.lattice.tocell([3, 4, 5, 6]) + + def test_creation5(self, setup): + with pytest.raises(ValueError): + setup.lattice.tocell([3, 4, 5, 6, 7, 6, 7]) + + def test_creation_rotate(self, setup): + # cell parameters + param = np.array([1, 2, 3, 45, 60, 80], np.float64) + parama = param.copy() + parama[3:] *= np.pi / 180 + lattice = Lattice(param) + assert np.allclose(param, lattice.parameters()) + assert np.allclose(parama, lattice.parameters(True)) + for ang in range(0, 91, 5): + s = lattice.rotate(ang, lattice.cell[0, :]).rotate(ang, lattice.cell[1, :]).rotate(ang, lattice.cell[2, :]) + assert np.allclose(param, s.parameters()) + assert np.allclose(parama, s.parameters(True)) + + def test_rcell(self, setup): + # LAPACK inverse algorithm implicitly does + # a transpose. + rcell = lin.inv(setup.lattice.cell) * 2. * np.pi + assert np.allclose(rcell.T, setup.lattice.rcell) + assert np.allclose(rcell.T / (2 * np.pi), setup.lattice.icell) + + def test_icell(self, setup): + assert np.allclose(setup.lattice.rcell, setup.lattice.icell * 2 * np.pi) + + def test_translate1(self, setup): + lattice = setup.lattice.translate([0, 0, 10]) + assert np.allclose(lattice.cell[2, :2], setup.lattice.cell[2, :2]) + assert np.allclose(lattice.cell[2, 2], setup.lattice.cell[2, 2]+10) + + def test_center1(self, setup): + assert np.allclose(setup.lattice.center(), np.sum(setup.lattice.cell, axis=0) / 2) + for i in [0, 1, 2]: + assert np.allclose(setup.lattice.center(i), setup.lattice.cell[i, :] / 2) + + def test_pickle(self, setup): + import pickle as p + s = p.dumps(setup.lattice) + n = p.loads(s) + assert setup.lattice == n + s = Lattice([1, 1, 1]) + assert setup.lattice != s + + def test_orthogonal(self, setup): + assert not setup.lattice.is_orthogonal() + + def test_fit1(self, setup): + g = graphene() + gbig = g.repeat(40, 0).repeat(40, 1) + gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 + lattice = g.lattice.fit(gbig) + assert np.allclose(lattice.cell, gbig.cell) + + def test_fit2(self, setup): + g = graphene(orthogonal=True) + gbig = g.repeat(40, 0).repeat(40, 1) + gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 + lattice = g.lattice.fit(gbig) + assert np.allclose(lattice.cell, gbig.cell) + + def test_fit3(self, setup): + g = graphene(orthogonal=True) + gbig = g.repeat(40, 0).repeat(40, 1) + gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 + lattice = g.lattice.fit(gbig, axis=0) + assert np.allclose(lattice.cell[0, :], gbig.cell[0, :]) + assert np.allclose(lattice.cell[1:, :], g.cell[1:, :]) + + def test_fit4(self, setup): + g = graphene(orthogonal=True) + gbig = g.repeat(40, 0).repeat(40, 1) + gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 + lattice = g.lattice.fit(gbig, axis=[0, 1]) + assert np.allclose(lattice.cell[0:2, :], gbig.cell[0:2, :]) + assert np.allclose(lattice.cell[2, :], g.cell[2, :]) + + def test_parallel1(self, setup): + g = graphene(orthogonal=True) + gbig = g.repeat(40, 0).repeat(40, 1) + assert g.lattice.parallel(gbig.lattice) + assert gbig.lattice.parallel(g.lattice) + g = g.rotate(90, g.cell[0, :], what="abc") + assert not g.lattice.parallel(gbig.lattice) + + def test_tile_multiply_orthogonal(self): + lattice = graphene(orthogonal=True).lattice + assert np.allclose(lattice.tile(3, 0).tile(2, 1).tile(4, 2).cell, (lattice * (3, 2, 4)).cell) + assert np.allclose(lattice.tile(3, 0).tile(2, 1).cell, (lattice * [3, 2]).cell) + assert np.allclose(lattice.tile(3, 0).tile(3, 1).tile(3, 2).cell, (lattice * 3).cell) + + def test_tile_multiply_non_orthogonal(self): + lattice = graphene(orthogonal=False).lattice + assert np.allclose(lattice.tile(3, 0).tile(2, 1).tile(4, 2).cell, (lattice * (3, 2, 4)).cell) + assert np.allclose(lattice.tile(3, 0).tile(2, 1).cell, (lattice * [3, 2]).cell) + assert np.allclose(lattice.tile(3, 0).tile(3, 1).tile(3, 2).cell, (lattice * 3).cell) + + def test_angle1(self, setup): + g = graphene(orthogonal=True) + gbig = g.repeat(40, 0).repeat(40, 1) + assert g.lattice.angle(0, 1) == 90 + + def test_angle2(self, setup): + lattice = Lattice([1, 1, 1]) + assert lattice.angle(0, 1) == 90 + assert lattice.angle(0, 2) == 90 + assert lattice.angle(1, 2) == 90 + lattice = Lattice([[1, 1, 0], + [1, -1, 0], + [0, 0, 2]]) + assert lattice.angle(0, 1) == 90 + assert lattice.angle(0, 2) == 90 + assert lattice.angle(1, 2) == 90 + lattice = Lattice([[3, 4, 0], + [4, 3, 0], + [0, 0, 2]]) + assert lattice.angle(0, 1, rad=True) == approx(0.28379, abs=1e-4) + assert lattice.angle(0, 2) == 90 + assert lattice.angle(1, 2) == 90 + + def test_cell2length(self): + gr = graphene(orthogonal=True) + lattice = (gr * (40, 40, 1)).rotate(24, gr.cell[2, :]).lattice + assert np.allclose(lattice.length, (lattice.cell2length(lattice.length) ** 2).sum(1) ** 0.5) + assert np.allclose(1, (lattice.cell2length(1) ** 2).sum(0)) + + def test_set_lattice_off_wrong_size(self, setup): + lattice = setup.lattice.copy() + with pytest.raises(ValueError): + lattice.sc_off = np.zeros([10000, 3]) + + +def _dot(u, v): + """ Dot product u . v """ + return u[0] * v[0] + u[1] * v[1] + u[2] * v[2] + + +def test_plane1(): + lattice = Lattice([1] * 3) + # Check point [0.5, 0.5, 0.5] + pp = np.array([0.5] * 3) + + n, p = lattice.plane(0, 1, True) + assert -0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(0, 2, True) + assert -0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(1, 2, True) + assert -0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(0, 1, False) + assert -0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(0, 2, False) + assert -0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(1, 2, False) + assert -0.5 == approx(_dot(n, pp - p)) + + +def test_plane2(): + lattice = Lattice([1] * 3) + # Check point [-0.5, -0.5, -0.5] + pp = np.array([-0.5] * 3) + + n, p = lattice.plane(0, 1, True) + assert 0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(0, 2, True) + assert 0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(1, 2, True) + assert 0.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(0, 1, False) + assert -1.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(0, 2, False) + assert -1.5 == approx(_dot(n, pp - p)) + n, p = lattice.plane(1, 2, False) + assert -1.5 == approx(_dot(n, pp - p)) + + +def test_tocuboid_simple(): + lattice = Lattice([1, 1, 1, 90, 90, 90]) + c1 = lattice.toCuboid() + assert np.allclose(lattice.cell, c1._v) + c2 = lattice.toCuboid(True) + assert np.allclose(c1._v, c2._v) + + +def test_tocuboid_complex(): + lattice = Lattice([1, 1, 1, 60, 60, 60]) + s = str(lattice.cell) + c1 = lattice.toCuboid() + assert np.allclose(lattice.cell, c1._v) + c2 = lattice.toCuboid(True) + assert not np.allclose(np.diagonal(c1._v), np.diagonal(c2._v)) + + +def test_lattice_indices(): + lattice = Lattice([1] * 3, nsc=[3, 5, 7]) + for i in range(lattice.n_s): + assert i == lattice.sc_index(lattice.sc_off[i]) diff --git a/sisl/tests/test_plot.py b/sisl/tests/test_plot.py index a4eca08d9a..0c1b57e438 100644 --- a/sisl/tests/test_plot.py +++ b/sisl/tests/test_plot.py @@ -17,19 +17,19 @@ def test_supercell_2d(): g = sisl.geom.graphene() - sisl.plot(g.sc, axis=[0, 1]) - sisl.plot(g.sc, axis=[0, 2]) - sisl.plot(g.sc, axis=[1, 2]) + sisl.plot(g.lattice, axis=[0, 1]) + sisl.plot(g.lattice, axis=[0, 2]) + sisl.plot(g.lattice, axis=[1, 2]) plt.close('all') ax = plt.subplot(111) - sisl.plot(g.sc, axis=[1, 2], axes=ax) + sisl.plot(g.lattice, axis=[1, 2], axes=ax) plt.close('all') def test_supercell_3d(): g = sisl.geom.graphene() - sisl.plot(g.sc) + sisl.plot(g.lattice) plt.close('all') diff --git a/sisl/tests/test_sgeom.py b/sisl/tests/test_sgeom.py index 2b49bb9abc..a2b422f0ad 100644 --- a/sisl/tests/test_sgeom.py +++ b/sisl/tests/test_sgeom.py @@ -5,7 +5,7 @@ import math as m import numpy as np -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl.geometry import sgeom @@ -15,15 +15,15 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) C = Atom(Z=6, R=[bond * 1.01] * 2) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) - self.mol = Geometry([[i, 0, 0] for i in range(10)], sc=[50]) + self.mol = Geometry([[i, 0, 0] for i in range(10)], lattice=[50]) def sg_g(**kwargs): kwargs['ret_geometry'] = True @@ -57,22 +57,22 @@ def test_cite(self): sgeom(argv=['--cite']) def test_tile1(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[0, :] *= 2 for tile in ['tile 2 x', 'tile-x 2']: tx = setup.sg_g(argv=('--' + tile).split()) - assert np.allclose(cell, tx.sc.cell) + assert np.allclose(cell, tx.lattice.cell) cell[1, :] *= 2 for tile in ['tile 2 y', 'tile-y 2']: ty = setup.sg_g(geometry=tx, argv=('--' + tile).split()) - assert np.allclose(cell, ty.sc.cell) + assert np.allclose(cell, ty.lattice.cell) cell[2, :] *= 2 for tile in ['tile 2 z', 'tile-z 2']: tz = setup.sg_g(geometry=ty, argv=('--' + tile).split()) - assert np.allclose(cell, tz.sc.cell) + assert np.allclose(cell, tz.lattice.cell) def test_tile2(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[:, :] *= 2 for xt in ['tile 2 x', 'tile-x 2']: xt = '--' + xt @@ -82,25 +82,25 @@ def test_tile2(self, setup): zt = '--' + zt argv = ' '.join([xt, yt, zt]).split() t = setup.sg_g(argv=argv) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) def test_repeat1(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[0, :] *= 2 for repeat in ['repeat 2 x', 'repeat-x 2']: tx = setup.sg_g(argv=('--' + repeat).split()) - assert np.allclose(cell, tx.sc.cell) + assert np.allclose(cell, tx.lattice.cell) cell[1, :] *= 2 for repeat in ['repeat 2 y', 'repeat-y 2']: ty = setup.sg_g(geometry=tx, argv=('--' + repeat).split()) - assert np.allclose(cell, ty.sc.cell) + assert np.allclose(cell, ty.lattice.cell) cell[2, :] *= 2 for repeat in ['repeat 2 z', 'repeat-z 2']: tz = setup.sg_g(geometry=ty, argv=('--' + repeat).split()) - assert np.allclose(cell, tz.sc.cell) + assert np.allclose(cell, tz.lattice.cell) def test_repeat2(self, setup): - cell = np.copy(setup.g.sc.cell) + cell = np.copy(setup.g.lattice.cell) cell[:, :] *= 2 for xt in ['repeat 2 x', 'repeat-x 2']: xt = '--' + xt @@ -110,7 +110,7 @@ def test_repeat2(self, setup): zt = '--' + zt argv = ' '.join([xt, yt, zt]).split() t = setup.sg_g(argv=argv) - assert np.allclose(cell, t.sc.cell) + assert np.allclose(cell, t.lattice.cell) def test_sub1(self, setup): for a, l in [('0', 1), ('0,1', 2), ('0-1', 2)]: @@ -120,24 +120,24 @@ def test_sub1(self, setup): def test_rotation1(self, setup): print(setup.g.cell) rot = setup.sg_g(argv='--rotate 180 z'.split()) - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) print(setup.g.cell) rot = setup.sg_g(argv='--rotate-z 180'.split()) - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) rot = setup.sg_g(argv='--rotate rpi z'.split()) - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) rot = setup.sg_g(argv='--rotate-z rpi'.split()) - rot.sc.cell[2, 2] *= -1 - assert np.allclose(-rot.sc.cell, setup.g.sc.cell) + rot.lattice.cell[2, 2] *= -1 + assert np.allclose(-rot.lattice.cell, setup.g.lattice.cell) assert np.allclose(-rot.xyz, setup.g.xyz) def test_swap(self, setup): diff --git a/sisl/tests/test_sgrid.py b/sisl/tests/test_sgrid.py index 32a26a83ae..c1a7a05810 100644 --- a/sisl/tests/test_sgrid.py +++ b/sisl/tests/test_sgrid.py @@ -7,7 +7,7 @@ import numpy as np -from sisl import Geometry, Atom, SuperCell, Grid +from sisl import Geometry, Atom, Lattice, Grid from sisl.grid import sgrid from sisl import get_sile @@ -20,17 +20,17 @@ class t(): def __init__(self): bond = 1.42 sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) + self.lattice = Lattice(np.array([[1.5, sq3h, 0.], + [1.5, -sq3h, 0.], + [0., 0., 10.]], np.float64) * bond, nsc=[3, 3, 1]) C = Atom(Z=6, R=[bond * 1.01] * 2) self.g = Geometry(np.array([[0., 0., 0.], [1., 0., 0.]], np.float64) * bond, - atoms=C, sc=self.sc) + atoms=C, lattice=self.lattice) self.grid = Grid(0.2, geometry=self.g) self.grid.grid[:, :, :] = np.random.rand(*self.grid.shape) - self.mol = Geometry([[i, 0, 0] for i in range(10)], sc=[50]) + self.mol = Geometry([[i, 0, 0] for i in range(10)], lattice=[50]) self.grid_mol = Grid(0.2, geometry=self.mol) self.grid_mol.grid[:, :, :] = np.random.rand(*self.grid_mol.shape) diff --git a/sisl/tests/test_sparse_geometry.py b/sisl/tests/test_sparse_geometry.py index a4694c98af..295504826c 100644 --- a/sisl/tests/test_sparse_geometry.py +++ b/sisl/tests/test_sparse_geometry.py @@ -7,7 +7,7 @@ import numpy as np import scipy as sc -from sisl import Geometry, Atom, SuperCell +from sisl import Geometry, Atom, Lattice from sisl.geom import fcc, graphene from sisl.sparse_geometry import * @@ -134,7 +134,7 @@ def test_untile1(self, setup): def test_untile_wrong_usage(self): # one should not untile - geometry = Geometry([0] * 3, Atom(1, R=1.001), SuperCell(1, nsc=[1]* 3)) + geometry = Geometry([0] * 3, Atom(1, R=1.001), Lattice(1, nsc=[1]* 3)) geometry = geometry.tile(4, 0) s = SparseAtom(geometry) s.construct([[0.1, 1.01], [1, 2]]) @@ -150,7 +150,7 @@ def test_untile_wrong_usage(self): def test_untile_segment_single(self): # one should not untile - geometry = Geometry([0] * 3, Atom(1, R=1.001), SuperCell(1, nsc=[1]* 3)) + geometry = Geometry([0] * 3, Atom(1, R=1.001), Lattice(1, nsc=[1]* 3)) geometry = geometry.tile(4, 0) s = SparseAtom(geometry) s.construct([[0.1, 1.01], [1, 2]]) @@ -170,7 +170,7 @@ def test_untile_segment_three(self, axis): # one should not untile nsc = [3] * 3 nsc[axis] = 1 - geometry = Geometry([0] * 3, Atom(1, R=1.001), SuperCell(1, nsc=nsc)) + geometry = Geometry([0] * 3, Atom(1, R=1.001), Lattice(1, nsc=nsc)) geometry = geometry.tile(4, axis) s = SparseAtom(geometry) s.construct([[0.1, 1.01], [1, 2]]) @@ -540,7 +540,7 @@ def test_sparse_atom_symmetric(n0, n1, n2): # Figure out the transposed supercell indices of the edges isc = - s.geometry.a2isc(edges) # Convert to supercell - IA = s.geometry.sc.sc_index(isc) * na + ia + IA = s.geometry.lattice.sc_index(isc) * na + ia # Figure out if 'ia' is also in the back-edges for ja, edge in zip(IA, edges % na): assert ja in s.edges(edge) @@ -617,14 +617,14 @@ def test_sparse_orbital_add_axis(setup): s = SparseOrbital(g) s.construct([[0.1, 1.5], [1, 2]]) s1 = s.add(s, axis=2) - s2 = SparseOrbital(g.append(SuperCell([0, 0, 10]), 2).add(g, offset=[0, 0, 5])) + s2 = SparseOrbital(g.append(Lattice([0, 0, 10]), 2).add(g, offset=[0, 0, 5])) s2.construct([[0.1, 1.5], [1, 2]]) assert s1.spsame(s2) def test_sparse_orbital_add_no_axis(): from sisl.geom import sc - g = (sc(1., Atom(1, R=1.5)) * 2).add(SuperCell([0, 0, 5])) + g = (sc(1., Atom(1, R=1.5)) * 2).add(Lattice([0, 0, 5])) s = SparseOrbital(g) s.construct([[0.1, 1.5], [1, 2]]) s1 = s.add(s, offset=[0, 0, 3]) diff --git a/sisl/tests/test_sparse_orbital.py b/sisl/tests/test_sparse_orbital.py index c9d51cb988..89c2eaae22 100644 --- a/sisl/tests/test_sparse_orbital.py +++ b/sisl/tests/test_sparse_orbital.py @@ -7,7 +7,7 @@ import numpy as np import scipy as sc -from sisl import Geometry, Atom, SuperCell, Cuboid +from sisl import Geometry, Atom, Lattice, Cuboid from sisl.geom import fcc, graphene from sisl.sparse_geometry import * import sisl.messages as sm @@ -35,7 +35,7 @@ def test_sparse_orbital_symmetric(n0, n1, n2): # Figure out the transposed supercell indices of the edges isc = - s.geometry.o2isc(edges) # Convert to supercell - IO = s.geometry.sc.sc_index(isc) * no + io + IO = s.geometry.lattice.sc_index(isc) * no + io # Figure out if 'io' is also in the back-edges for jo, edge in zip(IO, edges % no): assert jo in s.edges(edge) @@ -134,7 +134,7 @@ def test_sparse_orbital_append_scale(n0, n1, n2, axis): def test_sparse_orbital_hermitian(): - g = Geometry([0] * 3, Atom(1, R=1), sc=SuperCell(1, nsc=[3, 1, 1])) + g = Geometry([0] * 3, Atom(1, R=1), sc=Lattice(1, nsc=[3, 1, 1])) for f in [True, False]: spo = SparseOrbital(g) @@ -167,7 +167,7 @@ def test_sparse_orbital_hermitian(): def test_sparse_orbital_sub_orbital(): a0 = Atom(1, R=(1.1, 1.4, 1.6)) a1 = Atom(2, R=(1.3, 1.1)) - g = Geometry([[0, 0, 0], [1, 1, 1]], [a0, a1], sc=SuperCell(2, nsc=[3, 1, 1])) + g = Geometry([[0, 0, 0], [1, 1, 1]], [a0, a1], sc=Lattice(2, nsc=[3, 1, 1])) g = g.tile(3, 0) assert g.no == 15 @@ -250,7 +250,7 @@ def test_sparse_orbital_sub_orbital_nested(): """ a0 = Atom(1, R=(1.1, 1.4, 1.6)) a1 = Atom(2, R=(1.3, 1.1)) - g = Geometry([[0, 0, 0], [1, 1, 1]], [a0, a1], sc=SuperCell(2, nsc=[3, 1, 1])) + g = Geometry([[0, 0, 0], [1, 1, 1]], [a0, a1], sc=Lattice(2, nsc=[3, 1, 1])) g = g.repeat(3, 0) assert g.no == 15 @@ -360,7 +360,7 @@ def create_sp(geom): # now replace every position that can be replaced for y in [0, 2, 3]: for x in [1, 2, 3]: - cube = Cuboid(hole.sc.cell, origin=g.sc.offset([x, y, 0]) - 0.1) + cube = Cuboid(hole.lattice.cell, origin=g.lattice.offset([x, y, 0]) - 0.1) atoms = big.within(cube) assert len(atoms) == 4 * 6 * 6 new = big.replace(atoms, hole) @@ -402,7 +402,7 @@ def create_sp(geom): # now replace every position that can be replaced for y in [0, 3]: for x in [1, 3]: - cube = Cuboid(hole.sc.cell, origin=g.sc.offset([x, y, 0]) - 0.1) + cube = Cuboid(hole.lattice.cell, origin=g.lattice.offset([x, y, 0]) - 0.1) atoms = big.within(cube) assert len(atoms) == 4 * 6 * 6 new = big.replace(atoms, hole) diff --git a/sisl/tests/test_supercell.py b/sisl/tests/test_supercell.py deleted file mode 100644 index 310aedf9bc..0000000000 --- a/sisl/tests/test_supercell.py +++ /dev/null @@ -1,457 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. -import pytest -from pytest import approx - -import math as m -import numpy as np - -import sisl.linalg as lin -from sisl import SuperCell, SuperCellChild -from sisl.geom import graphene - - -pytestmark = [pytest.mark.supercell, pytest.mark.sc] - - -@pytest.fixture -def setup(): - class t(): - def __init__(self): - alat = 1.42 - sq3h = 3.**.5 * 0.5 - self.sc = SuperCell(np.array([[1.5, sq3h, 0.], - [1.5, -sq3h, 0.], - [0., 0., 10.]], np.float64) * alat, nsc=[3, 3, 1]) - return t() - - -class TestSuperCell: - - def test_str(self, setup): - str(setup.sc) - str(setup.sc) - assert setup.sc != 'Not a SuperCell' - - def test_nsc1(self, setup): - sc = setup.sc.copy() - sc.set_nsc([5, 5, 0]) - assert np.allclose([5, 5, 1], sc.nsc) - assert len(sc.sc_off) == np.prod(sc.nsc) - - def test_nsc2(self, setup): - sc = setup.sc.copy() - sc.set_nsc([0, 1, 0]) - assert np.allclose([1, 1, 1], sc.nsc) - assert len(sc.sc_off) == np.prod(sc.nsc) - sc.set_nsc(a=3) - assert np.allclose([3, 1, 1], sc.nsc) - assert len(sc.sc_off) == np.prod(sc.nsc) - sc.set_nsc(b=3) - assert np.allclose([3, 3, 1], sc.nsc) - assert len(sc.sc_off) == np.prod(sc.nsc) - sc.set_nsc(c=5) - assert np.allclose([3, 3, 5], sc.nsc) - assert len(sc.sc_off) == np.prod(sc.nsc) - - def test_nsc3(self, setup): - assert setup.sc.sc_index([0, 0, 0]) == 0 - for s in range(setup.sc.n_s): - assert setup.sc.sc_index(setup.sc.sc_off[s, :]) == s - arng = np.arange(setup.sc.n_s) - np.random.seed(42) - np.random.shuffle(arng) - sc_off = setup.sc.sc_off[arng, :] - assert np.all(setup.sc.sc_index(sc_off) == arng) - - def test_nsc_fail_even(self, setup): - with pytest.raises(ValueError): - setup.sc.set_nsc(a=2) - - def test_nsc_fail_even_and_odd(self, setup): - with pytest.raises(ValueError): - setup.sc.set_nsc([1, 2, 3]) - - def test_area1(self, setup): - setup.sc.area(0, 1) - - def test_fill(self, setup): - sc = setup.sc.swapaxes(1, 2) - i = sc._fill([1, 1]) - assert i.dtype == np.int32 - i = sc._fill([1., 1.]) - assert i.dtype == np.float64 - for dt in [np.int32, np.float32, np.float64, np.complex64]: - i = sc._fill([1., 1.], dt) - assert i.dtype == dt - i = sc._fill(np.ones([2], dt)) - assert i.dtype == dt - - def test_add_vacuum1(self, setup): - sc = setup.sc.copy() - for i in range(3): - s = sc.add_vacuum(10, i) - ax = setup.sc.cell[i, :] - ax += ax / np.sum(ax ** 2) ** .5 * 10 - assert np.allclose(ax, s.cell[i, :]) - - def test_add1(self, setup): - sc = setup.sc.copy() - for R in range(1, 10): - s = sc + R - assert np.allclose(s.cell, sc.cell + np.diag([R] * 3)) - - def test_rotation1(self, setup): - rot = setup.sc.rotate(180, [0, 0, 1]) - rot.cell[2, 2] *= -1 - assert np.allclose(-rot.cell, setup.sc.cell) - - rot = setup.sc.rotate(m.pi, [0, 0, 1], rad=True) - rot.cell[2, 2] *= -1 - assert np.allclose(-rot.cell, setup.sc.cell) - - rot = rot.rotate(180, [0, 0, 1]) - rot.cell[2, 2] *= -1 - assert np.allclose(rot.cell, setup.sc.cell) - - def test_rotation2(self, setup): - rot = setup.sc.rotate(180, setup.sc.cell[2, :]) - rot.cell[2, 2] *= -1 - assert np.allclose(-rot.cell, setup.sc.cell) - - rot = setup.sc.rotate(m.pi, setup.sc.cell[2, :], rad=True) - rot.cell[2, 2] *= -1 - assert np.allclose(-rot.cell, setup.sc.cell) - - rot = rot.rotate(180, setup.sc.cell[2, :]) - rot.cell[2, 2] *= -1 - assert np.allclose(rot.cell, setup.sc.cell) - - @pytest.mark.parametrize("a,b", [[0, 1], [0, 2], [1, 2]]) - def test_swapaxes_lattice_vector(self, setup, a, b): - sc = setup.sc - sab = sc.swapaxes(a, b) - assert np.allclose(sc.origin, sab.origin) - assert np.allclose(sc.nsc[[b, a]], sab.nsc[[a, b]]) - assert np.allclose(sc.cell[[b, a]], sab.cell[[a, b]]) - - # and string input - sab = setup.sc.swapaxes("abc"[a], "abc"[b]) - assert np.allclose(sab.cell[[b, a]], setup.sc.cell[[a, b]]) - assert np.allclose(sab.origin, setup.sc.origin) - assert np.allclose(sab.nsc[[b, a]], setup.sc.nsc[[a, b]]) - - @pytest.mark.parametrize("a,b", [[0, 1], [0, 2], [1, 2]]) - def test_swapaxes_xyz(self, setup, a, b): - sc = setup.sc - sab = sc.swapaxes(1, 2, "xyz") - assert np.allclose(sc.nsc, sab.nsc) - assert np.allclose(sc.origin[[b, a]], sab.origin[[a, b]]) - assert np.allclose(sc.origin[[b, a]], sab.origin[[a, b]]) - - # and string input - sab = setup.sc.swapaxes("xyz"[a], "xyz"[b]) - assert np.allclose(sc.nsc, sab.nsc) - assert np.allclose(sc.origin[[b, a]], sab.origin[[a, b]]) - assert np.allclose(sc.origin[[b, a]], sab.origin[[a, b]]) - - def test_swapaxes_complicated(self, setup): - - # swap a couple of lattice vectors and cartesian coordinates - a = "azby" - b = "bxcz" - # this will result in - # 0. abc, xyz - # 1. bac, xyz - # 2. bac, zyx - # 3. bca, zyx - # 4. bca, zxy - sab = setup.sc.swapaxes(a, b) - idx_abc = [1, 2, 0] - idx_xyz = [2, 0, 1] - assert np.allclose(sab.cell, setup.sc.cell[idx_abc][:, idx_xyz]) - assert np.allclose(sab.origin, setup.sc.origin[idx_xyz]) - assert np.allclose(sab.nsc, setup.sc.nsc[idx_abc]) - - def test_offset1(self, setup): - off = setup.sc.offset() - assert np.allclose(off, [0, 0, 0]) - off = setup.sc.offset([1, 1, 1]) - cell = setup.sc.cell[:, :] - assert np.allclose(off, cell[0, :] + cell[1, :] + cell[2, :]) - - def test_sc_index1(self, setup): - sc_index = setup.sc.sc_index([0, 0, 0]) - assert sc_index == 0 - sc_index = setup.sc.sc_index([0, 0, None]) - assert len(sc_index) == setup.sc.nsc[2] - - def test_sc_index2(self, setup): - sc_index = setup.sc.sc_index([[0, 0, 0], - [1, 1, 0]]) - s = str(sc_index) - assert len(sc_index) == 2 - - def test_sc_index3(self, setup): - with pytest.raises(Exception): - setup.sc.sc_index([100, 100, 100]) - - def test_vertices(self, setup): - verts = setup.sc.vertices() - - assert verts.shape == (2, 2, 2, 3) - assert np.allclose(verts[0, 0, 0], [0, 0, 0]) - assert np.allclose(verts[1, 0, 0], setup.sc.cell[0]) - assert np.allclose(verts[1, 1, 1], setup.sc.cell.sum(axis=0)) - - def test_untile1(self, setup): - cut = setup.sc.untile(2, 0) - assert np.allclose(cut.cell[0, :] * 2, setup.sc.cell[0, :]) - assert np.allclose(cut.cell[1, :], setup.sc.cell[1, :]) - - def test_creation1(self, setup): - # full cell - tmp1 = SuperCell([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) - # diagonal cell - tmp2 = SuperCell([1, 1, 1]) - # cell parameters - tmp3 = SuperCell([1, 1, 1, 90, 90, 90]) - tmp4 = SuperCell([1]) - assert np.allclose(tmp1.cell, tmp2.cell) - assert np.allclose(tmp1.cell, tmp3.cell) - assert np.allclose(tmp1.cell, tmp4.cell) - - def test_creation2(self, setup): - # full cell - class P(SuperCellChild): - - def copy(self): - a = P() - a.set_supercell(setup.sc) - return a - tmp1 = P() - tmp1.set_supercell([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) - # diagonal cell - tmp2 = P() - tmp2.set_supercell([1, 1, 1]) - # cell parameters - tmp3 = P() - tmp3.set_supercell([1, 1, 1, 90, 90, 90]) - tmp4 = P() - tmp4.set_supercell([1]) - assert np.allclose(tmp1.cell, tmp2.cell) - assert np.allclose(tmp1.cell, tmp3.cell) - assert np.allclose(tmp1.cell, tmp4.cell) - assert len(tmp1._fill([0, 0, 0])) == 3 - assert len(tmp1._fill_sc([0, 0, 0])) == 3 - assert tmp1.is_orthogonal() - for i in range(3): - t2 = tmp2.add_vacuum(10, i) - assert tmp1.cell[i, i] + 10 == t2.cell[i, i] - - def test_creation3(self, setup): - with pytest.raises(ValueError): - setup.sc.tocell([3, 6]) - - def test_creation4(self, setup): - with pytest.raises(ValueError): - setup.sc.tocell([3, 4, 5, 6]) - - def test_creation5(self, setup): - with pytest.raises(ValueError): - setup.sc.tocell([3, 4, 5, 6, 7, 6, 7]) - - def test_creation_rotate(self, setup): - # cell parameters - param = np.array([1, 2, 3, 45, 60, 80], np.float64) - parama = param.copy() - parama[3:] *= np.pi / 180 - sc = SuperCell(param) - assert np.allclose(param, sc.parameters()) - assert np.allclose(parama, sc.parameters(True)) - for ang in range(0, 91, 5): - s = sc.rotate(ang, sc.cell[0, :]).rotate(ang, sc.cell[1, :]).rotate(ang, sc.cell[2, :]) - assert np.allclose(param, s.parameters()) - assert np.allclose(parama, s.parameters(True)) - - def test_rcell(self, setup): - # LAPACK inverse algorithm implicitly does - # a transpose. - rcell = lin.inv(setup.sc.cell) * 2. * np.pi - assert np.allclose(rcell.T, setup.sc.rcell) - assert np.allclose(rcell.T / (2 * np.pi), setup.sc.icell) - - def test_icell(self, setup): - assert np.allclose(setup.sc.rcell, setup.sc.icell * 2 * np.pi) - - def test_translate1(self, setup): - sc = setup.sc.translate([0, 0, 10]) - assert np.allclose(sc.cell[2, :2], setup.sc.cell[2, :2]) - assert np.allclose(sc.cell[2, 2], setup.sc.cell[2, 2]+10) - - def test_center1(self, setup): - assert np.allclose(setup.sc.center(), np.sum(setup.sc.cell, axis=0) / 2) - for i in [0, 1, 2]: - assert np.allclose(setup.sc.center(i), setup.sc.cell[i, :] / 2) - - def test_pickle(self, setup): - import pickle as p - s = p.dumps(setup.sc) - n = p.loads(s) - assert setup.sc == n - s = SuperCell([1, 1, 1]) - assert setup.sc != s - - def test_orthogonal(self, setup): - assert not setup.sc.is_orthogonal() - - def test_fit1(self, setup): - g = graphene() - gbig = g.repeat(40, 0).repeat(40, 1) - gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 - sc = g.sc.fit(gbig) - assert np.allclose(sc.cell, gbig.cell) - - def test_fit2(self, setup): - g = graphene(orthogonal=True) - gbig = g.repeat(40, 0).repeat(40, 1) - gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 - sc = g.sc.fit(gbig) - assert np.allclose(sc.cell, gbig.cell) - - def test_fit3(self, setup): - g = graphene(orthogonal=True) - gbig = g.repeat(40, 0).repeat(40, 1) - gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 - sc = g.sc.fit(gbig, axis=0) - assert np.allclose(sc.cell[0, :], gbig.cell[0, :]) - assert np.allclose(sc.cell[1:, :], g.cell[1:, :]) - - def test_fit4(self, setup): - g = graphene(orthogonal=True) - gbig = g.repeat(40, 0).repeat(40, 1) - gbig.xyz[:, :] += (np.random.rand(len(gbig), 3) - 0.5) * 0.01 - sc = g.sc.fit(gbig, axis=[0, 1]) - assert np.allclose(sc.cell[0:2, :], gbig.cell[0:2, :]) - assert np.allclose(sc.cell[2, :], g.cell[2, :]) - - def test_parallel1(self, setup): - g = graphene(orthogonal=True) - gbig = g.repeat(40, 0).repeat(40, 1) - assert g.sc.parallel(gbig.sc) - assert gbig.sc.parallel(g.sc) - g = g.rotate(90, g.cell[0, :], what="abc") - assert not g.sc.parallel(gbig.sc) - - def test_tile_multiply_orthogonal(self): - sc = graphene(orthogonal=True).sc - assert np.allclose(sc.tile(3, 0).tile(2, 1).tile(4, 2).cell, (sc * (3, 2, 4)).cell) - assert np.allclose(sc.tile(3, 0).tile(2, 1).cell, (sc * [3, 2]).cell) - assert np.allclose(sc.tile(3, 0).tile(3, 1).tile(3, 2).cell, (sc * 3).cell) - - def test_tile_multiply_non_orthogonal(self): - sc = graphene(orthogonal=False).sc - assert np.allclose(sc.tile(3, 0).tile(2, 1).tile(4, 2).cell, (sc * (3, 2, 4)).cell) - assert np.allclose(sc.tile(3, 0).tile(2, 1).cell, (sc * [3, 2]).cell) - assert np.allclose(sc.tile(3, 0).tile(3, 1).tile(3, 2).cell, (sc * 3).cell) - - def test_angle1(self, setup): - g = graphene(orthogonal=True) - gbig = g.repeat(40, 0).repeat(40, 1) - assert g.sc.angle(0, 1) == 90 - - def test_angle2(self, setup): - sc = SuperCell([1, 1, 1]) - assert sc.angle(0, 1) == 90 - assert sc.angle(0, 2) == 90 - assert sc.angle(1, 2) == 90 - sc = SuperCell([[1, 1, 0], - [1, -1, 0], - [0, 0, 2]]) - assert sc.angle(0, 1) == 90 - assert sc.angle(0, 2) == 90 - assert sc.angle(1, 2) == 90 - sc = SuperCell([[3, 4, 0], - [4, 3, 0], - [0, 0, 2]]) - assert sc.angle(0, 1, rad=True) == approx(0.28379, abs=1e-4) - assert sc.angle(0, 2) == 90 - assert sc.angle(1, 2) == 90 - - def test_cell2length(self): - gr = graphene(orthogonal=True) - sc = (gr * (40, 40, 1)).rotate(24, gr.cell[2, :]).sc - assert np.allclose(sc.length, (sc.cell2length(sc.length) ** 2).sum(1) ** 0.5) - assert np.allclose(1, (sc.cell2length(1) ** 2).sum(0)) - - def test_set_sc_off_wrong_size(self, setup): - sc = setup.sc.copy() - with pytest.raises(ValueError): - sc.sc_off = np.zeros([10000, 3]) - - -def _dot(u, v): - """ Dot product u . v """ - return u[0] * v[0] + u[1] * v[1] + u[2] * v[2] - - -def test_plane1(): - sc = SuperCell([1] * 3) - # Check point [0.5, 0.5, 0.5] - pp = np.array([0.5] * 3) - - n, p = sc.plane(0, 1, True) - assert -0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(0, 2, True) - assert -0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(1, 2, True) - assert -0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(0, 1, False) - assert -0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(0, 2, False) - assert -0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(1, 2, False) - assert -0.5 == approx(_dot(n, pp - p)) - - -def test_plane2(): - sc = SuperCell([1] * 3) - # Check point [-0.5, -0.5, -0.5] - pp = np.array([-0.5] * 3) - - n, p = sc.plane(0, 1, True) - assert 0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(0, 2, True) - assert 0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(1, 2, True) - assert 0.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(0, 1, False) - assert -1.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(0, 2, False) - assert -1.5 == approx(_dot(n, pp - p)) - n, p = sc.plane(1, 2, False) - assert -1.5 == approx(_dot(n, pp - p)) - - -def test_tocuboid_simple(): - sc = SuperCell([1, 1, 1, 90, 90, 90]) - c1 = sc.toCuboid() - assert np.allclose(sc.cell, c1._v) - c2 = sc.toCuboid(True) - assert np.allclose(c1._v, c2._v) - - -def test_tocuboid_complex(): - sc = SuperCell([1, 1, 1, 60, 60, 60]) - s = str(sc.cell) - c1 = sc.toCuboid() - assert np.allclose(sc.cell, c1._v) - c2 = sc.toCuboid(True) - assert not np.allclose(np.diagonal(c1._v), np.diagonal(c2._v)) - - -def test_sc_indices(): - sc = SuperCell([1] * 3, nsc=[3, 5, 7]) - for i in range(sc.n_s): - assert i == sc.sc_index(sc.sc_off[i]) diff --git a/sisl/typing/_common.py b/sisl/typing/_common.py index 30025b7c7a..006245271e 100644 --- a/sisl/typing/_common.py +++ b/sisl/typing/_common.py @@ -8,7 +8,7 @@ Atoms, Shape, Geometry, - SuperCell + Lattice ) from sisl._category import GenericCategory from sisl.geom.category import AtomCategory @@ -34,6 +34,6 @@ ] CellOrGeometry = Union[ - SuperCell, + Lattice, Geometry ] diff --git a/sisl/viz/plots/bond_length.py b/sisl/viz/plots/bond_length.py index f51213c063..d73a6e1d7a 100644 --- a/sisl/viz/plots/bond_length.py +++ b/sisl/viz/plots/bond_length.py @@ -375,7 +375,7 @@ def _set_data(self, strain, axes, atoms, show_atoms, bind_bonds_to_ats, points_p if show_strain: self.bonds = self.relaxed_bonds - self.geometry.set_nsc(self.relaxed_geom.sc.nsc) + self.geometry.set_nsc(self.relaxed_geom.lattice.nsc) else: self.bonds = self.geom_bonds diff --git a/sisl/viz/plots/geometry.py b/sisl/viz/plots/geometry.py index b3818ed7fe..babaafa204 100644 --- a/sisl/viz/plots/geometry.py +++ b/sisl/viz/plots/geometry.py @@ -20,7 +20,7 @@ ) from ..plotutils import values_to_colors from sisl._dispatcher import AbstractDispatch -from sisl._supercell import cell_invert +from sisl._lattice import cell_invert class BoundGeometry(AbstractDispatch): diff --git a/sisl/viz/plots/grid.py b/sisl/viz/plots/grid.py index c5330c2d15..6cba925580 100644 --- a/sisl/viz/plots/grid.py +++ b/sisl/viz/plots/grid.py @@ -8,7 +8,7 @@ import sisl from sisl.messages import warn -from sisl._supercell import cell_invert +from sisl._lattice import cell_invert from sisl import _array as _a from ..plot import Plot, entry_point from ..input_fields import ( @@ -877,7 +877,7 @@ def _transform_grid_cell(grid, cell=np.eye(3), output_shape=None, mode="constant # Create a new grid with the new shape and the new cell (notice how the cell # is rescaled from the input cell to fit the actual coordinates of the system) - new_grid = grid.__class__((1, 1, 1), sc=cell*lengths.reshape(3, 1)) + new_grid = grid.__class__((1, 1, 1), lattice=cell*lengths.reshape(3, 1)) new_grid.grid = transformed_image # Find the offset between the origin before and after the transformation @@ -1065,7 +1065,7 @@ def scan(self, along, start=None, stop=None, step=None, num=None, breakpoints=No if mode == "as_is" and set(axes) - set(["x", "y", "z"]): raise ValueError("To perform a scan, the axes need to be cartesian. Please set the axes to a combination of 'x', 'y' and 'z'.") - if self.grid.sc.is_cartesian(): + if self.grid.lattice.is_cartesian(): grid = self.grid else: transform_bc = kwargs.pop("transform_bc", self.get_setting("transform_bc")) diff --git a/sisl/viz/plots/tests/test_grid.py b/sisl/viz/plots/tests/test_grid.py index 2561819578..af62f32dd5 100644 --- a/sisl/viz/plots/tests/test_grid.py +++ b/sisl/viz/plots/tests/test_grid.py @@ -54,7 +54,7 @@ def init_func_and_attrs(self, request, siesta_test_files, vasp_test_files): complex_grid_shape = (8, 10, 10) np.random.seed(1) values = np.random.random(complex_grid_shape).astype(np.complex128) + np.random.random(complex_grid_shape) * 1j - complex_grid = sisl.Grid(complex_grid_shape, sc=1) + complex_grid = sisl.Grid(complex_grid_shape, lattice=1) complex_grid.grid = values init_func = complex_grid.plot diff --git a/toolbox/transiesta/poisson/fftpoisson_fix.py b/toolbox/transiesta/poisson/fftpoisson_fix.py index 3f5402670c..43ce200649 100644 --- a/toolbox/transiesta/poisson/fftpoisson_fix.py +++ b/toolbox/transiesta/poisson/fftpoisson_fix.py @@ -245,7 +245,7 @@ def sl2idx(grid, sl): import matplotlib.pyplot as plt slicex3 = np.index_exp[:] * 3 axs = [ - np.linspace(0, grid.sc.length[ax], shape, endpoint=False) + np.linspace(0, grid.lattice.length[ax], shape, endpoint=False) for ax, shape in enumerate(grid.shape) ] @@ -395,7 +395,7 @@ def fftpoisson_fix_run(args): dat = V.average(args.plot) import matplotlib.pyplot as plt axs = [ - np.linspace(0, V.sc.length[ax], shape, endpoint=False) for ax, shape in enumerate(V.shape) + np.linspace(0, V.lattice.length[ax], shape, endpoint=False) for ax, shape in enumerate(V.shape) ] idx = list(range(3))