Skip to content

Commit

Permalink
Bugfix: io.pwscf.PWInput.from_str() (#3931)
Browse files Browse the repository at this point in the history
* Bugfix: `io.pwscf.PWInput.from_str()`

Fixes wrong parsing of:
- Namelist options ending with comma (`,`)
- `ATOMIC_SPECIES` and `ATOMIC_POSITIONS` cards for structures with oxidation states

* Additional fix in regexp

- Must only have one of either + or - in oxidation states, not one of both

---------

Co-authored-by: Janosh Riebesell <janosh.riebesell@gmail.com>
  • Loading branch information
jsukpark and janosh authored Aug 6, 2024
1 parent 4ffec03 commit 99f62d2
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/pymatgen/io/pwscf.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ def input_mode(line):
if match := re.match(r"(\w+)\(?(\d*?)\)?\s*=\s*(.*)", line):
key = match[1].strip()
key_ = match[2].strip()
val = match[3].strip()
val = match[3].strip().rstrip(",")
if key_ != "":
if sections[section].get(key) is None:
val_ = [0.0] * 20 # MAX NTYP DEFINITION
Expand All @@ -306,7 +306,7 @@ def input_mode(line):
sections[section][key] = PWInput.proc_val(key, val)

elif mode[0] == "pseudo":
if match := re.match(r"(\w+)\s+(\d*.\d*)\s+(.*)", line):
if match := re.match(r"(\w+\d*[\+-]?)\s+(\d*.\d*)\s+(.*)", line):
pseudo[match[1].strip()] = match[3].strip()

elif mode[0] == "kpoints":
Expand All @@ -318,7 +318,7 @@ def input_mode(line):

elif mode[0] == "structure":
m_l = re.match(r"(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)", line)
m_p = re.match(r"(\w+)\s+(-?\d+\.\d*)\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)", line)
m_p = re.match(r"(\w+\d*[\+-]?)\s+(-?\d+\.\d*)\s+(-?\d+\.?\d*)\s+(-?\d+\.?\d*)", line)
if m_l:
lattice += [
float(m_l[1]),
Expand Down
26 changes: 26 additions & 0 deletions tests/io/test_pwscf.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,32 @@ def test_read_str(self):
assert_allclose(lattice, pw_in.structure.lattice.matrix)
assert pw_in.sections["system"]["smearing"] == "cold"

def test_write_and_read_str(self):
struct = self.get_structure("Graphite")
struct.remove_oxidation_states()
pw = PWInput(
struct,
pseudo={"C": "C.pbe-n-kjpaw_psl.1.0.0.UPF"},
control={"calculation": "scf", "pseudo_dir": "./"},
system={"ecutwfc": 45},
)
pw_str = str(pw)
assert pw_str.strip() == str(PWInput.from_str(pw_str)).strip()

def test_write_and_read_str_with_oxidation(self):
struct = self.get_structure("Li2O")
pw = PWInput(
struct,
control={"calculation": "scf", "pseudo_dir": "./"},
pseudo={
"Li+": "Li.pbe-n-kjpaw_psl.0.1.UPF",
"O2-": "O.pbe-n-kjpaw_psl.0.1.UPF",
},
system={"ecutwfc": 50},
)
pw_str = str(pw)
assert pw_str.strip() == str(PWInput.from_str(pw_str)).strip()


class TestPWOutput(PymatgenTest):
def setUp(self):
Expand Down

0 comments on commit 99f62d2

Please sign in to comment.