From 67e65fd08482f4cf420b648aab06efce1da9a001 Mon Sep 17 00:00:00 2001 From: Han Yang Date: Wed, 18 Sep 2024 09:12:28 +0800 Subject: [PATCH] Fix: fixed electronic step check with algo = exact and nelm = 1 (#4071) * fixed electronic step check with algo = exact and nelm = 1 * pre-commit auto-fixes * fixed the cases in which ALGO does not appear in incar * pre-commit auto-fixes --------- Co-authored-by: yanghan-microsoft Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/pymatgen/io/vasp/outputs.py | 42 +++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/pymatgen/io/vasp/outputs.py b/src/pymatgen/io/vasp/outputs.py index c4cef04d8e9..f954554d0f6 100644 --- a/src/pymatgen/io/vasp/outputs.py +++ b/src/pymatgen/io/vasp/outputs.py @@ -624,6 +624,8 @@ def converged_electronic(self) -> bool: while set(final_elec_steps[idx]) == to_check: idx += 1 return idx + 1 != self.parameters["NELM"] + if self.incar.get("ALGO", "").upper() == "EXACT" and self.incar.get("NELM") == 1: + return True return len(final_elec_steps) < self.parameters["NELM"] @property @@ -1699,8 +1701,10 @@ def __init__( self.separate_spins = separate_spins with zopen(filename, mode="rt") as file: - self.efermi = self.eigenvalues = self.projected_eigenvalues = None - parsed_header = in_kpoints_opt = False + self.efermi = None + parsed_header = False + in_kpoints_opt = False + self.eigenvalues = self.projected_eigenvalues = None self.kpoints_opt_props = None for event, elem in ET.iterparse(file, events=["start", "end"]): tag = elem.tag @@ -1980,7 +1984,10 @@ def __init__(self, filename: PathLike) -> None: # For single atom systems, VASP doesn't print a total line, so # reverse parsing is very difficult - read_charge = read_mag_x = read_mag_y = read_mag_z = False # for SOC calculations only + read_charge = False + read_mag_x = False + read_mag_y = False # for SOC calculations only + read_mag_z = False all_lines.reverse() for clean in all_lines: if read_charge or read_mag_x or read_mag_y or read_mag_z: @@ -1999,7 +2006,10 @@ def __init__(self, filename: PathLike) -> None: elif read_mag_z: mag_z.append(dict(zip(header, tokens, strict=True))) elif clean.startswith("tot"): - read_charge = read_mag_x = read_mag_y = read_mag_z = False + read_charge = False + read_mag_x = False + read_mag_y = False + read_mag_z = False if clean == "total charge": charge = [] read_charge = True @@ -2486,8 +2496,10 @@ def read_cs_core_contribution(self) -> None: self.data["cs_core_contribution"] = core_contrib def read_cs_raw_symmetrized_tensors(self) -> None: - """Parse the matrix form of NMR tensor before corrected to table - and set as self.data["unsym_cs_tensor"]. + """Parse the matrix form of NMR tensor before corrected to table. + + Returns: + nsymmetrized tensors list in the order of atoms. """ header_pattern = r"\s+-{50,}\s+\s+Absolute Chemical Shift tensors\s+\s+-{50,}$" first_part_pattern = r"\s+UNSYMMETRIZED TENSORS\s+$" @@ -3475,7 +3487,8 @@ def parse_file(filename: PathLike) -> tuple[Poscar, dict, dict]: dim: list[int] = [] dimline = "" read_dataset = False - ngrid_pts = data_count = 0 + ngrid_pts = 0 + data_count = 0 poscar = None with zopen(filename, mode="rt") as file: for line in file: @@ -3941,13 +3954,16 @@ def _read(self, filename: PathLike, parsed_kpoints: set[tuple[Kpoint]] | None = ion_expr = re.compile(r"^ion.*") total_expr = re.compile(r"^tot.*") expr = re.compile(r"^([0-9]+)\s+") - current_kpoint = current_band = 0 + current_kpoint = 0 + current_band = 0 spin = Spin.down # switched to Spin.up for first block n_kpoints = None kpoints: list[tuple[float, float, float]] = [] - n_bands = n_ions = headers = None + n_bands = None + n_ions = None weights: np.ndarray[float] | None = None + headers = None data: dict[Spin, np.ndarray] = {} eigenvalues: dict[Spin, np.ndarray] | None = None occupancies: dict[Spin, np.ndarray] | None = None @@ -3960,7 +3976,8 @@ def _read(self, filename: PathLike, parsed_kpoints: set[tuple[Kpoint]] | None = # first dynamically determine whether PROCAR is SOC or not; SOC PROCARs have 4 lists of projections ( # total and x,y,z) for each band, while non-SOC have only 1 list of projections: - tot_count = band_count = 0 + tot_count = 0 + band_count = 0 for line in file_handle: if total_expr.match(line): tot_count += 1 @@ -4516,7 +4533,8 @@ def get_str( lines.extend((" ".join(self.site_symbols), " ".join(map(str, self.natoms)))) format_str = f"{{:.{significant_figures}f}}" - ionicstep_cnt = output_cnt = 1 + ionicstep_cnt = 1 + output_cnt = 1 for cnt, structure in enumerate(self.structures, start=1): ionicstep_cnt = cnt if ( @@ -5137,7 +5155,7 @@ def get_parchg( # Scaling of ng for the fft grid, need to restore value at the end temp_ng = self.ng - self.ng = self.ng * scale # (ruff-preview) noqa: PLR6104 + self.ng = self.ng * scale N = np.prod(self.ng) data = {}