diff --git a/xvg2csv/xvg2csv.py b/xvg2csv/xvg2csv.py new file mode 100755 index 0000000..e57d812 --- /dev/null +++ b/xvg2csv/xvg2csv.py @@ -0,0 +1,236 @@ +#!/usr/bin/python2 +# xvg2csv +# Copyright (C) 2014 Evgeniy Alekseev +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import argparse, datetime, os + + +def defineType(file): + """function to define type of input file""" + type = None + with open(file, 'r') as input: + for line in input: + if (line[0] == '@') and (line.find("title") > -1): + if (line.find("RMSD") > -1): + type = "rmsd" + elif (line.find("distance") > -1): + type = "dist" + elif (line.find("Angle") > -1): + type = "angl" + break + return type + + +def getAngleOutput(file, first=True): + """function to parse angle file""" + data = [] + with open(file, 'r') as input: + for line in input: + if ((line[0] == '@') or (line[0] == '#')): + continue + try: + if ((not first) and (float(line.split()[0]) == 0.0)): + continue + data.append(float(line.split()[2])) + except: + pass + return data + + +def getDistanceOutput(file, first=True): + """function to parse distance file""" + data = [] + with open(file, 'r') as input: + for line in input: + if ((line[0] == '@') or (line[0] == '#')): + continue + try: + if ((not first) and (float(line.split()[0]) == 0.0)): + continue + data.append(float(line.split()[1]) * 10.0) + except: + pass + return data + + +def getRmsdOutput(file, first=True): + """function to parse rmsd files""" + data = [] + with open(file, 'r') as input: + for line in input: + if ((line[0] == '@') or (line[0] == '#')): + continue + try: + if ((not first) and (float(line.split()[0]) == 0.0)): + continue + data.append(float(line.split()[1]) * 10.0) + except: + pass + return data + + +def getFullFileList(dirs): + """function to get full file list""" + fileList = {} + for dir in dirs: + directory = os.path.abspath(dir) + if (os.path.exists(directory)) and (os.path.isdir(directory)): + newFileList = getFileList(directory) + for label in newFileList.keys(): + if (not fileList.has_key(label)): fileList[label] = {} + for system in newFileList[label].keys(): + if (not fileList[label].has_key(system)): fileList[label][system] = [] + fileList[label][system].append(newFileList[label][system]) + return fileList + + +def getFileList(directory): + """function to get file list""" + rawFileList = [file for file in os.listdir(directory) if (os.path.splitext(file)[1] == ".xvg")] + rawFileList.sort() + return parseFileList(directory, rawFileList) + + +def parseFileList(directory, rawFileList): + """function to parse file list""" + fileList = {} + for file in rawFileList: + fullFileName = os.path.join(directory, file) + label = os.path.splitext(file)[0].split('_')[-2] + system = '_'.join(os.path.splitext(file)[0].split('_')[:-2]) + if (not fileList.has_key(label)): fileList[label] = {} + if (not fileList[label].has_key(system)): fileList[label][system] = [] + if (fileList[label][system].count(fullFileName) == 0): + fileList[label][system].append(fullFileName) + return fileList + + +def getAveragingData(rawData, time): + """function to get averaging data""" + data = {} + for system in rawData.keys(): + if (not data.has_key(system)): data[system] = [] + count = len(rawData[system]) / time + for i in range(count): + value = sum(rawData[system][i*time:(i+1)*time]) / float(time) + data[system].append(value) + return data + + + +def getData(fileList): + """function to get data from files""" + rawData = {} + for system in fileList.keys(): + first = True + type = None + if (not rawData.has_key(system)): rawData[system] = [] + for files in fileList[system]: + for file in files: + if (first): + type = defineType(file) + if (type == "rmsd"): + rawData[system].append(getRmsdOutput(file, first)) + elif (type == "dist"): + rawData[system] = rawData[system] + getDistanceOutput(file, first) + elif (type == "angl"): + rawData[system].append(getAngleOutput(file, first)) + if (first): + first = False + return rawData + + +def createCsv(directory, label, data, timeStep): + """function to create *.csv file""" + file = os.path.join(directory, label + ".csv") + with open(file, "w") as output: + output.write("t\t%s\n" % ('\t'.join(data.keys()))) + count = max([len(data[system]) for system in data.keys()]) + for i in range(count): + line = "%.3f" % (i * timeStep + timeStep / 2.0) + for system in data.keys(): + if (len(data[system]) > i): + line = "%s\t%.5f" % (line, data[system][i]) + else: + line = "%s\t" % (line) + output.write(line + "\n") + + +def createQti(directory, label, data, timeStep): + """function to create *.qti file""" + file = os.path.join(directory, label + ".qti") + with open(file, "w") as output: + count = max([len(data[system]) for system in data.keys()]) + timestamp = datetime.datetime.now().strftime("%d.%m.%y %H:%M") + output.write("QtiPlot 0.9.8 project file\n") + output.write("\tPython\n") + output.write("\t1\n") + output.write("\n") + output.write("%s\t%i\t%i\t%s\n" % (label, count, len(data.keys()) + 1, timestamp)) + output.write("geometry\t0\t0\t445\t220\t\n") + output.write("header\tt[X]\t%s[Y]\n" % ('[Y]\t'.join(data.keys()))) + output.write("ColWidth\t100") + for system in data.keys(): output.write("\t100") + output.write("\n\n\n") + output.write("ColType\t0;0/13") + for system in data.keys(): output.write("\t0;0/13") + output.write("\nReadOnlyColumn\t0") + for system in data.keys(): output.write("\t0") + output.write("\nHiddenColumn\t0") + for system in data.keys(): output.write("\t0") + output.write("\nComments\t\t") + for system in data.keys(): output.write("\t") + output.write("\nWindowLabel\t\t2\n\n") + for i in range(count): + line = "%i\t%.3f" % (i, i * timeStep + timeStep / 2.0) + for system in data.keys(): + if (len(data[system]) > i): + line = "%s\t%.8f" % (line, data[system][i]) + else: + line = "%s\t" % (line) + output.write(line + "\n") + output.write("\n
\n") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description = 'Convert GROMACS *.xvg files to *.csv and *.qti. Example filename is "system_label_number.xvg"') + parser.add_argument('-d', '--directories', dest = 'dirs', + help = 'Directories, comma separared', action = 'store', default = ".") + parser.add_argument('-o', '--output', dest = 'output', + help = 'Output directory', action = 'store', default = ".") + parser.add_argument('-nc', '--nocsv', dest = 'nocsv', + help = 'Do not create *.csv file', action = 'store_true', default = False) + parser.add_argument('-nq', '--noqti', dest = 'noqti', + help = 'Do not create *.qti file', action = 'store_true', default = False) + parser.add_argument('-t', '--time', dest = 'time', + help = 'Averaging time', action = 'store', default = 100) + parser.add_argument('-s', '--step', dest = 'step', + help = 'Time step', action = 'store', default = 1.0) + args = parser.parse_args() + + dirs = args.dirs.split(',') + output = os.path.abspath(args.output) + if not os.path.exists(output): os.makedirs(output) + + fileList = getFullFileList(dirs) + for label in fileList.keys(): + rawData = getData(fileList[label]) + data = getAveragingData(rawData, args.time) + if (not args.nocsv): + createCsv(output, label, data, args.step) + if (not args.noqti): + createQti(output, label, data, args.step)