Skip to content

Commit fb70654

Browse files
committed
DosOutput: add first version
Add the first version of the `DosOutput` class, a parser for `dos.x` outputs, via a new file parser for the `.dos` output file, supporting the various spin cases. As a demonstrator, the `DosOutput` class also tries to find the XML file, and extracts the spin type from it. A typical Quantum ESPRESSO user will run `pw.x` then `dos.x` in the same directory, so both files _should_ be present. This ability for the various output classes to use the file parsers of other codes and extract only the information they need with `glom` queries is very flexible, and demonstrates one of the reasons behind the design. Using `glom` queries, we can also offer the user the outputs in two ways: having the energy, DOS, integrated DOS etc at the top-level, immediately accessible via tab-completion in the `outputs` namespace, or gathered in the `full_dos` output. This doesn't actually duplicate any data: the "raw" outputs are simply queried differently for the desired "base" outputs. The original motivation for adding the `full_dos` is to then allow conversion into the types of our supported libraries, e.g. an `ArrayData` for AiiDA. Note that we _do_ use numpy here, despite a desire to avoid dependency on this package. Frankly, the code without using number becomes more complicated and less readable. We have to see if it is worth avoiding numpy, since it is also ubiquitous in our ecosystem.
1 parent 0df5e81 commit fb70654

File tree

15 files changed

+3202
-2
lines changed

15 files changed

+3202
-2
lines changed

docs/getting_started.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,24 @@ pw_out.get_output('fermi_energy')
8181
!!! warning "Important"
8282

8383
For the `pw.x` calculation, we retrieve most of the final outputs from the XML file.
84-
Parsing _only_ from the `stdout` file will lead to limited results.
84+
85+
86+
### Parsing other outputs
87+
88+
We don't only provide output parsing for `pw.x`!
89+
Below you can find and example where we plot the DOS output of a `dos.x` calculation:
90+
91+
```python
92+
from qe_tools.outputs import DosOutput
93+
94+
dos_out = DosOutput.from_dir('dos_dir')
95+
```
96+
97+
```python
98+
import matplotlib.pyplot as plt
99+
100+
plt.plot(dos_out.outputs.energy, dos_out.outputs.dos)
101+
```
85102

86103

87104
## Parsing an already existing input file

src/qe_tools/outputs/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
from .pw import PwOutput
2+
from .dos import DosOutput
23

3-
__all__ = ("PwOutput",)
4+
__all__ = (
5+
"PwOutput",
6+
"DosOutput",
7+
)

src/qe_tools/outputs/dos.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""Output of the Quantum ESPRESSO pw.x code."""
2+
3+
from __future__ import annotations
4+
5+
from pathlib import Path
6+
from typing import TextIO
7+
8+
from qe_tools.outputs.base import BaseOutput
9+
10+
from .parsers.base import BaseStdoutParser
11+
from .parsers.dos import DosParser
12+
from .parsers.pw import PwXMLParser
13+
14+
15+
def _determine_spin_type(spin: dict) -> str:
16+
if spin["noncolin"]:
17+
return "non-collinear"
18+
if spin["spinorbit"]:
19+
return "spin-orbit"
20+
if spin["lsda"]:
21+
return "spin-polarised"
22+
return "non-spin-polarised"
23+
24+
25+
class DosOutput(BaseOutput):
26+
"""Output of the Quantum ESPRESSO pw.x code."""
27+
28+
_output_spec_mapping = {
29+
"energy": "dos.energy",
30+
"dos": "dos.dos",
31+
"dos_up": "dos.dos_up",
32+
"dos_down": "dos.dos_down",
33+
"fermi_energy": "dos.fermi_energy",
34+
"integrated_dos": "dos.integrated_dos",
35+
"full_dos": "dos",
36+
"spin_type": ("xml.input.spin", _determine_spin_type),
37+
}
38+
39+
@classmethod
40+
def from_dir(cls, directory: str | Path):
41+
"""
42+
From a directory, locates the standard output and XML files and
43+
parses them.
44+
"""
45+
directory = Path(directory)
46+
47+
if not directory.is_dir():
48+
raise ValueError(f"Path `{directory}` is not a valid directory.")
49+
50+
stdout_file = None
51+
dos_file = next(directory.glob("*.dos"), None)
52+
xml_file = next(directory.rglob("data-file*.xml"), None)
53+
54+
for file in [path for path in directory.iterdir() if path.is_file()]:
55+
with file.open("r") as handle:
56+
header = "".join(handle.readlines(5))
57+
58+
if "Program DOS" in header:
59+
stdout_file = file
60+
61+
return cls.from_files(dos=dos_file, xml=xml_file, stdout=stdout_file)
62+
63+
@classmethod
64+
def from_files(
65+
cls,
66+
*,
67+
dos: None | str | Path | TextIO = None,
68+
xml: None | str | Path | TextIO = None,
69+
stdout: None | str | Path | TextIO = None,
70+
):
71+
"""Parse the outputs directly from the provided files."""
72+
raw_outputs = {}
73+
74+
if stdout is not None:
75+
raw_outputs["stdout"] = BaseStdoutParser.parse_from_file(stdout)
76+
77+
if dos is not None:
78+
raw_outputs["dos"] = DosParser.parse_from_file(dos)
79+
80+
if xml is not None:
81+
raw_outputs["xml"] = PwXMLParser.parse_from_file(xml)
82+
83+
return cls(raw_outputs=raw_outputs)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from __future__ import annotations
2+
3+
from qe_tools.outputs.parsers.base import BaseOutputFileParser
4+
import numpy as np
5+
from io import StringIO
6+
import re
7+
8+
9+
class DosParser(BaseOutputFileParser):
10+
"""
11+
Class for parsing the XML output of pw.x.
12+
"""
13+
14+
@staticmethod
15+
def parse(content: str) -> dict:
16+
"""Parse an output `.dos` file of Quantum ESPRESSO dos.x."""
17+
18+
header, _, body = content.partition("\n")
19+
20+
fermi_energy = float(
21+
re.search(r"EFermi\s=\s+([\d\.]+)\seV", header).groups()[0]
22+
)
23+
24+
body_array = np.loadtxt(StringIO(body))
25+
26+
parsed_data = {
27+
"fermi_energy": fermi_energy,
28+
"energy": body_array[:, 0],
29+
"integrated_dos": body_array[:, -1],
30+
}
31+
# Spin-polarised case
32+
if "dosup" in header:
33+
parsed_data["dos_up"] = body_array[:, 1].tolist()
34+
parsed_data["dos_down"] = body_array[:, 2].tolist()
35+
# Non-spin-polarised/non-collinear case
36+
else:
37+
parsed_data["dos"] = body_array[:, 1].tolist()
38+
39+
return parsed_data
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
Program DOS v.7.2 starts on 10Oct2025 at 8:45: 3
3+
4+
This program is part of the open-source Quantum ESPRESSO suite
5+
for quantum simulation of materials; please cite
6+
"P. Giannozzi et al., J. Phys.:Condens. Matter 21 395502 (2009);
7+
"P. Giannozzi et al., J. Phys.:Condens. Matter 29 465901 (2017);
8+
"P. Giannozzi et al., J. Chem. Phys. 152 154105 (2020);
9+
URL http://www.quantum-espresso.org",
10+
in publications or presentations arising from this work. More details at
11+
http://www.quantum-espresso.org/quote
12+
13+
Parallel version (MPI & OpenMP), running on 11 processor cores
14+
Number of MPI processes: 1
15+
Threads/MPI process: 11
16+
17+
MPI processes distributed on 1 nodes
18+
0 MiB available memory on the printing compute node when the environment starts
19+
20+
21+
Reading xml data from directory:
22+
23+
./out/aiida.save/
24+
25+
IMPORTANT: XC functional enforced from input :
26+
Exchange-correlation= PBESOL
27+
( 1 4 10 8 0 0 0)
28+
Any further DFT definition will be discarded
29+
Please, verify this is what you really want
30+
31+
32+
G-vector sticks info
33+
--------------------
34+
sticks: dense smooth PW G-vecs: dense smooth PW
35+
Sum 1649 829 241 50733 17941 2721
36+
37+
Using Slab Decomposition
38+
39+
40+
Optimized tetrahedron method used
41+
42+
[opt_tetra] Optimized tetrahedron method is used.
43+
44+
DOS : 3.70s CPU 1.19s WALL
45+
46+
47+
This run was terminated on: 8:45: 4 10Oct2025
48+
49+
=------------------------------------------------------------------------------=
50+
JOB DONE.
51+
=------------------------------------------------------------------------------=
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# E (eV) dosup(E) dosdw(E) Int dos(E) EFermi = 1.845 eV
2+
-39.451 0.2402E+02 0.2402E+02 0.5678E-01
3+
-38.451 0.0000E+00 0.0000E+00 0.8000E+01
4+
-37.451 0.0000E+00 0.0000E+00 0.8000E+01
5+
-36.451 0.0000E+00 0.0000E+00 0.8000E+01
6+
-35.451 0.0000E+00 0.0000E+00 0.8000E+01
7+
-34.451 0.0000E+00 0.0000E+00 0.8000E+01
8+
-33.451 0.0000E+00 0.0000E+00 0.8000E+01
9+
-32.451 0.0000E+00 0.0000E+00 0.8000E+01
10+
-31.451 0.0000E+00 0.0000E+00 0.8000E+01
11+
-30.451 0.0000E+00 0.0000E+00 0.8000E+01
12+
-29.451 0.0000E+00 0.0000E+00 0.8000E+01
13+
-28.451 0.0000E+00 0.0000E+00 0.8000E+01
14+
-27.451 0.0000E+00 0.0000E+00 0.8000E+01
15+
-26.451 0.0000E+00 0.0000E+00 0.8000E+01
16+
-25.451 0.0000E+00 0.0000E+00 0.8000E+01
17+
-24.451 0.0000E+00 0.0000E+00 0.8000E+01
18+
-23.451 0.0000E+00 0.0000E+00 0.8000E+01
19+
-22.451 0.0000E+00 0.0000E+00 0.8000E+01
20+
-21.451 0.0000E+00 0.0000E+00 0.8000E+01
21+
-20.451 0.0000E+00 0.0000E+00 0.8000E+01
22+
-19.451 0.0000E+00 0.0000E+00 0.8000E+01
23+
-18.451 0.2383E+01 0.2383E+01 0.1163E+02
24+
-17.451 0.0000E+00 0.0000E+00 0.1600E+02
25+
-16.451 0.0000E+00 0.0000E+00 0.1600E+02
26+
-15.451 0.0000E+00 0.0000E+00 0.1600E+02
27+
-14.451 0.0000E+00 0.0000E+00 0.1600E+02
28+
-13.451 0.0000E+00 0.0000E+00 0.1600E+02
29+
-12.451 0.0000E+00 0.0000E+00 0.1600E+02
30+
-11.451 0.0000E+00 0.0000E+00 0.1600E+02
31+
-10.451 0.0000E+00 0.0000E+00 0.1600E+02
32+
-9.451 0.0000E+00 0.0000E+00 0.1600E+02
33+
-8.451 0.0000E+00 0.0000E+00 0.1600E+02
34+
-7.451 0.0000E+00 0.0000E+00 0.1600E+02
35+
-6.451 0.0000E+00 0.0000E+00 0.1600E+02
36+
-5.451 0.0000E+00 0.0000E+00 0.1600E+02
37+
-4.451 0.0000E+00 0.0000E+00 0.1600E+02
38+
-3.451 0.0000E+00 0.0000E+00 0.1600E+02
39+
-2.451 0.0000E+00 0.0000E+00 0.1600E+02
40+
-1.451 0.3044E+01 0.3044E+01 0.2119E+02
41+
-0.451 0.5013E+01 0.5013E+01 0.2574E+02
42+
0.549 0.5392E+01 0.5392E+01 0.3746E+02
43+
1.549 0.0000E+00 0.0000E+00 0.4000E+02
44+
2.549 0.0000E+00 0.0000E+00 0.4000E+02
45+
3.549 0.0000E+00 0.0000E+00 0.4000E+02
46+
4.549 0.0000E+00 0.0000E+00 0.4000E+02
47+
5.549 0.0000E+00 0.0000E+00 0.4000E+02
48+
6.549 0.0000E+00 0.0000E+00 0.4000E+02
49+
7.549 0.0000E+00 0.0000E+00 0.4000E+02
50+
8.549 0.0000E+00 0.0000E+00 0.4000E+02
51+
9.549 0.4021E-02 0.4021E-02 0.4000E+02
52+
10.549 0.3961E+00 0.3961E+00 0.4079E+02
53+
11.549 0.4039E+00 0.4039E+00 0.4158E+02
54+
12.549 0.2797E+00 0.2797E+00 0.4237E+02
55+
13.549 0.2726E+00 0.2726E+00 0.4292E+02
56+
14.549 0.2766E+00 0.2766E+00 0.4347E+02
57+
15.549 0.8322E+01 0.8321E+01 0.4685E+02
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
Program DOS v.7.2 starts on 9Oct2025 at 18:53:21
3+
4+
This program is part of the open-source Quantum ESPRESSO suite
5+
for quantum simulation of materials; please cite
6+
"P. Giannozzi et al., J. Phys.:Condens. Matter 21 395502 (2009);
7+
"P. Giannozzi et al., J. Phys.:Condens. Matter 29 465901 (2017);
8+
"P. Giannozzi et al., J. Chem. Phys. 152 154105 (2020);
9+
URL http://www.quantum-espresso.org",
10+
in publications or presentations arising from this work. More details at
11+
http://www.quantum-espresso.org/quote
12+
13+
Parallel version (MPI & OpenMP), running on 11 processor cores
14+
Number of MPI processes: 1
15+
Threads/MPI process: 11
16+
17+
MPI processes distributed on 1 nodes
18+
0 MiB available memory on the printing compute node when the environment starts
19+
20+
21+
Reading xml data from directory:
22+
23+
./out/aiida.save/
24+
25+
IMPORTANT: XC functional enforced from input :
26+
Exchange-correlation= PBESOL
27+
( 1 4 10 8 0 0 0)
28+
Any further DFT definition will be discarded
29+
Please, verify this is what you really want
30+
31+
32+
G-vector sticks info
33+
--------------------
34+
sticks: dense smooth PW G-vecs: dense smooth PW
35+
Sum 1649 829 241 50733 17941 2721
36+
37+
Using Slab Decomposition
38+
39+
40+
Optimized tetrahedron method used
41+
42+
[opt_tetra] Optimized tetrahedron method is used.
43+
44+
DOS : 3.76s CPU 1.16s WALL
45+
46+
47+
This run was terminated on: 18:53:23 9Oct2025
48+
49+
=------------------------------------------------------------------------------=
50+
JOB DONE.
51+
=------------------------------------------------------------------------------=
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# E (eV) dos(E) Int dos(E) EFermi = 1.845 eV
2+
-39.451 0.4804E+02 0.5694E-01
3+
-38.451 0.0000E+00 0.8000E+01
4+
-37.451 0.0000E+00 0.8000E+01
5+
-36.451 0.0000E+00 0.8000E+01
6+
-35.451 0.0000E+00 0.8000E+01
7+
-34.451 0.0000E+00 0.8000E+01
8+
-33.451 0.0000E+00 0.8000E+01
9+
-32.451 0.0000E+00 0.8000E+01
10+
-31.451 0.0000E+00 0.8000E+01
11+
-30.451 0.0000E+00 0.8000E+01
12+
-29.451 0.0000E+00 0.8000E+01
13+
-28.451 0.0000E+00 0.8000E+01
14+
-27.451 0.0000E+00 0.8000E+01
15+
-26.451 0.0000E+00 0.8000E+01
16+
-25.451 0.0000E+00 0.8000E+01
17+
-24.451 0.0000E+00 0.8000E+01
18+
-23.451 0.0000E+00 0.8000E+01
19+
-22.451 0.0000E+00 0.8000E+01
20+
-21.451 0.0000E+00 0.8000E+01
21+
-20.451 0.0000E+00 0.8000E+01
22+
-19.451 0.0000E+00 0.8000E+01
23+
-18.451 0.4765E+01 0.1163E+02
24+
-17.451 0.0000E+00 0.1600E+02
25+
-16.451 0.0000E+00 0.1600E+02
26+
-15.451 0.0000E+00 0.1600E+02
27+
-14.451 0.0000E+00 0.1600E+02
28+
-13.451 0.0000E+00 0.1600E+02
29+
-12.451 0.0000E+00 0.1600E+02
30+
-11.451 0.0000E+00 0.1600E+02
31+
-10.451 0.0000E+00 0.1600E+02
32+
-9.451 0.0000E+00 0.1600E+02
33+
-8.451 0.0000E+00 0.1600E+02
34+
-7.451 0.0000E+00 0.1600E+02
35+
-6.451 0.0000E+00 0.1600E+02
36+
-5.451 0.0000E+00 0.1600E+02
37+
-4.451 0.0000E+00 0.1600E+02
38+
-3.451 0.0000E+00 0.1600E+02
39+
-2.451 0.0000E+00 0.1600E+02
40+
-1.451 0.6087E+01 0.2119E+02
41+
-0.451 0.1003E+02 0.2574E+02
42+
0.549 0.1078E+02 0.3746E+02
43+
1.549 0.0000E+00 0.4000E+02
44+
2.549 0.0000E+00 0.4000E+02
45+
3.549 0.0000E+00 0.4000E+02
46+
4.549 0.0000E+00 0.4000E+02
47+
5.549 0.0000E+00 0.4000E+02
48+
6.549 0.0000E+00 0.4000E+02
49+
7.549 0.0000E+00 0.4000E+02
50+
8.549 0.0000E+00 0.4000E+02
51+
9.549 0.8044E-02 0.4000E+02
52+
10.549 0.7922E+00 0.4079E+02
53+
11.549 0.8078E+00 0.4158E+02
54+
12.549 0.5594E+00 0.4237E+02
55+
13.549 0.5452E+00 0.4292E+02
56+
14.549 0.5532E+00 0.4347E+02
57+
15.549 0.1664E+02 0.4685E+02

0 commit comments

Comments
 (0)