Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions castep_outputs/parsers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
parse_elf_fmt_file,
parse_pot_fmt_file,
)
from .pes_file_parser import parse_pes_file
from .phonon_dos_file_parser import parse_phonon_dos_file
from .phonon_file_parser import parse_phonon_file
from .tddft_file_parser import parse_tddft_file
Expand All @@ -46,6 +47,9 @@
"parse_md_geom_file",
"parse_md_geom_file",
"parse_param_file",
"parse_param_file",
"parse_pes_file",
"parse_pes_file",
"parse_phonon_dos_file",
"parse_phonon_file",
"parse_pot_fmt_file",
Expand Down Expand Up @@ -78,6 +82,7 @@
"err": parse_err_file,
"phonon": parse_phonon_file,
"epme": parse_epme_file,
"pes": parse_pes_file,
}

#: Names of parsers/parsable file extensions (without ``"."``).
Expand Down
94 changes: 94 additions & 0 deletions castep_outputs/parsers/pes_file_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""Parse castep .pes files."""

from __future__ import annotations

from typing import TextIO, TypedDict

from ..utilities.datatypes import ThreeByThreeMatrix, ThreeVector
from ..utilities.filewrapper import Block
from ..utilities.utility import file_or_path, to_type


class PESData(TypedDict):
"""PES sample points."""

pos: ThreeVector
e: float
f_opt: float | None


class PESFileInfo(TypedDict, total=False):
"""Full pes file information."""

probe_species: str
probe_method: str
cell: ThreeByThreeMatrix
date_started: str
data: list[PESData]
units: dict[str, str]
samples: dict[str, int]


def _parse_header(header: Block) -> PESFileInfo:
accum: PESFileInfo = {"units": {}, "samples": {}, "data": []}

header = map(str.strip, header)

for line in header:
if line.startswith("Job:"):
_, accum["probe_method"] = line.split(": ")
elif line.startswith("Probe species:"):
_, accum["probe_species"] = line.split(": ")
elif "unit:" in line:
typ_, _, unit = line.split()
accum["units"][typ_.lower()] = unit
elif line.startswith("Number of samples"):
*_, direc, count = line.split()
accum["samples"][direc.strip(":")] = int(count)
elif line.startswith("Cell Vectors"):
*_, unit = line.split()
accum["units"]["cell"] = unit.strip("()")
accum["cell"] = tuple(to_type(cell.split(), float)
for cell, _ in zip(header, range(3)))
elif line.startswith("Date"):
_, accum["date_started"] = line.split(": ", maxsplit=1)

return accum


@file_or_path(mode="r")
def parse_pes_file(pes_file: TextIO) -> PESFileInfo:
"""Parse castep .pes file.

Parameters
----------
pes_file
A handle to a CASTEP .pes file.

Returns
-------
PESFileInfo
Parsed data.
"""
line = next(pes_file)
block = Block.from_re(line, pes_file, "BEGIN header", "END header")

accum = _parse_header(block)

line = next(pes_file)
block = Block.from_re(line, pes_file, " BLOCK DATA", "ENDBLOCK DATA")
block.remove_bounds(1, 1)

data = accum["data"]

for line in block:
a, b, c, e, *extra = to_type(line.split(), float)

curr = {}
curr["pos"] = a, b, c
curr["e"] = e
curr["f_opt"] = extra[0] if extra else None

data.append(curr)

return accum
6 changes: 5 additions & 1 deletion test/data_files/gen_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"efield",
"tddft",
"err",
"pes",
"epme",
("pp-md", "castep"),
("si8-md", "castep"),
Expand Down Expand Up @@ -63,7 +64,10 @@ def gen_data(

argp.add_argument("datasets", nargs=REMAINDER, help="Sets to generate.", default=ALL_SETS)
argp.add_argument(
"--formats", nargs="+", help="Formats to generate.", default=("json", "pyyaml", "ruamel"),
"--formats",
nargs="+",
help="Formats to generate.",
default=("json", "pyyaml", "ruamel"),
)
args = argp.parse_args()

Expand Down
141 changes: 141 additions & 0 deletions test/data_files/pes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
"units": {
"energy": "eV",
"force": "eV/A",
"cell": "Bohr"
},
"samples": {
"a": 10,
"b": 10
},
"data": [
{
"pos": [
0.5,
0.5,
0.50017
],
"e": -231.164733,
"f_opt": 0.148
},
{
"pos": [
0.61111,
0.5,
0.50029
],
"e": -231.345479,
"f_opt": 0.42
},
{
"pos": [
0.72222,
0.5,
0.50042
],
"e": -231.557748,
"f_opt": 0.194
},
{
"pos": [
0.83333,
0.5,
0.50074
],
"e": -231.445747,
"f_opt": -0.582
},
{
"pos": [
0.94444,
0.5,
0.50149
],
"e": -231.041607,
"f_opt": -0.531
},
{
"pos": [
1.05556,
0.5,
0.50233
],
"e": -231.015796,
"f_opt": 0.408
},
{
"pos": [
1.16667,
0.5,
0.50266
],
"e": -231.314431,
"f_opt": 0.401
},
{
"pos": [
1.27778,
0.5,
0.50263
],
"e": -231.347231,
"f_opt": -0.201
},
{
"pos": [
1.38889,
0.5,
0.50254
],
"e": -231.199074,
"f_opt": -0.212
},
{
"pos": [
1.5,
0.5,
0.50258
],
"e": -231.166451,
"f_opt": 0.16
},
{
"pos": [
1.5,
0.61111,
0.5027
],
"e": -231.336101,
"f_opt": 0.413
},
{
"pos": [
1.38889,
0.61111,
0.5027
],
"e": -231.21672,
"f_opt": 0.0254
}
],
"date_started": "Fri Jun 27 13:43:56 +0100 2025",
"probe_method": "min_c",
"probe_species": "H",
"cell": [
[
0.0,
5.077705,
5.077705
],
[
5.077705,
0.0,
5.077705
],
[
5.077705,
5.077705,
0.0
]
]
}
96 changes: 96 additions & 0 deletions test/data_files/pes.pyyaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
cell: !!python/tuple
- !!python/tuple
- 0.0
- 5.077705
- 5.077705
- !!python/tuple
- 5.077705
- 0.0
- 5.077705
- !!python/tuple
- 5.077705
- 5.077705
- 0.0
data:
- e: -231.164733
f_opt: 0.148
pos: !!python/tuple
- 0.5
- 0.5
- 0.50017
- e: -231.345479
f_opt: 0.42
pos: !!python/tuple
- 0.61111
- 0.5
- 0.50029
- e: -231.557748
f_opt: 0.194
pos: !!python/tuple
- 0.72222
- 0.5
- 0.50042
- e: -231.445747
f_opt: -0.582
pos: !!python/tuple
- 0.83333
- 0.5
- 0.50074
- e: -231.041607
f_opt: -0.531
pos: !!python/tuple
- 0.94444
- 0.5
- 0.50149
- e: -231.015796
f_opt: 0.408
pos: !!python/tuple
- 1.05556
- 0.5
- 0.50233
- e: -231.314431
f_opt: 0.401
pos: !!python/tuple
- 1.16667
- 0.5
- 0.50266
- e: -231.347231
f_opt: -0.201
pos: !!python/tuple
- 1.27778
- 0.5
- 0.50263
- e: -231.199074
f_opt: -0.212
pos: !!python/tuple
- 1.38889
- 0.5
- 0.50254
- e: -231.166451
f_opt: 0.16
pos: !!python/tuple
- 1.5
- 0.5
- 0.50258
- e: -231.336101
f_opt: 0.413
pos: !!python/tuple
- 1.5
- 0.61111
- 0.5027
- e: -231.21672
f_opt: 0.0254
pos: !!python/tuple
- 1.38889
- 0.61111
- 0.5027
date_started: Fri Jun 27 13:43:56 +0100 2025
probe_method: min_c
probe_species: H
samples:
a: 10
b: 10
units:
cell: Bohr
energy: eV
force: eV/A
Loading