From 5b04798ecf6faa8ba91df6ca607884cbbdc3e816 Mon Sep 17 00:00:00 2001 From: James Graham <J.A.Graham@soton.ac.uk> Date: Fri, 16 Dec 2016 15:33:09 +0000 Subject: [PATCH] CFG parser use OrderedDict Small amounts of tidying elsewhere --- data/atom_masses.json | 7 ++++--- doc/source/tutorial.rst | 2 +- pycgtool/frame.py | 2 +- pycgtool/mapping.py | 14 +++++++++----- pycgtool/parsers/cfg.py | 25 ++++++++----------------- 5 files changed, 23 insertions(+), 27 deletions(-) diff --git a/data/atom_masses.json b/data/atom_masses.json index e344c37..cea07cf 100644 --- a/data/atom_masses.json +++ b/data/atom_masses.json @@ -1,7 +1,8 @@ { + "H": 1.0080, "C": 12.0110, - "O": 15.9994, "N": 14.0067, - "H": 1.0080, - "P": 30.9738 + "O": 15.9994, + "P": 30.9738, + "S": 32.0600 } diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst index c7f83e1..af620ff 100644 --- a/doc/source/tutorial.rst +++ b/doc/source/tutorial.rst @@ -2,7 +2,7 @@ PyCGTOOL Tutorial ================= This tutorial follows the complete process of parametrising a new molecule within the MARTINI forcefield, covering aspects of mapping design, model generation and model validation. -PyCGTOOL is used at multiple stages, showing its use in several different situations +PyCGTOOL is used at multiple stages, showing its use in several different situations. All files required to follow this tutorial are present in the ``doc/tutorial_files`` directory. The molecule chosen as a target for this parametrisation is the :math:`\beta_1` antagonist atenolol. diff --git a/pycgtool/frame.py b/pycgtool/frame.py index 3a6191b..b7a959b 100644 --- a/pycgtool/frame.py +++ b/pycgtool/frame.py @@ -358,7 +358,7 @@ class Frame: atoms = [] for res in self.residues: for atom in res: - atoms.append(repr(atom.coords)) + atoms.append(repr(atom)) rep += "\n".join(atoms) return rep diff --git a/pycgtool/mapping.py b/pycgtool/mapping.py index 0a6794e..64abd39 100644 --- a/pycgtool/mapping.py +++ b/pycgtool/mapping.py @@ -84,7 +84,6 @@ class Mapping: :return: Instance of Mapping """ self._mappings = {} - self._map_center = options.map_center self._masses_are_set = False @@ -127,6 +126,8 @@ class Mapping: else: bead.charge += atoms[atom][0] + self._masses_are_set = True + def __len__(self): return len(self._mappings) @@ -153,7 +154,6 @@ class Mapping: if bead.mass == 0: mass_array = np.zeros((len(bead.atoms), 1), dtype=np.float32) for i, atom in enumerate(bead.atoms): - mass = 0 try: mass = mass_dict[atom[:2]] except KeyError: @@ -185,6 +185,7 @@ class Mapping: cgframe.name = name missing_mappings = set() + cg_bead_num = 1 for aares in aa_residues: try: @@ -196,12 +197,15 @@ class Mapping: continue cgres = Residue(name=aares.name, num=aares.num) - cgres.atoms = [Atom(name=bead.name, type=bead.type, charge=bead.charge, mass=bead.mass) for bead in molmap] + cgres.atoms = [Atom(name=bmap.name, type=bmap.type, charge=bmap.charge, mass=bmap.mass, coords=np.zeros(3)) for bmap in molmap] for i, (bead, bmap) in enumerate(zip(cgres, molmap)): cgres.name_to_num[bead.name] = i bead.charge = bmap.charge bead.mass = bmap.mass + bead.num = cg_bead_num + + cg_bead_num += 1 cgframe.add_residue(cgres) cgframe.natoms += len(cgres) @@ -229,7 +233,7 @@ class Mapping: cgframe.box = frame.box select_predicate = lambda res: res.name in self._mappings and not (exclude is not None and res.name in exclude) - aa_residues = (aares for aares in frame if select_predicate(aares)) + aa_residues = filter(select_predicate, frame) for aares, cgres in zip(aa_residues, cgframe): molmap = self._mappings[aares.name] @@ -249,7 +253,7 @@ class Mapping: return cgframe -@numba.jit(nopython=True) +@numba.jit def calc_coords_weight(ref_coords, coords, box, weights): """ Calculate the coordinates of a single CG bead from weighted component atom coordinates. diff --git a/pycgtool/parsers/cfg.py b/pycgtool/parsers/cfg.py index 9e4d452..87695b3 100644 --- a/pycgtool/parsers/cfg.py +++ b/pycgtool/parsers/cfg.py @@ -5,6 +5,8 @@ Format is based upon GROMACS .itp files but does not support nesting of sections """ import os +from collections import OrderedDict + class Section: """ @@ -48,7 +50,7 @@ class CFG: Contains a dictionary of Sections. """ - __slots__ = ["filename", "_sections", "_section_names", "_iter_section"] + __slots__ = ["filename", "_sections"] def __init__(self, filename=None, allow_duplicate=False): """ @@ -59,13 +61,12 @@ class CFG: :return: Instance of CFG """ self.filename = filename - self._sections = {} - self._section_names = [] + self._sections = OrderedDict() with open(self.filename) as f: curr_section = None for line in f: - line = line.strip(" \t\n") + line = line.strip() if not line or line.startswith(";"): continue @@ -73,14 +74,12 @@ class CFG: cfg2 = CFG(os.path.join(os.path.dirname(self.filename), line.split()[1])) self._sections.update(cfg2._sections) - self._section_names += cfg2._section_names continue elif line.startswith("["): curr_section = line.strip("[ ]") if curr_section in self._sections and not allow_duplicate: raise DuplicateSectionError(curr_section, self.filename) - self._section_names.append(curr_section) self._sections[curr_section] = Section(name=curr_section) continue @@ -94,21 +93,13 @@ class CFG: pass def __len__(self): - return len(self._section_names) + return len(self._sections) def __iter__(self): - self._iter_section = -1 - return self - - def __next__(self): - self._iter_section += 1 - if self._iter_section >= len(self._section_names): - raise StopIteration - sec = self._section_names[self._iter_section] - return self._sections[sec] + return iter(self._sections.values()) def __contains__(self, item): - return item in self._section_names + return item in self._sections def __getitem__(self, item): return self._sections[item] -- GitLab