Skip to content

Nexus: Add Z-valence parsers for UPF, XML, and POTCAR files#6035

Merged
prckent merged 5 commits into
QMCPACK:developfrom
brockdyer03:pp-zval-parsers
Jul 9, 2026
Merged

Nexus: Add Z-valence parsers for UPF, XML, and POTCAR files#6035
prckent merged 5 commits into
QMCPACK:developfrom
brockdyer03:pp-zval-parsers

Conversation

@brockdyer03

Copy link
Copy Markdown
Contributor

Proposed changes

This PR adds Z-valence parsers for UPF v1, UPF v2, XML, and POTCAR files.

These are currently unused, but will be useful in the future when I eventually get around to refactoring pseudopotential.py. The idea is to be able to parse most of the pseudopotential formats that a user will have so that they don't need to specify the Z-valences manually. This will mean less chance of user error and generally cleaner scripts in the future.

I anticipate allowing users to continue to manually specify Z-valences for creating a PhysicalSystem, but also adding in a feature where they can provide Z-valences to ppset, then providing the ppset label to PhysicalSystem, which will either parse the files or use the provided Z-valences to pseudize the system.

Ideally this will mean that eventually user's wont need to specify a Z-valence manually anymore, which I personally have found to be a cumbersome task.

Note about POTCAR parser and test

In hopes of not incurring the wrath of a lawyer, I have made sure to only use publicly available information about the format of a POTCAR file. The parser and test for read_potcar_z_valence() are constructed solely from information found on the VASP Wiki. I modified the mock POTCAR headers slightly to have a Z-valence matching that of the UPF and XML tests, but otherwise it is verbatim from the VASP Wiki.

What type(s) of changes does this code introduce?

  • New feature
  • Testing changes (e.g. new unit/integration/performance tests)

Does this introduce a breaking change?

  • No

What systems has this change been tested on?

Desktop, Fedora Linux 43 (KDE Plasma Desktop Edition)
AMD Ryzen 9 7900X (12 cores, 24 logical processors)

Python        3.14.5
uv            0.11.26
cif2cell      2.1.0
coverage      7.15.0
h5py          3.16.0
matplotlib    3.11.0
numpy         2.5.1
pycifrw       4.4.6
pydot         4.0.1
pytest        9.1.1
pytest-cov    7.1.0
pytest-order  1.5.0
scipy         1.18.0
seekpath      2.2.1
spglib        2.7.0
sphinx        9.1.0

Checklist

    • I have read the pull request guidance and develop docs
    • This PR is up to date with the current state of 'develop'
    • This PR adds tests to cover any new code, or to catch a bug that is being fixed
    • Documentation has been added (if appropriate)

@brockdyer03 brockdyer03 requested review from jtkrogel and prckent July 9, 2026 01:20
@brockdyer03 brockdyer03 self-assigned this Jul 9, 2026
@brockdyer03 brockdyer03 added enhancement nexus python Pull requests that update python code labels Jul 9, 2026

@jtkrogel jtkrogel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments

Comment thread nexus/nexus/pseudopotential.py
Comment thread nexus/nexus/pseudopotential.py Outdated
Comment thread nexus/nexus/pseudopotential.py
Comment thread nexus/nexus/pseudopotential.py
Comment thread nexus/nexus/pseudopotential.py
Comment thread nexus/nexus/pseudopotential.py Outdated
f"Could not find Z valence in file: {file!s}\n"
"You may need to provide the Z valence manually!"
)
elif zval.is_integer():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice call. What is it's tolerance? If too strict, we won't be able to use it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unusual behavior; even the floating point numbers closest to zero are apparently non-integer:

>>> 4.940656458412465e-324.is_integer()
False
>>> -4.940656458412465e-324.is_integer()
0

This is far too strict.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never seen any pseudopotentials with that small of a Z-valence...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is that parsing floating point numbers is not guaranteed to satisfy is_integer. Those numbers are as close to zero as possible (w/o being zero). The tolerance should be something like 1e-9, >300 orders of magnitude larger.

Comment thread nexus/nexus/pseudopotential.py
Comment thread nexus/nexus/pseudopotential.py
Comment thread nexus/nexus/pseudopotential.py Outdated

def read_xml_z_valence(file: PathLike) -> int | float:
"""Read the Z-valence from a QMCPACK-compatible XML pseudopotential file."""
header_pattern = re.compile(r'zval=\"([\d\.]+)\"')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex is insufficient. XML can have whitespace between zval and =.

@jtkrogel jtkrogel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

@jtkrogel jtkrogel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

Comment thread nexus/nexus/pseudopotential.py Outdated
while not found_header_start:
line = pseudo.readline()
if "<PP_HEADER" in line:
header_data.append(line)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think logic is missing here. header_data is collected, but not used. The parse below based on the end of PP_HEADER assumes the zval data resides on that line.

I don't understand how this code passes the upf parsing test, unless it always trips the fallback code.

@brockdyer03 brockdyer03 requested a review from jtkrogel July 9, 2026 14:20
Comment thread nexus/nexus/pseudopotential.py Outdated
break
elif "/>" in line or "</PP_HEADER>" in line:
break
#end if

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

misplaced end if

@jtkrogel jtkrogel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good now

@prckent prckent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the care in not including a complete POTCAR .

@prckent

prckent commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Test this please

@prckent prckent enabled auto-merge July 9, 2026 15:27
@prckent prckent merged commit 5028956 into QMCPACK:develop Jul 9, 2026
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement nexus python Pull requests that update python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants