castep_outputs demo#
In this Jupyter Notebook we’ll look at how to use the castep_outputs
module to process CASTEP output files.
First we’ll set up some data to process.
import pathlib
data_path = pathlib.Path.cwd() / "example_data"
examples = data_path / "pair-pot-lj"
param_file = examples.with_suffix(".param")
param_file
PosixPath('/home/runner/work/castep_outputs/castep_outputs/docs/example_data/pair-pot-lj.param')
print(param_file.read_text())
task : moleculardynamics # Comment
md_delta_t = 5 fs
md_ensemble = nvt
md_thermostat = langevin
md_ion_t = 50 fs
md_num_iter = 10
md_sample_iter = 5
md_temperature 100 K
cut_off_energy : 100 eV
write_checkpoint : none
write_bib : false
%block DEVEL_CODE
PP=T
# Another comment
PP: LJ=T LJ_EPS_Ar=120. LJ_SIG_Ar=0.3405 :ENDPP
%endblock DEVEL_CODE
popn_write : minimal
It is possible to use castep_outputs
directly by importing the top-level castep_outputs and using parse_single
to parse a single datafile.
import castep_outputs
lj_data = castep_outputs.parse_single(param_file)
lj_data
[{'task': 'moleculardynamics',
'md_delta_t': (5, 'fs'),
'md_ensemble': 'nvt',
'md_thermostat': 'langevin',
'md_ion_t': (50, 'fs'),
'md_num_iter': 10,
'md_sample_iter': 5,
'md_temperature': (100, 'K'),
'cut_off_energy': (100, 'eV'),
'write_checkpoint': 'none',
'write_bib': False,
'devel_code': {'pp': {'lj': True, 'lj_eps_ar': 120.0, 'lj_sig_ar': 0.3405},
'_pp': True},
'popn_write': 'minimal'}]
Note that many of the data are parsed into the appropriate Python types. e.g logicals to bool
s and numeric types to their most likely type.
parse_single
works by determining the type of parser from the file extension. If we don’t have a file extension, the parser will fail.
from io import StringIO
cell_file = examples.with_suffix(".cell")
# Read the file into a file-like buffer, which doesn't contain the extension or details.
file = StringIO(cell_file.read_text())
try:
castep_outputs.parse_single(file)
except ValueError as err:
print(f"Oh no! {err=}")
Oh no! err=ValueError('Unable to determine parser. Please specify through arguments.')
To rectify this, we can explicitly pass the parser (by file extension) we want to use.
# Rewind to the beginning of the buffer
file.seek(0)
castep_outputs.parse_single(file, parser="cell")
[{'lattice_cart': {'data': [(17.395297, 0.0, 0.0),
(0.0, 17.395297, 0.0),
(0.0, 0.0, 17.395297)]},
'positions_abs': {('Ar', 1): {'pos': (4.023973, 2.257202, 2.476523),
'units': 'Ang'},
('Ar', 2): {'pos': (4.29215, 0.741938, -1.542184), 'units': 'Ang'},
('Ar', 3): {'pos': (0.834362, 4.894828, 5.031917), 'units': 'Ang'},
('Ar', 4): {'pos': (-7.896037, -0.914764, -0.186325), 'units': 'Ang'},
('Ar', 5): {'pos': (-5.92112, -1.280009, 5.918613), 'units': 'Ang'}},
'fix_all_cell': True,
'kpoint_mp_spacing': (1.0, '1/ang')}]
Or pass it as the callable directly.
# Rewind to the beginning of the buffer
file.seek(0)
castep_outputs.parse_single(file, parser=castep_outputs.parse_cell_file)
[{'lattice_cart': {'data': [(17.395297, 0.0, 0.0),
(0.0, 17.395297, 0.0),
(0.0, 0.0, 17.395297)]},
'positions_abs': {('Ar', 1): {'pos': (4.023973, 2.257202, 2.476523),
'units': 'Ang'},
('Ar', 2): {'pos': (4.29215, 0.741938, -1.542184), 'units': 'Ang'},
('Ar', 3): {'pos': (0.834362, 4.894828, 5.031917), 'units': 'Ang'},
('Ar', 4): {'pos': (-7.896037, -0.914764, -0.186325), 'units': 'Ang'},
('Ar', 5): {'pos': (-5.92112, -1.280009, 5.918613), 'units': 'Ang'}},
'fix_all_cell': True,
'kpoint_mp_spacing': (1.0, '1/ang')}]
Alternatively, we can just apply the correct parser directly.
# Rewind to the beginning of the buffer
file.seek(0)
castep_outputs.parse_cell_file(file)
[{'lattice_cart': {'data': [(17.395297, 0.0, 0.0),
(0.0, 17.395297, 0.0),
(0.0, 0.0, 17.395297)]},
'positions_abs': {('Ar', 1): {'pos': (4.023973, 2.257202, 2.476523),
'units': 'Ang'},
('Ar', 2): {'pos': (4.29215, 0.741938, -1.542184), 'units': 'Ang'},
('Ar', 3): {'pos': (0.834362, 4.894828, 5.031917), 'units': 'Ang'},
('Ar', 4): {'pos': (-7.896037, -0.914764, -0.186325), 'units': 'Ang'},
('Ar', 5): {'pos': (-5.92112, -1.280009, 5.918613), 'units': 'Ang'}},
'fix_all_cell': True,
'kpoint_mp_spacing': (1.0, '1/ang')}]