diff --git a/CHANGELOG.md b/CHANGELOG.md index e0850e2a9..b2272f0cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ we hit release version 1.0.0. ## [0.15.3] - YYYY-MM-DD +### Added +- 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/siesta/stdout.py b/src/sisl/io/siesta/stdout.py index 4841abf3e..c0b2d535e 100644 --- a/src/sisl/io/siesta/stdout.py +++ b/src/sisl/io/siesta/stdout.py @@ -828,7 +828,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, ): @@ -840,7 +840,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 @@ -854,7 +854,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!" @@ -1084,8 +1086,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, ): @@ -1127,15 +1129,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. @@ -1568,9 +1570,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"), ) @@ -1605,6 +1607,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 a6e3e8d47..3d4d096d5 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]()