Source code for tcc_python_scripts.post_processing.cluster_movie_maker
""" A script to take the RAW file output from the TCC and produce a combined
cluster XYZ for rendering. Takes a cluster list argument and labels
particles according to the list priority."""
import sys
import io
import string
[docs]def add_cluster_to_xyz(xyz_frame, particle_types, cluster_number):
"""
Given a list of particle types, overwrite the cluster type in xyz_frame if
a particle is in a cluster.
Args:
xyz_frame (cluster_movie_maker.Snapshot): A snapshot of the system.
particle_types (list of string): Whether particles are in a cluster
or not. "A" and "B" correspond to particles not in a cluster while
"C" and "D" correspond to particles in a cluster
cluster_number (integer): The index of the cluster in the priority
Returns:
cluster_movie_maker.Snapshot: an updated XYZ snapshot.
"""
for index, particle in enumerate(particle_types):
if particle == "C" or particle == "D":
xyz_frame.particle_species[index] = \
string.ascii_uppercase[cluster_number + 1]
return xyz_frame
[docs]def prepare_output_file(output_filename):
"""
Open the output file once at the beginning of the analysis to delete
any previous copy.
"""
open(output_filename, 'w').close()
[docs]def main(xyz_name, raw_stub, cluster_list):
"""
The main loop.
Returns:
int: 0 if script ran successfully.
"""
output_filename = "output.xyz"
cluster_list = list(reversed(cluster_list.split()))
raw_file_handles = open_raw_files(cluster_list, raw_stub)
xyz_file = XyzFileReader(xyz_name)
print("Particles not in any cluster are labelled with the letter A")
prepare_output_file(output_filename)
for frame_number, xyz_frame in enumerate(xyz_file):
for index, raw_file in enumerate(raw_file_handles):
cluster_types = raw_file.get_frame()
xyz_frame = add_cluster_to_xyz(xyz_frame, cluster_types, index)
if frame_number == 0:
print("Cluster type {} is labelled with the letter {}".format(
raw_file.cluster_name, string.ascii_uppercase[index + 1]))
xyz_frame.write_xyz(output_filename)
[docs]def open_raw_files(cluster_list, raw_stub):
"""
Given a list of clusters, open the corresponding TCC RAW files.
Args:
cluster_list (list of string): TCC cluster names in reverse order
of priority.
raw_stub (string): The base of the RAW file name relative to the
working directory.
Returns:
list of RawFileReader: Objects representing the open RAW files.
"""
raw_file_handles = []
for cluster_type in cluster_list:
raw_file_handles.append(RawFileReader(raw_stub, cluster_type))
return raw_file_handles
[docs]def process_arguments():
"""
Process the command line arguments and return variables with the values.
Returns:
strings: Processed command line parameters.
"""
if len(sys.argv) != 4:
print("Syntax: ./cluster_movie_maker.py simulation_data.xyz "
"simulation_data.xyz.raw_ cluster_priority_list")
sys.exit()
xyz_name = sys.argv[1]
raw_stub = sys.argv[2]
cluster_list = sys.argv[3]
return xyz_name, raw_stub, cluster_list
[docs]class XyzFileReader:
"""
Generator for xyz files. Opens a file handle when the object is
instantiated. Iteration then returns the file frame by frame.
"""
def __init__(self, file_name):
"""
On instantiation, open a file handle to file_name.
Args:
file_name (string): The xyz file to open.
"""
self.file_handle = open(file_name, 'r')
def __iter__(self):
"""
Reads a single frame from the xyz and returns it.
Returns:
Snapshot: A snapshot object representing a single frame from the
xyz.
"""
line = self.file_handle.readline()
while line != "" and line != "\n":
xyz_snapshot = Snapshot()
xyz_snapshot.num_particles = self.process_num_particles(line)
xyz_snapshot.comment = self.file_handle.readline()
for particle in range(xyz_snapshot.num_particles):
line = self.file_handle.readline().split()
# All particles are labelled "A" as this represents not being
# present in a cluster. This value is later overwritten if it
# is in a cluster.
xyz_snapshot.particle_species.append("A")
xyz_snapshot.x_coordinates.append(float(line[1]))
xyz_snapshot.y_coordinates.append(float(line[2]))
xyz_snapshot.z_coordinates.append(float(line[3]))
yield xyz_snapshot
# Read the first line of the next frame
line = self.file_handle.readline()
[docs] @staticmethod
def process_num_particles(line):
"""
Process the first line of an XYZ frame to make sure that it is a
valid number.
Args:
line (string): The first line of an xyz frame.
Returns:
integer: The number of particles from line.
"""
try:
num_particles = int(line)
except TypeError:
print("Error reading number of particles from XYZ file.")
raise TypeError
return num_particles
[docs]class RawFileReader:
"""
Reader for TCC .RAW files. Instantiation opens a file handle and the get
frame method then allows the file to be read a frame at a time.
"""
def __init__(self, file_stub, cluster_type):
"""
Open the RAW file specified by file_name.
Args:
file_stub (string): The base of the file name relative to the
working directory.
cluster_type (string): The TCC cluster type e.g. "10A"
"""
file_name = "{}{}".format(file_stub, cluster_type)
self.file_handle = open(file_name, "r")
self.num_particles = 0
self.cluster_name = cluster_type
[docs] def get_frame(self):
"""
Get a single frame of data from the raw file.
Returns:
list of string: Whether the particles are in a cluster or not.
"""
self.num_particles = int(self.file_handle.readline())
# Skip the comment line
_ = self.file_handle.readline()
type_list = []
for particle in range(self.num_particles):
line = self.file_handle.readline().split()
type_list.append(line[0])
return type_list
[docs]class Snapshot:
"""
Object representing a single configuration of a system with particle types
and coordinates.
"""
def __init__(self):
"""
Initialise variables.
"""
self.num_particles = 0
self.comment = ""
self.particle_species = []
self.x_coordinates = []
self.y_coordinates = []
self.z_coordinates = []
def __str__(self):
""""
Returns:
string: String representation of the Snapshot.
"""
buffer = io.StringIO()
for particle in range(self.num_particles):
buffer.write("{} {} {} {}\n".format(self.particle_species[particle],
self.x_coordinates[particle],
self.y_coordinates[particle],
self.z_coordinates[particle]))
return buffer.getvalue()
[docs] def write_xyz(self, output_name):
"""
Write the Snapshot to an xyz file.
"""
with open(output_name, 'a') as output_file:
output_file.write("{}\n".format(self.num_particles))
output_file.write("{}".format(self.comment))
for particle in range(self.num_particles):
output_file.write("{}\t{}\t{}\t{}\n".
format(self.particle_species[particle],
self.x_coordinates[particle],
self.y_coordinates[particle],
self.z_coordinates[particle]))
if __name__ == "__main__":
xyz_name, raw_stub, cluster_list = process_arguments()
main(xyz_name, raw_stub, cluster_list)