I'm currently picking up CASTEP for geometry optimization and am following the website's tutorials.

Strangely, none of the documentation indicates how one should efficiently extract information from CASTEP files, despite the fact that the output files are in a human readable format, instead of a machine readable format. For example, I need to test for convergence, and copying and pasting the forces and stresses for even a single calculations is a tedious and error prone task. I highly doubt that this is how regular users actually analyze their data. Presumably, they use a tool to extract the information out from the binary files.

I haven't been able to find an obvious, or standard, tool for dealing with castep output. No one around me uses CASTEP. And I doubt everyone else paid for Materials Studio. So, I have to ask: What are the standard tools people use for plotting output from .castep files?

  • $\begingroup$ I am willing to start using CASTEP too, and that is one of my concerns. Looking at Github, there are several tools that claim to read CASTEP output. $\endgroup$
    – Camps
    Commented Aug 25, 2023 at 20:42
  • 3
    $\begingroup$ github.com/CCP-NC/castepconv is a good place to start for convergence testing, and c2x can extract most of the binary checkpoint file information if that's what you need - alternatively if you know Python you can easily write your own using the DFT Python API $\endgroup$ Commented Aug 26, 2023 at 16:04
  • $\begingroup$ @PhilHasnip by DFT Python API, did you mean this? $\endgroup$ Commented Aug 31, 2023 at 23:41
  • 1
    $\begingroup$ @AbdulMuhaymin yes, CASTEP has a complete implementation of that API -- there's also ASE, of course, but that's mostly file-based. $\endgroup$ Commented Sep 2, 2023 at 1:19

2 Answers 2


I have used CASTEP a lot, through the Materials Studio suite though. Initially, I was doing everything manually, but as you mentioned, it is a very tedious task. I ended up writing my own codes to extract the information I needed. Let me give you an example of one I have used to extract the final energy and some other info. I used R. It is for sure not the most efficient nor the most elegant way to do it, but it is a start. In addition, you can check this publication. All the numerical analysis was done using a simple R code.

#This script imports and reads CASTEP files within a directory for extracting the lattice parameters, final volume, final enthalpy, functional used, and whether long-range dispersion correction was used for the calculations or not.

# the program exports the data into a excel (.xlsx) file. Name is provided by the user. Default location for exporting the file is in the same working directory of the R script
# setting location of the working directory (for the R script)

# loading libraries

library(openxlsx) # for writing in excel format

# getting CASTEP files into a list

print("Introduce the complete route of castep files:")
print("Path must be in the format accepted in R, like 'C:\\Users\\ ...' or 'C:/Users/...' ")
castep_files_list <- list.files(readline(),all.files = FALSE,full.names = TRUE)

# creating the data structure to store the values that will be extracted
castep_data <- data.frame(
  Functional = c(""),
  DFTD = c("On/Off"),
  Volume = c("cubic angstrom"),
  Enthalphy = c("eV"),
  a = c("angstrom"),
  b = c(""),
  c = c(" "),
  alpha = c(" "),
  beta = c(" "),
  gamma = c(" ")

# we have to iterate through each element of the list to read the file
# main 'for' loop
for(i in 1:length(castep_files_list)){
  # castep_files[i]
  # storing the file 'castep_files[i]' in "filetxt' variable
  castep_file <- read.delim(file = castep_files_list[i], header = FALSE, sep = "\n", quote="")
  # getting the type of functional used
  for (j in 1:length(row(castep_file))) {
    if(grepl("using functional", castep_file[j,]))
      functional <- castep_file[j,]
  # checking if a long-range dispersion correction was used
  for (j in 1:length(row(castep_file))) {
    if(grepl("dispersion correction", castep_file[j,]))
      dftd_correction <- castep_file[j,]
  # # extracting the final volume of the structure
  # for (j in 1:length(row(castep_file))) {
  #   if(grepl("Current cell volume", castep_file[j,]))
  #      castep_file[j,]
  #     cell_volume <- castep_file[j,]
  #     # castep_file[j,]
  #   # "cell_volume not found" bug. check why the initial values is requiered

      # extracting the value of the final volume after geometry optimization in numeric format, without string or other characters
      # unit_cell_volume <- as.numeric(unlist(regmatches(cell_volume,gregexpr("(?>-)*[[:digit:]]+\\.*[[:digit:]]*",cell_volume, perl=TRUE))))
      # unit_cell_volume <- unit_cell_volume[1]
  # getting the final lattice constants of the structure (a,b & c)
  # Lattice parameters(A) and cell angles
  for (j in 1:length(row(castep_file))) {
    if(grepl("Final Configuration", castep_file[j,])){
      values_a <- as.numeric(unlist(regmatches(castep_file[j+12,],gregexpr("(?>-)*[[:digit:]]+\\.*[[:digit:]]*",castep_file[j+12,], perl=TRUE))))
      values_b <- as.numeric(unlist(regmatches(castep_file[j+13,],gregexpr("(?>-)*[[:digit:]]+\\.*[[:digit:]]*",castep_file[j+13,], perl=TRUE))))
      values_c <- as.numeric(unlist(regmatches(castep_file[j+14,],gregexpr("(?>-)*[[:digit:]]+\\.*[[:digit:]]*",castep_file[j+14,], perl=TRUE))))
  # getting the value of the final enthalpy (as a string)
  for (j in 1:length(row(castep_file))) {
    # condition specifically design to read CASTEP files with the exact string
    if (grepl("Final Enthalpy", castep_file[j,])){
      energy <- castep_file[j,]
      #extracting the value of the final enthalpy
      enthalpy_value <- as.numeric(unlist(regmatches(energy,gregexpr("(?>-)*[[:digit:]]+\\.*[[:digit:]]*",energy, perl=TRUE))))
  final_enthalpy_value <- enthalpy_value[1]*10^enthalpy_value[2]
  # in units of eV
  # calculating the volume of the unit cell
  unit_cell_volume <- values_a[1]*values_b[1]*values_c[1]
  # storing the newly extracted values into one temporarily data frame
  # columns name must be the same, adding the values as lists of one element
  temp_data <- data.frame(Functional = c(functional),
                          DFTD = c(dftd_correction),
                          Volume = c(unit_cell_volume),
                          Enthalphy = c(final_enthalpy_value),
                          a = c(values_a[1]),
                          b = c(values_b[1]),
                          c = c(values_c[1]),
                          alpha = c(values_a[2]),
                          beta = c(values_b[2]),
                          gamma = c(values_c[2])
  # adding new values to the previously created data frame
  castep_data <- rbind(castep_data,temp_data)

# exporting the data frame to an excel (.xlsx) file
# requesting the name of the file to the user
print("Insert name of file (e.g., /file_name.xlsx)")
name <- readline() #inserting the name of the file in the specified format
write.xlsx(castep_data, name) #writing the data in a .xlsx file
print("file exported successfully :)")
print("file located in:")

This is a somewhat delayed response but I hope that this is better late than never.

The answer to the immediate use case for data extraction for convergence testing is addressed by the CASTEPconv software. This provides support for automation of the entire process of convergence testing from generating input files to producing convergence plots.

The more general question of parsing CASTEP outputs is addressed by the castep_outputs project. This is a new Python library which reads any of the text-format CASTEP output files and generates a Python dictionary or a json file.

These and other compatible preprocessing and analysis software are documented on the CASTEP documentation website https://castep-docs.github.io/castep-docs under "Other codes and Tools".


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .