CASTEP [1] W is a software package which uses density functional theory to provide a good atomic-level description of all manner of materials and molecules. CASTEP can give information about total energies, forces and stresses on an atomic system, as well as calculating optimum geometries, band structures, optical spectra, phonon spectra and much more. It can also perform molecular dynamics simulations.

The CASTEP calculator interface class offers intuitive access to all CASTEP settings and most results. All CASTEP specific settings are accessible via attribute access (i.e. calc.param.keyword = ... or calc.cell.keyword = ...)

Getting Started:

Set the environment variables appropriately for your system:

export CASTEP_COMMAND=' ... '
export CASTEP_PP_PATH=' ... '

Note: alternatively to CASTEP_PP_PATH one can set PSPOT_DIR as CASTEP consults this by default, i.e.:

export PSPOT_DIR=' ... '

Running the Calculator

The default initialization command for the CASTEP calculator is

class ase.calculators.castep.Castep(directory='CASTEP', label='castep')[source]

To do a minimal run one only needs to set atoms, this will use all default settings of CASTEP, meaning LDA, singlepoint, etc..

With a generated castep_keywords.json in place all options are accessible by inspection, i.e. tab-completion. This works best when using ipython. All options can be accessed via calc.param.<TAB> or calc.cell.<TAB> and documentation is printed with calc.param.<keyword> ? or calc.cell.<keyword> ?. All options can also be set directly using calc.keyword = ... or calc.KEYWORD = ... or even ialc.KeYwOrD or directly as named arguments in the call to the constructor (e.g. Castep(task='GeometryOptimization')). If using this calculator on a machine without CASTEP, one might choose to copy a castep_keywords.json file generated elsewhere in order to access this feature: the file will be used if located in the working directory, $HOME/.ase/ or ase/ase/calculators/ within the ASE library. The file should be generated the first time it is needed, but you can generate a new keywords file in the currect directory with python -m ase.calculators.castep.

All options that go into the .param file are held in an CastepParam instance, while all options that go into the .cell file and don’t belong to the atoms object are held in an CastepCell instance. Each instance can be created individually and can be added to calculators by attribute assignment, i.e. calc.param = param or calc.cell = cell.

All internal variables of the calculator start with an underscore (_). All cell attributes that clearly belong into the atoms object are blocked. Setting calc.atoms_attribute (e.g. = positions) is sent directly to the atoms object.





The relative path where all input and output files will be placed. If this does not exist, it will be created. Existing directories will be moved to directory-TIMESTAMP unless self._rename_existing_dir is set to false.


The prefix of .param, .cell, .castep, etc. files.


Command to run castep. Can also be set via the bash environment variable CASTEP_COMMAND. If none is given or found, will default to castep


Boolean whether to check if the installed castep version matches the version from which the available options were deduced. Defaults to False.


The path where the pseudopotentials are stored. Can also be set via the bash environment variables PSPOT_DIR (preferred) and CASTEP_PP_PATH. Will default to the current working directory if none is given or found. Note that pseudopotentials may be generated on-the-fly if they are not found.


Boolean whether to search for pseudopotentials in <castep_pp_path> or not. If activated, files in this directory will be checked for typical names. If files are not found, they will be generated on the fly, depending on the _build_missing_pspots value. A RuntimeError will be raised in case multiple files per element are found. Defaults to False.


Integer to indicate the level of tolerance to apply validation of any parameters set in the CastepCell or CastepParam objects against the ones found in castep_keywords. Levels are as following:

0 = no tolerance, keywords not found in castep_keywords will raise an exception

1 = keywords not found will be accepted but produce a warning (default)

2 = keywords not found will be accepted silently

3 = no attempt is made to look for castep_keywords.json at all


Can be used to pass a CastepKeywords object that is then used with no attempt to actually load a castep_keywords.json file. Most useful for debugging and testing purposes.

Additional Settings

Internal Setting



(=castep): the actual shell command used to call CASTEP.


(=True): this makes write_param() only write a continue or reuse statement if the addressed .check or .castep_bin file exists in the directory.


(=False): if set to True the calculator will actually copy the needed pseudo-potential (*.usp) file, usually it will only create symlinks.


(=True): if set to True the calculator will actually will create symlinks to the needed pseudo potentials. Set this option (and _copy_pspots) to False if you rather want to access your pseudo potentials using the PSPOT_DIR environment variable that is read by CASTEP. Note: This option has no effect if copy_pspots is True..


(=True): if set to True, castep will generate missing pseudopotentials on the fly. If not, a RuntimeError will be raised if not all files were found.


(=True): if this is set to True, all calculator internal settings shown here will be included in the .param in a comment line (#) and can be read again by merge_param. merge_param can be forced to ignore this directive using the optional argument ignore_internal_keys=True.


(=True): this controls wether the *cell and *param will be overwritten.


(=False): If set to True, the calculator will create *cell und *param file but not start the calculation itself. If this is used to prepare jobs locally and run on a remote cluster it is recommended to set _copy_pspots = True.


(='.') : the place where the calculator will look for pseudo-potential files.


(=False): if set to True, the calculator will try to find the respective pseudopotentials from <_castep_pp_path>. As long as there are no multiple files per element in this directory, the auto-detect feature should be very robust. Raises a RuntimeError if required files are not unique (multiple files per element). Non existing pseudopotentials will be generated, though this could be dangerous.


(=True) : when using a new instance of the calculator, this will move directories out of the way that would be overwritten otherwise, appending a date string.


(=False) : setting this to True will overwrite any atoms object previously attached to the calculator when reading a .castep file. By de- fault, the read() function will only create a new atoms object if none has been attached and other- wise try to assign forces etc. based on the atom’s positions. _set_atoms=True could be necessary if one uses CASTEP’s internal geometry optimization (calc.param.task='GeometryOptimization') because then the positions get out of sync. Warning: this option is generally not recommended unless one knows one really needs it. There should never be any need, if CASTEP is used as a single-point calculator.


(=False) : if set to true, the interface will append a number to the label on all input and output files, where n is the number of calls to this instance. Warning: this setting may con- sume a lot more disk space because of the additio- nal *check files.


(=_track_output) : when setting this, the in- terface will try to fetch the reuse file from the previous run even if _track_output is True. By de- fault it is equal to _track_output, but may be overridden.

Since this behavior may not always be desirable for single-point calculations. Regular reuse for e.g. a geometry-optimization can be achieved by setting calc.param.reuse = True.


(=False) if set to true, the calculator will inform about settings probably wasting a lot of CPU time or causing numerical inconsistencies.

Special features:


Runs castep_command seed -dryrun in a temporary directory return True if all variables initialized ok. This is a fast way to catch errors in the input. Afterwards _kpoints_used is set.


Takes a filename or filehandler of a .param file or CastepParam instance and merges it into the current calculator instance, overwriting current settings


Can be used on any option like calc.param.keyword.clear() or calc.cell.keyword.clear() to return to the CASTEP default.


Creates all needed input in the _directory. This can then copied to and run in a place without ASE or even python.


This automatically sets the pseudo-potential for all present species to <Species>_<library>.usp. Make sure that _castep_pp_path is set correctly. Note that there is no check, if the file actually exists. If it doesn’t castep will crash! You may want to use find_pspots() instead.

.find_pspots(pspot=<library>, suffix=<suffix>)

This automatically searches for pseudopotentials of type <Species>_<library>.<suffix> or <Species>-<library>.<suffix> in castep_pp_path` (make sure this is set correctly). Note that ``<Species> will be searched for case insensitive. Regular expressions are accepted, and arguments '*' will be regarded as bash-like wildcards. Defaults are any <library> and any <suffix> from ['usp', 'UPF', 'recpot']. If you have well-organized folders with pseudopotentials of one kind, this should work with the defaults.


Prints a short summary of the calculator settings and atoms.'path-to/seed')

Given you have a combination of seed.{param,cell,castep} this will return an atoms object with the last ionic positions in the .castep file and all other settings parsed from the .cell and .param file. If no .castep file is found the positions are taken from the .cell file. The output directory will be set to the same directory, only the label is preceded by ‘copy_of_’ to avoid overwriting.


This is equivalent to initialising the calculator with calc = Castep(kpts=kpoints). kpoints can be specified in many convenient forms: simple Monkhorst-Pack grids can be specified e.g. (2, 2, 3) or '2 2 3'; lists of specific weighted k-points can be given in reciprocal lattice coordinates e.g. [[0, 0, 0, 0.25], [0.25, 0.25, 0.25, 0.75]]; a dictionary syntax is available for more complex requirements e.g. {'size': (2, 2, 2), 'gamma': True} will give a Gamma-centered 2x2x2 M-P grid, {'density': 10, 'gamma': False, 'even': False} will give a mesh with density of at least 10 Ang (based on the unit cell of currently-attached atoms) with an odd number of points in each direction and avoiding the Gamma point.


This is equivalent to initialialising the calculator with calc=Castep(bandpath=bandpath) and may be set simultaneously with kpts. It allows an electronic band structure path to be set up using ASE BandPath objects. This enables a band structure calculation to be set up conveniently using e.g. calc.set_bandpath(atoms.cell.bandpath().interpolate(npoints=200))


Read a band structure from _seedname.bands_ file. This returns an ase BandStructure object which may be plotted with e.g. calc.band_structure().plot()


  • Currently only the FixAtoms constraint is fully supported for reading and writing. There is some experimental support for the FixCartesian constraint.

  • There is no support for the CASTEP unit system. Units of eV and Angstrom are used throughout. In particular when converting total energies from different calculators, one should check that the same CODATA version is used for constants and conversion factors, respectively.


"""This simple demo calculates the total energy of CO molecules
using once LDA and once PBE as xc-functional. Obviously
some parts in this scripts are longer than necessary, but are shown
to demonstrate some more features."""

import ase
import ase.calculators.castep

calc = ase.calculators.castep.Castep()
directory = 'CASTEP_ASE_DEMO'

# include interface settings in .param file
calc._export_settings = True

# reuse the same directory
calc._directory = directory
calc._rename_existing_dir = False
calc._label = 'CO_LDA'

# necessary for tasks with changing positions
# such as GeometryOptimization or MolecularDynamics
calc._set_atoms = True

# Param settings
calc.param.xc_functional = 'LDA'
calc.param.cut_off_energy = 400
# Prevent CASTEP from writing *wvfn* files
calc.param.num_dump_cycles = 0

# Cell settings
calc.cell.kpoint_mp_grid = '1 1 1'
calc.cell.fix_com = False
calc.cell.fix_all_cell = True

# Set and clear and reset settings (just for shows)
calc.param.task = 'SinglePoint'
# Reset to CASTEP default

# all of the following are identical
calc.param.task = 'GeometryOptimization'
calc.task = 'GeometryOptimization'
calc.TASK = 'GeometryOptimization'
calc.Task = 'GeometryOptimization'

# Prepare atoms
mol = ase.atoms.Atoms('CO', [[0, 0, 0], [0, 0, 1.2]], cell=[10, 10, 10])
mol.calc = calc

# Check for correct input
if calc.dryrun_ok():
    print(f'{mol.calc._label} : {mol.get_potential_energy()} ')
    print("Found error in input")

# Read all settings from previous calculation
mol ='%s/CO_LDA' % directory)

# Use the OTF pseudo-potential we have just generated

# Change some settings
mol.calc.param.xc_functional = 'PBE'
# don't forget to set an appropriate label
mol.calc._label = 'CO_PBE'
# Recalculate the potential energy
print(f'{mol.calc._label} : {mol.get_potential_energy()} ')