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)
#
setwd("C:\\Users\\...\\script\\")
# loading libraries
library(readr)
library(pracma)
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,]
#print()
}
# 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,]
#print()dftd_correction
}
# # 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:")
print(getwd())
```