From 50cdb3821b9fc3bf7d9af2654e7d03d61c7e6be9 Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Thu, 7 Nov 2024 14:13:57 +0100 Subject: [PATCH 1/5] enabled ellipsis here and there Should be improved so None fully gets removed. Signed-off-by: Nick Papior --- CHANGELOG.md | 4 ++++ src/sisl/io/_multiple.py | 4 ++++ src/sisl/io/siesta/stdout.py | 25 +++++++++++++++---------- src/sisl/io/siesta/tests/test_stdout.py | 2 ++ 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bc44dd8b8..2a94bbf413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,10 @@ we hit release version 1.0.0. with *many* edges in the sparse matrix, but a perf. hit for very small TB matrices. - dtype removed from `Spin` class +- enabled `...` when extracting slices of MD steps. + Here it is the same as `:`. But it also allows + inline arguments: `read_scf(imd=...)` where `imd=:` is not + allowed, partly fixes #835 ## [0.15.2] - 2024-11-06 diff --git a/src/sisl/io/_multiple.py b/src/sisl/io/_multiple.py index abaaf21d56..565b642565 100644 --- a/src/sisl/io/_multiple.py +++ b/src/sisl/io/_multiple.py @@ -109,6 +109,10 @@ def __call__(self, *args, **kwargs): start = 0 stop = inf + if key is Ellipsis: + # Allow [...] to extract all" + key = slice(None) + if isinstance(key, Integral): if key >= 0: start = key diff --git a/src/sisl/io/siesta/stdout.py b/src/sisl/io/siesta/stdout.py index 89b73a71f4..27e8852d47 100644 --- a/src/sisl/io/siesta/stdout.py +++ b/src/sisl/io/siesta/stdout.py @@ -830,7 +830,7 @@ def read_data(self, *args, **kwargs) -> Any: def read_scf( self, key: str = "scf", - iscf: Optional[int] = -1, + iscf: Optional[Union[int, Ellipsis]] = -1, as_dataframe: bool = False, ret_header: bool = False, ): @@ -842,7 +842,7 @@ def read_scf( parse SCF information from Siesta SCF or TranSiesta SCF iscf : which SCF cycle should be stored. If ``-1`` only the final SCF step is stored, - for None *all* SCF cycles are returned. When `iscf` values queried are not found they + for `...`/`None` *all* SCF cycles are returned. When `iscf` values queried are not found they will be truncated to the nearest SCF step. as_dataframe: whether the information should be returned as a `pandas.DataFrame`. The advantage of this @@ -856,7 +856,9 @@ def read_scf( # These are the properties that are written in SIESTA scf props = ["iscf", "Eharris", "E_KS", "FreeEng", "dDmax", "Ef", "dHmax"] - if not iscf is None: + if iscf is Ellipsis: + iscf = None + elif iscf is not None: if iscf == 0: raise ValueError( f"{self.__class__.__name__}.read_scf requires iscf argument to *not* be 0!" @@ -1086,8 +1088,8 @@ def construct_data(d, data): def read_charge( self, name: Literal["voronoi", "hirshfeld", "mulliken", "mulliken:<5.2"], - iscf=Opt.ANY, - imd=Opt.ANY, + iscf: Union[Opt, int, Ellipsis] = Opt.ANY, + imd: Union[Opt, int, Ellipsis] = Opt.ANY, key_scf: str = "scf", as_dataframe: bool = False, ): @@ -1129,15 +1131,15 @@ def read_charge( ---------- name: the name of the charges that you want to read - iscf: int or Opt, optional + iscf: int or Opt or `...`, optional index (0-based) of the scf iteration you want the charges for. - If the enum specifier `Opt.ANY` or `Opt.ALL` are used, then + If the enum specifier `Opt.ANY` or `Opt.ALL`/`...` are used, then the returned quantities depend on what is present. If ``None/Opt.NONE`` it will not return any SCF charges. If both `imd` and `iscf` are ``None`` then only the final charges will be returned. imd: int or Opt, optional index (0-based) of the md step you want the charges for. - If the enum specifier `Opt.ANY` or `Opt.ALL` are used, then + If the enum specifier `Opt.ANY` or `Opt.ALL`/`...` are used, then the returned quantities depend on what is present. If ``None/Opt.NONE`` it will not return any MD charges. If both `imd` and `iscf` are ``None`` then only the final charges will be returned. @@ -1570,9 +1572,9 @@ def try_parse_int(s): md_scf_charge = pd.concat( [ pd.concat( - iscf, keys=pd.RangeIndex(1, len(iscf) + 1, name="iscf") + iscf_, keys=pd.RangeIndex(1, len(iscf_) + 1, name="iscf") ) - for iscf in md_scf_charge + for iscf_ in md_scf_charge ], keys=pd.RangeIndex(1, len(md_scf_charge) + 1, name="imd"), ) @@ -1607,6 +1609,9 @@ def _p(flag, found): flag : corrected flag """ + if flag is Ellipsis: + flag = Opt.ALL + if isinstance(flag, Opt): # correct flag depending on what `found` is # If the values have been found we diff --git a/src/sisl/io/siesta/tests/test_stdout.py b/src/sisl/io/siesta/tests/test_stdout.py index a6e3e8d475..3d4d096d50 100644 --- a/src/sisl/io/siesta/tests/test_stdout.py +++ b/src/sisl/io/siesta/tests/test_stdout.py @@ -40,6 +40,8 @@ def test_mgco3_md_out(sisl_files): assert len(out.read_geometry[:]()) == nOutputs assert len(out.read_force[:]()) == nOutputs assert len(out.read_stress[:]()) == nOutputs + # slicing using ellipsis (same as above) + assert len(out.read_stress[...]()) == nOutputs f0 = out.read_force() f = out.read_force[-1]() From aa07623a081b4ff4c8d3bd3431cb0f3e37f34ad0 Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Thu, 7 Nov 2024 21:42:04 +0100 Subject: [PATCH 2/5] reverted ... in getitem for read_ methods Signed-off-by: Nick Papior --- src/sisl/io/_multiple.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sisl/io/_multiple.py b/src/sisl/io/_multiple.py index 565b642565..abaaf21d56 100644 --- a/src/sisl/io/_multiple.py +++ b/src/sisl/io/_multiple.py @@ -109,10 +109,6 @@ def __call__(self, *args, **kwargs): start = 0 stop = inf - if key is Ellipsis: - # Allow [...] to extract all" - key = slice(None) - if isinstance(key, Integral): if key >= 0: start = key From a106df400f26604b07c3ad1557fd7954a8e2132c Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Thu, 5 Dec 2024 15:14:20 +0100 Subject: [PATCH 3/5] removed faulty test Signed-off-by: Nick Papior --- src/sisl/io/siesta/tests/test_stdout.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sisl/io/siesta/tests/test_stdout.py b/src/sisl/io/siesta/tests/test_stdout.py index 3d4d096d50..a6e3e8d475 100644 --- a/src/sisl/io/siesta/tests/test_stdout.py +++ b/src/sisl/io/siesta/tests/test_stdout.py @@ -40,8 +40,6 @@ def test_mgco3_md_out(sisl_files): assert len(out.read_geometry[:]()) == nOutputs assert len(out.read_force[:]()) == nOutputs assert len(out.read_stress[:]()) == nOutputs - # slicing using ellipsis (same as above) - assert len(out.read_stress[...]()) == nOutputs f0 = out.read_force() f = out.read_force[-1]() From fbf8905cbcd3e15cbfe72c07193a68b3bdf6b2fa Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Thu, 5 Dec 2024 15:26:37 +0100 Subject: [PATCH 4/5] Enabled ... for atoms, orbitals arguments This seems a bit more natural than None. Signed-off-by: Nick Papior --- CHANGELOG.md | 10 ++++++---- src/sisl/_core/geometry.py | 5 +++++ src/sisl/_core/tests/test_geometry.py | 5 +++++ src/sisl/typing/_indices.py | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a94bbf413..7ce7eecc7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,12 @@ we hit release version 1.0.0. sisl.geom.graphene - added Nambu spin configuration, this is still experimental +- enabled `...` when extracting slices of MD steps in siesta output + files. + Here it is the same as `:`. But it also allows + inline arguments: `read_scf(imd=...)` where `imd=:` is not + allowed, partly fixes #835 +- enabled `...` for `atoms=` arguments. Selects all atoms. ### Fixed - `projection` arguments of several functions has been streamlined @@ -29,10 +35,6 @@ we hit release version 1.0.0. with *many* edges in the sparse matrix, but a perf. hit for very small TB matrices. - dtype removed from `Spin` class -- enabled `...` when extracting slices of MD steps. - Here it is the same as `:`. But it also allows - inline arguments: `read_scf(imd=...)` where `imd=:` is not - allowed, partly fixes #835 ## [0.15.2] - 2024-11-06 diff --git a/src/sisl/_core/geometry.py b/src/sisl/_core/geometry.py index 38a0b6675a..c74bcc8d1e 100644 --- a/src/sisl/_core/geometry.py +++ b/src/sisl/_core/geometry.py @@ -366,9 +366,12 @@ def _sanitize_atoms(self, atoms) -> ndarray: - name -> self._names[name] - `Atom` -> self.atoms.index(atom) - range/list/ndarray -> ndarray + - `...` -> ndarray """ if atoms is None: return np.arange(self.na) + elif atoms is Ellipsis: + return np.arange(self.na) atoms = _a.asarray(atoms) if atoms.size == 0: return _a.asarrayl([]) @@ -452,6 +455,8 @@ def _sanitize_orbs(self, orbitals) -> ndarray: """ if orbitals is None: return np.arange(self.no) + elif orbitals is Ellipsis: + return np.arange(self.no) orbitals = _a.asarray(orbitals) if orbitals.size == 0: return _a.asarrayl([]) diff --git a/src/sisl/_core/tests/test_geometry.py b/src/sisl/_core/tests/test_geometry.py index 081cba296a..9354d2b056 100644 --- a/src/sisl/_core/tests/test_geometry.py +++ b/src/sisl/_core/tests/test_geometry.py @@ -1654,6 +1654,11 @@ def test_geometry_sort_int(): assert np.all(np.diff(bi.fxyz[ix, 1] * bi.lattice.length[i]) <= atol) +def test_geometry_ellipsis(): + gr = sisl_geom.graphene() + assert np.allclose(gr.axyz(...), gr.axyz(None)) + + def test_geometry_sort_atom(): bi = sisl_geom.bilayer().tile(2, 0).repeat(2, 1) diff --git a/src/sisl/typing/_indices.py b/src/sisl/typing/_indices.py index cfe914ce37..bdab3e58cb 100644 --- a/src/sisl/typing/_indices.py +++ b/src/sisl/typing/_indices.py @@ -78,6 +78,7 @@ "GenericCategory", "Shape", bool, # for all or none + Ellipsis, # for all atoms None, # typically used to default for all ] """Indexing atoms via various construct methods""" @@ -91,6 +92,7 @@ "AtomCategory", # gets expended to orbitals on the atoms "Shape", bool, + Ellipsis, # for all orbitals None, ] """Indexing orbitals via various construct methods""" From e20395a1ce664490e69d06e86c9c3f448ddd9274 Mon Sep 17 00:00:00 2001 From: Nick Papior Date: Thu, 5 Dec 2024 15:40:25 +0100 Subject: [PATCH 5/5] ensured ellipsis can be typed Signed-off-by: Nick Papior --- src/sisl/typing/_indices.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sisl/typing/_indices.py b/src/sisl/typing/_indices.py index bdab3e58cb..e32954347f 100644 --- a/src/sisl/typing/_indices.py +++ b/src/sisl/typing/_indices.py @@ -78,7 +78,6 @@ "GenericCategory", "Shape", bool, # for all or none - Ellipsis, # for all atoms None, # typically used to default for all ] """Indexing atoms via various construct methods""" @@ -92,7 +91,14 @@ "AtomCategory", # gets expended to orbitals on the atoms "Shape", bool, - Ellipsis, # for all orbitals None, ] """Indexing orbitals via various construct methods""" + +try: + from types import EllipsisType + + AtomsIndex = Union[AtomsIndex, EllipsisType] + OrbitalsIndex = Union[OrbitalsIndex, EllipsisType] +except ImportError: + pass