From 8964d1d078a70c6c218f7bab6c445fee0a7f6d03 Mon Sep 17 00:00:00 2001 From: James Graham <J.A.Graham@soton.ac.uk> Date: Tue, 5 Jul 2016 16:46:01 +0100 Subject: [PATCH] Fixed stopping on first frame - test added Put main() and map_only() into pycgtool module --- pycgtool.py | 100 ++-------------------------------------- pycgtool/interface.py | 7 ++- pycgtool/pycgtool.py | 98 +++++++++++++++++++++++++++++++++++++++ test/data/sugar_out.xtc | Bin 0 -> 1408 bytes test/test_pycgtool.py | 45 ++++++++++++++++++ 5 files changed, 151 insertions(+), 99 deletions(-) create mode 100755 pycgtool/pycgtool.py create mode 100644 test/data/sugar_out.xtc diff --git a/pycgtool.py b/pycgtool.py index c30d715..ebd3000 100755 --- a/pycgtool.py +++ b/pycgtool.py @@ -2,100 +2,9 @@ import argparse import sys -import logging - -from pycgtool.frame import Frame -from pycgtool.mapping import Mapping -from pycgtool.bondset import BondSet -from pycgtool.forcefield import ForceField -from pycgtool.interface import Progress, Options - -logger = logging.getLogger(__name__) - - -def main(args, config): - """ - Main function of the program PyCGTOOL. - - Performs the complete AA->CG mapping and outputs a files dependent on given input. - - :param args: Arguments from argparse - :param config: Configuration dictionary - """ - frame = Frame(gro=args.gro, xtc=args.xtc, itp=args.itp, frame_start=args.begin, xtc_reader="mdtraj") - - if args.bnd: - bonds = BondSet(args.bnd, config) - logger.info("Bond measurements will be made") - else: - logger.info("Bond measurements will not be made") - - if args.map: - mapping = Mapping(args.map, config, itp=args.itp) - cgframe = mapping.apply(frame, exclude={"SOL"}) - cgframe.output(config.output_name + ".gro", format=config.output) - logger.info("Mapping will be performed") - else: - logger.info("Mapping will not be performed") - - # Main loop - perform mapping and measurement on every frame in XTC - def main_loop(): - nonlocal cgframe - frame.next_frame() - if args.map: - cgframe = mapping.apply(frame, cgframe=cgframe, exclude={"SOL"}) - if config.output_xtc: - cgframe.write_xtc(config.output_name + ".xtc") - else: - cgframe = frame - if args.bnd: - bonds.apply(cgframe) - - numframes = frame.numframes - args.begin if args.end == -1 else args.end - args.begin - logger.info("Beginning analysis of {0} frames".format(numframes)) - Progress(numframes, postwhile=main_loop).run() - - if args.bnd: - if args.map: - logger.info("Beginning Boltzmann inversion") - bonds.boltzmann_invert() - if config.output_forcefield: - logger.info("Creating GROMACS forcefield directory") - ff = ForceField("ff" + config.output_name + ".ff") - ff.write_rtp(config.output_name + ".rtp", mapping, bonds) - logger.info("GROMACS forcefield directory created") - else: - bonds.write_itp(config.output_name + ".itp", mapping=mapping) - - if config.dump_measurements: - logger.info("Dumping bond measurements to file") - bonds.dump_values(config.dump_n_values) - - -def map_only(args, config): - """ - Perform AA->CG mapping and output coordinate file. - - :param args: Program arguments - :param config: Object containing run options - """ - frame = Frame(gro=args.gro, xtc=args.xtc) - mapping = Mapping(args.map, config) - cgframe = mapping.apply(frame, exclude={"SOL"}) - cgframe.output(config.output_name + ".gro", format=config.output) - - if args.xtc and (config.output_xtc or args.outputxtc): - # Main loop - perform mapping and measurement on every frame in XTC - def main_loop(): - nonlocal cgframe - frame.next_frame() - cgframe = mapping.apply(frame, cgframe=cgframe, exclude={"SOL"}) - cgframe.write_xtc(config.output_name + ".xtc") - - numframes = frame.numframes - args.begin if args.end == -1 else args.end - args.begin - logger.info("Beginning analysis of {0} frames".format(numframes)) - Progress(numframes, postwhile=main_loop).run() +from pycgtool.pycgtool import main, map_only +from pycgtool.interface import Options if __name__ == "__main__": parser = argparse.ArgumentParser(description="Perform coarse-grain mapping of atomistic trajectory") @@ -108,6 +17,7 @@ if __name__ == "__main__": parser.add_argument('--interactive', default=False, action='store_true') parser.add_argument('--outputxtc', default=False, action='store_true') + parser.add_argument('--quiet', default=False, action='store_true') input_files.add_argument('--begin', type=int, default=0, help="Frame number to begin") input_files.add_argument('--end', type=int, default=-1, help="Frame number to end") @@ -140,10 +50,6 @@ if __name__ == "__main__": print("Using XTC: {0}".format(args.xtc)) if config.map_only: - logger.info("Starting: mapping only") map_only(args, config) else: - logger.info("Starting: parameter measurement") main(args, config) - - logger.info("Analysis complete") diff --git a/pycgtool/interface.py b/pycgtool/interface.py index d22d3ed..db65c37 100644 --- a/pycgtool/interface.py +++ b/pycgtool/interface.py @@ -263,14 +263,17 @@ class Progress: """ Iterate through self until stopped by maximum iterations or False condition. """ - collections.deque(self, maxlen=0) + # collections.deque(self, maxlen=0) + for _ in self: + pass return self._its @property def _bar(self): done = int(self._length * (self._its / self._maxits)) left = self._length - done - return "{0} [".format(self._its) + done * "#" + left * "-" + "] {0}".format(self._maxits) + width = len(str(self._maxits)) + return "{0:-{width}} [".format(self._its, width=width) + done * "#" + left * "-" + "] {0}".format(self._maxits) def _stop(self): if not self._quiet: diff --git a/pycgtool/pycgtool.py b/pycgtool/pycgtool.py new file mode 100755 index 0000000..c728e9b --- /dev/null +++ b/pycgtool/pycgtool.py @@ -0,0 +1,98 @@ +import logging + +from .frame import Frame +from .mapping import Mapping +from .bondset import BondSet +from .forcefield import ForceField +from .interface import Progress + +logger = logging.getLogger(__name__) + + +def main(args, config): + """ + Main function of the program PyCGTOOL. + + Performs the complete AA->CG mapping and outputs a files dependent on given input. + + :param args: Arguments from argparse + :param config: Configuration dictionary + """ + frame = Frame(gro=args.gro, xtc=args.xtc, itp=args.itp, frame_start=args.begin, xtc_reader="mdtraj") + + if args.bnd: + bonds = BondSet(args.bnd, config) + logger.info("Bond measurements will be made") + else: + logger.info("Bond measurements will not be made") + + if args.map: + mapping = Mapping(args.map, config, itp=args.itp) + cgframe = mapping.apply(frame, exclude={"SOL"}) + cgframe.output(config.output_name + ".gro", format=config.output) + logger.info("Mapping will be performed") + else: + logger.info("Mapping will not be performed") + + # Main loop - perform mapping and measurement on every frame in XTC + def main_loop(): + nonlocal cgframe + if not frame.next_frame(): + return False + if args.map: + cgframe = mapping.apply(frame, cgframe=cgframe, exclude={"SOL"}) + if config.output_xtc: + cgframe.write_xtc(config.output_name + ".xtc") + else: + cgframe = frame + if args.bnd: + bonds.apply(cgframe) + return True + + numframes = frame.numframes - args.begin if args.end == -1 else args.end - args.begin + logger.info("Beginning analysis of {0} frames".format(numframes)) + Progress(numframes, postwhile=main_loop, quiet=args.quiet).run() + + if args.bnd: + if args.map: + logger.info("Beginning Boltzmann inversion") + bonds.boltzmann_invert() + if config.output_forcefield: + logger.info("Creating GROMACS forcefield directory") + ff = ForceField("ff" + config.output_name + ".ff") + ff.write_rtp(config.output_name + ".rtp", mapping, bonds) + logger.info("GROMACS forcefield directory created") + else: + bonds.write_itp(config.output_name + ".itp", mapping=mapping) + + if config.dump_measurements: + logger.info("Dumping bond measurements to file") + bonds.dump_values(config.dump_n_values) + + +def map_only(args, config): + """ + Perform AA->CG mapping and output coordinate file. + + :param args: Program arguments + :param config: Object containing run options + """ + frame = Frame(gro=args.gro, xtc=args.xtc) + mapping = Mapping(args.map, config) + cgframe = mapping.apply(frame, exclude={"SOL"}) + cgframe.output(config.output_name + ".gro", format=config.output) + + if args.xtc and (config.output_xtc or args.outputxtc): + # Main loop - perform mapping and measurement on every frame in XTC + def main_loop(): + nonlocal cgframe + if not frame.next_frame(): + return False + cgframe = mapping.apply(frame, cgframe=cgframe, exclude={"SOL"}) + cgframe.write_xtc(config.output_name + ".xtc") + return True + + numframes = frame.numframes - args.begin if args.end == -1 else args.end - args.begin + logger.info("Beginning analysis of {0} frames".format(numframes)) + Progress(numframes, postwhile=main_loop, quiet=args.quiet).run() + diff --git a/test/data/sugar_out.xtc b/test/data/sugar_out.xtc new file mode 100644 index 0000000000000000000000000000000000000000..0f9b0822191d84aa887bedd2c1c71978a93fcb20 GIT binary patch literal 1408 zcmZQzU_Z^kz`(}9z`)4Bz`)>;e{LO!hG7i8wk9h`y@Rd)0|%SGU+h;qPjfJQ-R5BT zvdVt<^IQj`11%1QVjcE7Z>u<HZ*z0dHa4+e{QZK1(QZBmy_@3pox9>3ECiArEX{rF zX9T`MvY!cLr$c_@E)WgF7<{cGZD9NDe%^7g@!V~{>OhNwQJk5BqgaRiW}$osqYX+9 z#!8p$_hdCV=-f4M&@S0)zufz{gQ@UY2c0#X_C21v9jsgB9n8|w?Wdo+g=9Z7$WDj+ zBeozKhB5fsoJ+y>+dd9)uykJsvETQKgZ<o1_S?0Y91Jr`!2aJ=_sc=MRo+4K)Is}Y z?K%#oYqmRRUz}>+b)dz;;_G1tGZsnv>E6eY>}LVl>5zX?4Mf8*24Cy;0=WHl?K<}B zZb~>9{(j-$`1^(ZUVRw{W9MlO#>ZCJ@4fWNLHl{GgP!Xm`{n0uIhehybTFt;x9?5e z;b2*D&B1!<6Z={7_aoU4idP1Q{5j8Hc7tdPzINzTu>Fo=9S&9xJ?z)=g*lk~{o-KH zWoN(R>tP4uZEg+*Uys=DthnZ&FSWoyt3Sqmamik=pLO?2*>^q@aIn>vb}-NBv7a%y z6v=*28f0+D7uW`}7ltwT+6O`IV{@>tdFNp5Jk5U1+er>4Zznl82qfF@{k+}5a95mz zajU%j{unKA`qRm3uwTPr<Y4q?nuC53lYQ^ROb5$d@nHLBD_umgpB-eUL%v@ah=ySd zzK+-&u>T#B{2Z)g*4l4SI0{Nj4)#(D><=g$b1-<C07{Sc`{!<Q(0b_MpjURve&z2M z4kn*D9CSZ#x9{C6<zUUk3yKf>Ia&2c_H%&jbjbTY0Yt+v24DMlDA;~G*F_F?C$`$J ziZgRC@!aj;xGT<npQ(d`sePS;aY~f^zOqvex|{SIbk3Z$U-i(#!DM5-gF&vfeYf~i z2Xihv2OAC}`<W4fNcMAr>~zRC^99i`jKSBw7zwr?6#kYO#r7+<SUH&7HE^)o5oEt3 z@Qs7<^IQjmq7C4(K>OGV2hEwY>{r<qI+#dIanO7wVBdXgg@eTwD+g2iTKnl-c1ZSf zf$Vh1>+u88FpR<1{+11~Uz-V>hC$_zN!23<`*XMK_nbNFU_7<S!7!s3oECJtT^zKJ zt*~EFw86pjMuvl~{{#D8zAy*NnX?=$4At#t&YXp0KR3uuhul|dK{O0w@O2VE`Gn2E zmM_e~dTNvXTK@+QhH9@IY#)c%@0!2g!SK{U2ZN`H_WQzE9JIe*aL{yL2abP`{n{6& S*!TRXbFdWa0O$W%4?O^_<c5|2 literal 0 HcmV?d00001 diff --git a/test/test_pycgtool.py b/test/test_pycgtool.py index 2b1edd2..eb1bf0d 100644 --- a/test/test_pycgtool.py +++ b/test/test_pycgtool.py @@ -2,12 +2,57 @@ import unittest import subprocess import os +import numpy as np + +from simpletraj.trajectory import XtcTrajectory + +from pycgtool.interface import Options +from pycgtool.pycgtool import main, map_only + + +class Args: + def __init__(self, name, map=True, bnd=True): + self.gro = os.path.join("test/data", name+".gro") + self.xtc = os.path.join("test/data", name+".xtc") + self.map = os.path.join("test/data", name+".map") if map else None + self.bnd = os.path.join("test/data", name+".bnd") if bnd else None + self.begin = 0 + self.end = -1 + self.quiet = True + class PycgtoolTest(unittest.TestCase): + config = Options([("output_name", "out"), + ("output", "gro"), + ("output_xtc", True), + ("map_only", False), + ("map_center", "geom"), + ("constr_threshold", 100000), + ("dump_measurements", False), + ("dump_n_values", 100000), + ("output_forcefield", False), + ("temperature", 310), + ("angle_default_fc", True), + ("generate_angles", True), + ("generate_dihedrals", False)]) + def test_run(self): path = os.path.dirname(os.path.dirname(__file__)) self.assertEqual(0, subprocess.check_call([os.path.join(path, "pycgtool.py"), "-h"], stdout=subprocess.PIPE)) + def test_map_only(self): + map_only(Args("sugar"), self.config) + + xtc = XtcTrajectory("out.xtc") + xtc_ref = XtcTrajectory("test/data/sugar_out.xtc") + self.assertEqual(xtc_ref.numframes, xtc.numframes) + + for i in range(xtc_ref.numframes): + xtc.get_frame(i) + xtc_ref.get_frame(i) + np.testing.assert_array_almost_equal(xtc_ref.box, xtc.box, decimal=3) + np.testing.assert_array_almost_equal(xtc_ref.x, xtc.x, decimal=3) + # TODO more tests -- GitLab