示例#1
0
def _prepare_atoms(topology, compute_cycles=False):
    """Compute cycles and add white-/blacklists to atoms."""
    atom1 = next(topology.atoms())
    has_whitelists = hasattr(atom1, 'whitelist')
    has_cycles = hasattr(atom1, 'cycles')
    compute_cycles = compute_cycles and not has_cycles

    if compute_cycles or not has_whitelists:
        for atom in topology.atoms():
            if compute_cycles:
                atom.cycles = set()
            if not has_whitelists:
                atom.whitelist = OrderedSet()
                atom.blacklist = OrderedSet()

    if compute_cycles:
        bond_graph = nx.Graph()
        bond_graph.add_nodes_from(topology.atoms())
        bond_graph.add_edges_from(topology.bonds())
        cycles = nx.cycle_basis(bond_graph)
        for cycle in cycles:
            # NOTE: Only considering cycles containing less than 8 atoms
            if len(cycle) > 8:
                continue
            for atom in cycle:
                atom.cycles.add(tuple(cycle))
示例#2
0
def find_atomtypes(atoms, forcefield, debug=False):
    """Determine atomtypes for all atoms.

    This function is fairly general in that it can function on any list of atom
    objects as long as they have a property `neighbors`, which is a list of
    other atoms that they are bonded to as well as the attributes `whitelist`
    and `blacklist` which are sets - if they are ordered sets it simplifies
    debugging a little bit.

    Parameters
    ----------
    atoms : list of Atom objects
        The atoms whose atomtypes you are looking for.
    forcefield : simtk.openmm.app.Forcefield object
        The forcefield object.
    debug : bool, default=True
        Provides debug information about the logical consistency of the
        atomtyping rules.

    See also
    --------
    _sanitize

    """

    for atom in atoms:
        atom.whitelist = OrderedSet()
        atom.blacklist = OrderedSet()

    _load_rules(forcefield)
    # if debug:
    #     _sanitize()
    _iterate_rules(atoms, max_iter=10)
    _resolve_atomtypes(atoms)
示例#3
0
def write_gmx_topology(system, filename, header=""):
    """ Write out gmx topology file 

    Parameters
    ----------
    system : mb.Compound()
    filename : str
    header : str, optional
        Header string for include statements etc

    Notes
    -----
    Molecule names are based on the one-level-up parents of the particles
        """
    molecules = OrderedSet()
    for p in system.particles():
        if p.parent is not None:
            molecules.add(p.parent)

    with open(filename, 'w') as f:
        f.write("{}\n\n".format(header))
        f.write("[ system ]\n")
        f.write("mBuild Bilayer System\n\n")
        f.write("[ molecules ]\n")
        f.write("\n".join([
            "{:<8s} {}".format(name, sum(1 for _ in g))
            for name, g in groupby([c.name for c in molecules])
        ]))
示例#4
0
def abbreviate_names_uniquely(names):
    """Given a list of strings, return a list of strings with abbreviations
    for each that are unique among the strings given. Strings occuring
    later in the iterable will have longer names if there are conflicts
    with shorter abbreviations. If an unordered iterable is passed, the
    abbreviations assigned may be different each time. So this is really
    only meant to be used with ordered iterables.

    Args:
        names (iterable of str): Iterable of names to abbreviate.
    Return:
        abbrevs (dict): Mapping from names given to their abbreviations.

    """
    abbrevs = {}
    unique = OrderedSet()
    for name in names:
        words = name.split('_')
        n_words = len(words)
        abbrev = abbreviate_name_upton(name, n_words)

        # Sometimest last character is a parameter distinguisher, such as in
        # theta0, theta1, theta2, or as in lambda_B, lambda_W. The second case
        # falls under the typical use case, so should be accounted for to avoid
        # repeated last characters. The first case is atypical; without an
        # underscore preceding it, the last character is normally be discarded.
        last_char = name[-1]
        last_char_important = last_char.isupper() or last_char.isdigit()
        last_char_not_last_word = len(words[-1]) > 1
        add_last_char = last_char_important and last_char_not_last_word

        if add_last_char:
            abbrev += last_char

        while abbrev in unique:
            n_words += 1
            abbrev = abbreviate_name_upton(name, n_words)
            if add_last_char:
                abbrev += last_char

        unique.add(abbrev)
        abbrevs[name] = abbrev

    return abbrevs
示例#5
0
    def from_mbuild(cls, compound):
        """
        Instantiates a CG_Compound and follows mb.Compound.deep_copy
        to copy particles and bonds to CG_Compound

        Parameters
        ----------
        compound : mb.Compound to be compied

        Returns
        -------
        CG_Compound
        """

        comp = cls()

        clone_dict = {}
        comp.name = deepcopy(compound.name)
        comp.periodicity = deepcopy(compound.periodicity)
        comp._pos = deepcopy(compound._pos)
        comp.port_particle = deepcopy(compound.port_particle)
        comp._check_if_contains_rigid_bodies = deepcopy(
            compound._check_if_contains_rigid_bodies
        )
        comp._contains_rigid = deepcopy(compound._contains_rigid)
        comp._rigid_id = deepcopy(compound._rigid_id)
        comp._charge = deepcopy(compound._charge)

        if compound.children is None:
            comp.children = None
        else:
            comp.children = OrderedSet()
        # Parent should be None initially.
        comp.parent = None
        comp.labels = OrderedDict()
        comp.referrers = set()
        comp.bond_graph = None
        for p in compound.particles():
            new_particle = mb.Particle(name=p.name, pos=p.xyz.flatten())
            comp.add(new_particle)
            clone_dict[p] = new_particle

        for c1, c2 in compound.bonds():
            try:
                comp.add_bond((clone_dict[c1], clone_dict[c2]))
            except KeyError:
                raise MBuildError(
                    "Cloning failed. Compound contains bonds to "
                    "Particles outside of its containment hierarchy."
                )
        return comp
示例#6
0
def _prepare_atoms(topology, compute_cycles=False):
    """Compute cycles and add white-/blacklists to atoms."""
    atom1 = next(topology.atoms())
    has_whitelists = hasattr(atom1, 'whitelist')
    has_cycles = hasattr(atom1, 'cycles')
    compute_cycles = compute_cycles and not has_cycles

    if compute_cycles or not has_whitelists:
        for atom in topology.atoms():
            if compute_cycles:
                atom.cycles = set()
            if not has_whitelists:
                atom.whitelist = OrderedSet()
                atom.blacklist = OrderedSet()

    if compute_cycles:
        bond_graph = nx.Graph()
        bond_graph.add_nodes_from(topology.atoms())
        bond_graph.add_edges_from(topology.bonds())
        all_cycles = _find_chordless_cycles(bond_graph, max_cycle_size=8)
        for atom, cycles in zip(bond_graph.nodes, all_cycles):
            for cycle in cycles:
                atom.cycles.add(tuple(cycle))
示例#7
0
    def __init__(self,
                 subcompounds=None,
                 name=None,
                 pos=None,
                 charge=0.0,
                 periodicity=None,
                 port_particle=False):
        super(Compound, self).__init__()

        if name:
            if not isinstance(name, string_types):
                raise ValueError(
                    'Compound.name should be a string. You passed '
                    '{}'.format(name))
            self.name = name
        else:
            self.name = self.__class__.__name__

        # A periodocity of zero in any direction is treated as non-periodic.
        if periodicity is None:
            self._periodicity = np.array([0.0, 0.0, 0.0])
        else:
            self._periodicity = np.asarray(periodicity)

        if pos is not None:
            self._pos = np.asarray(pos, dtype=float)
        else:
            self._pos = np.zeros(3)

        self.charge = charge

        self.parent = None
        self.children = OrderedSet()
        self.labels = OrderedDict()
        self.referrers = set()

        self.bond_graph = None
        self.port_particle = port_particle

        # self.add() must be called after labels and children are initialized.
        if subcompounds:
            self.add(subcompounds)
示例#8
0
 def matches(self, atom):
     return self._matches(atom,
                          atom_pattern=self.start_atom_pattern(),
                          visited_atoms=OrderedSet(),
                          labeled_atoms=dict())
示例#9
0
文件: common.py 项目: timwee/cozy
def unique(iter):
    """
    Yields a stream of deduplicated elements.
    Elements are returned in the same order as the input iterator.
    """
    yield from OrderedSet(iter)
示例#10
0
def write_forcefield(structure, filename, ref_distance=1.0, ref_energy=1.0):
    """Output force field information in JSON format.

    Parameters
    ----------
    structure : parmed.GromacsTopologyFile
        Parmed structure object
    filename : str
        Path of the output file.
    ref_distance : float, default=1.0
        Reference distance for conversion to reduced units
    ref_energy : float, default=1.0
        Reference energy for conversion to reduced units
    """

    params = pmd.ParameterSet.from_structure(structure)
    ff_data = OrderedDict()

    styles = OrderedDict()

    with open(filename, 'w') as f:

        # Pair
        charges = np.any([atom.charge for atom in structure.atoms])
        if charges:
            styles['pair'] = 'lj/coul'
        else:
            styles['pair'] = 'lj'

        pair_data = dict()
        for key in params.atom_types.items():
            temp_dict = OrderedDict()
            temp_dict['element'] = {
                enum: ename
                for ename, enum in AtomicNum.items()
            }[key[1].atomic_number]
            temp_dict['epsilon'] = round(key[1].epsilon, 3) / ref_energy
            temp_dict['sigma'] = round(key[1].sigma, 3) / ref_distance
            pair_data[key[0]] = temp_dict
        pair_data = OrderedDict(
            sorted(pair_data.items(), key=lambda p: int(p[0].split('_')[1])))

        # Bonds
        bonds = [bond for bond in structure.bonds]
        if bonds:
            styles['bond'] = 'harmonic'
            unique_bond_types = dict(
                enumerate(
                    OrderedSet([(round(bond.type.k,
                                       3), round(bond.type.req, 3))
                                for bond in structure.bonds])))
            bond_data = OrderedDict()
            for idx, key in unique_bond_types.items():
                temp_dict = OrderedDict()
                temp_dict['k'] = round(key[0] * 2, 3) * (
                    (ref_distance**2) / ref_energy)
                temp_dict['r0'] = round(key[1], 3) / ref_distance
                bond_data[str(idx)] = temp_dict

        # Angles
        angles = [angle for angle in structure.angles]
        if angles:
            styles['angle'] = 'harmonic'
            unique_angle_types = dict(
                enumerate(
                    OrderedSet([(round(angle.type.k,
                                       3), round(angle.type.theteq, 3))
                                for angle in structure.angles])))
            angle_data = OrderedDict()
            for idx, key in unique_angle_types.items():
                temp_dict = OrderedDict()
                temp_dict['k'] = round(key[0] * 2, 3) / ref_energy
                temp_dict['t0'] = round(key[1], 3) * (np.pi / 180)
                angle_data[str(idx)] = temp_dict

        # Dihedrals
        dihedrals = [dihedral for dihedral in structure.rb_torsions]
        if dihedrals:
            styles['dihedral'] = 'opls'

            unique_dihedral_types = dict(
                enumerate(
                    OrderedSet([(round(dihedral.type.c0,
                                       3), round(dihedral.type.c1, 3),
                                 round(dihedral.type.c2,
                                       3), round(dihedral.type.c3, 3),
                                 round(dihedral.type.c4,
                                       3), round(dihedral.type.c5, 3),
                                 round(dihedral.type.scee,
                                       1), round(dihedral.type.scnb, 1))
                                for dihedral in structure.rb_torsions])))
            dihedrals_opls = [
                RB_to_OPLS(y[0], y[1], y[2], y[3], y[4], y[5])
                for x, y in unique_dihedral_types.items()
            ]
            dihedral_data = OrderedDict()
            for idx, key in enumerate(dihedrals_opls):
                temp_dict = OrderedDict()
                temp_dict['k1'] = round(key[0], 3) / ref_energy
                temp_dict['k2'] = round(key[1], 3) / ref_energy
                temp_dict['k3'] = round(key[2], 3) / ref_energy
                temp_dict['k4'] = round(key[3], 3) / ref_energy
                dihedral_data[str(idx)] = temp_dict

        ff_data['styles'] = styles
        ff_data['pair_coeffs'] = pair_data
        if bonds:
            ff_data['bond_coeffs'] = bond_data
        if angles:
            ff_data['angle_coeffs'] = angle_data
        if dihedrals:
            ff_data['dihedral_coeffs'] = dihedral_data

        json.dump(ff_data, f, indent=4)
示例#11
0
 def _init(self, maxsize):
     self.queue = OrderedSet()
示例#12
0
    def _clone(self, clone_of=None, root_container=None):
        """A faster alternative to deepcopying.

        Does not resolve circular dependencies. This should be safe provided
        you never try to add the top of a Compound hierarchy to a
        sub-Compound. Clones compound hierarchy only, not the bonds.
        """
        if root_container is None:
            root_container = self
        if clone_of is None:
            clone_of = dict()

        # If this compound has already been cloned, return that.
        if self in clone_of:
            return clone_of[self]

        # Otherwise we make a new clone.
        cls = self.__class__
        newone = cls.__new__(cls)

        # Remember that we're cloning the new one of self.
        clone_of[self] = newone

        newone.name = deepcopy(self.name)
        newone.wrapped = clone(self.wrapped)

        if hasattr(self, 'index'):
            newone.index = deepcopy(self.index)

        if self.children is None:
            newone.children = None
        else:
            newone.children = OrderedSet()
        # Parent should be None initially.
        newone.parent = None
        newone.labels = OrderedDict()
        newone.referrers = set()
        newone.bond_graph = None

        # Add children to clone.
        if self.children:
            for child in self.children:
                newchild = child._clone(clone_of, root_container)
                newone.children.add(newchild)
                newchild.parent = newone

        # Copy labels, except bonds with atoms outside the hierarchy.
        if self.labels:
            for label, compound in self.labels.items():
                if not isinstance(compound, list):
                    newone.labels[label] = compound._clone(
                        clone_of, root_container)
                    compound.referrers.add(clone_of[compound])
                else:
                    # compound is a list of compounds, so we create an empty
                    # list, and add the clones of the original list elements.
                    newone.labels[label] = []
                    for subpart in compound:
                        newone.labels[label].append(
                            subpart._clone(clone_of, root_container))
                        # Referrers must have been handled already, or the will
                        # be handled

        return newone
示例#13
0
    def add(self,
            new_child,
            label=None,
            containment=True,
            replace=False,
            inherit_periodicity=True):
        """Add a part to the Compound.

        Note:
            This does not necessarily add the part to self.children but may
            instead be used to add a reference to the part to self.labels. See
            'containment' argument.

        Parameters
        ----------
        new_child : mb.Compound or list-like of mb.Compound
            The object(s) to be added to this Compound.
        label : str, optional
            A descriptive string for the part.
        containment : bool, optional, default=True
            Add the part to self.children.
        replace : bool, optional, default=True
            Replace the label if it already exists.

        """
        # Support batch add via lists, tuples and sets.
        if (isinstance(new_child, collections.Iterable)
                and not isinstance(new_child, string_types)):
            for child in new_child:
                self.add(child)
            return

        if not isinstance(new_child, Compound):
            raise ValueError('Only objects that inherit from mbuild.Compound '
                             'can be added to Compounds. You tried to add '
                             '"{}".'.format(new_child))

        # Create children and labels on the first add operation
        if self.children is None:
            self.children = OrderedSet()
        if self.labels is None:
            self.labels = OrderedDict()

        if containment:
            if new_child.parent is not None:
                raise MBuildError('Part {} already has a parent: {}'.format(
                    new_child, new_child.parent))
            self.children.add(new_child)
            new_child.parent = self

            if new_child.bond_graph is not None:
                if self.root.bond_graph is None:
                    self.root.bond_graph = new_child.bond_graph
                else:
                    self.root.bond_graph.compose(new_child.bond_graph)

                new_child.bond_graph = None

        # Add new_part to labels. Does not currently support batch add.
        if label is None:
            label = '{0}[$]'.format(new_child.__class__.__name__)

        if label.endswith('[$]'):
            label = label[:-3]
            if label not in self.labels:
                self.labels[label] = []
            label_pattern = label + '[{}]'

            count = len(self.labels[label])
            self.labels[label].append(new_child)
            label = label_pattern.format(count)

        if not replace and label in self.labels:
            raise MBuildError('Label "{0}" already exists in {1}.'.format(
                label, self))
        else:
            self.labels[label] = new_child
        new_child.referrers.add(self)

        if (inherit_periodicity and isinstance(new_child, Compound)
                and new_child.periodicity.any()):
            self.periodicity = new_child.periodicity
示例#14
0
def write_gsd(structure,
              filename,
              forcefield,
              box,
              ref_distance=1.0,
              ref_mass=1.0,
              ref_energy=1.0,
              write_ff=True):
    """Output a GSD file (HOOMD default data format).
    
    Parameters
    ----------
    structure : parmed.GromacsTopologyFile
        Parmed structure object
    filename : str
        Path of the output file.
    forcefield : str, default=None
        Name of the force field to be applied to the compound
    box : mb.Box
        Box information to save to XML file
    ref_distance : float, default=1.0
        Reference distance for conversion to reduced units
    ref_mass : float, default=1.0
        Reference mass for conversion to reduced units
    ref_energy : float, default=1.0
        Reference energy for conversion to reduced units
    write_ff : boolean, default=True
        Write forcefield parameters to a JSON file, 'parameters.json'
    """

    import_('gsd')
    import gsd.hoomd

    xyz = np.array([[atom.xx, atom.xy, atom.xz] for atom in structure.atoms])

    # Center box at origin and remap coordinates into box
    box.lengths *= 10.0
    box.maxs *= 10.0
    box.mins *= 10.0
    box_init = deepcopy(box)
    box.mins = np.array([-d / 2 for d in box_init.lengths])
    box.maxs = np.array([d / 2 for d in box_init.lengths])

    shift = [box_init.maxs[i] - max for i, max in enumerate(box.maxs)]
    for i, pos in enumerate(xyz):
        for j, coord in enumerate(pos):
            xyz[i, j] -= shift[j]
            rep = floor((xyz[i, j] - box.mins[j]) / box.lengths[j])
            xyz[i, j] -= (rep * box.lengths[j])

    gsd_file = gsd.hoomd.Snapshot()

    gsd_file.configuration.step = 0
    gsd_file.configuration.dimensions = 3
    gsd_file.configuration.box = np.hstack(
        (box.lengths / ref_distance, np.zeros(3)))

    gsd_file.particles.N = len(structure.atoms)
    gsd_file.particles.position = xyz / ref_distance

    if forcefield:
        types = [atom.type for atom in structure.atoms]
    else:
        types = [atom.name for atom in structure.atoms]

    unique_types = list(set(types))
    unique_types.sort(key=_natural_sort)

    typeids = np.array([unique_types.index(t) for t in types])

    gsd_file.particles.types = unique_types
    gsd_file.particles.typeid = typeids

    masses = np.array([atom.mass for atom in structure.atoms])
    masses[masses == 0] = 1.0
    gsd_file.particles.mass = masses / ref_mass

    charges = np.array([atom.charge for atom in structure.atoms])
    e0 = 2.39725e-4
    '''
    Permittivity of free space = 2.39725e-4 e^2/((kcal/mol)(angstrom)),
    where e is the elementary charge
    '''
    charge_factor = (4.0 * np.pi * e0 * ref_distance * ref_energy)**0.5
    gsd_file.particles.charge = charges / charge_factor

    bonds = [[bond.atom1.idx, bond.atom2.idx] for bond in structure.bonds]
    if bonds:
        bonds = np.asarray(bonds)
        gsd_file.bonds.N = len(bonds)
        if len(structure.bond_types) == 0:
            bond_types = np.zeros(len(bonds), dtype=int)
            gsd_file.bonds.types = ['0']
        else:
            unique_bond_types = dict(
                enumerate(
                    OrderedSet([(round(bond.type.k,
                                       3), round(bond.type.req, 3))
                                for bond in structure.bonds])))
            unique_bond_types = OrderedDict([
                (y, x) for x, y in unique_bond_types.items()
            ])
            bond_types = [
                unique_bond_types[(round(bond.type.k,
                                         3), round(bond.type.req, 3))]
                for bond in structure.bonds
            ]
            gsd_file.bonds.types = [
                str(y) for x, y in unique_bond_types.items()
            ]
        gsd_file.bonds.typeid = bond_types
        gsd_file.bonds.group = bonds

    angles = [[angle.atom1.idx, angle.atom2.idx, angle.atom3.idx]
              for angle in structure.angles]
    if angles:
        angles = np.asarray(angles)
        gsd_file.angles.N = len(angles)
        unique_angle_types = dict(
            enumerate(
                OrderedSet([(round(angle.type.k,
                                   3), round(angle.type.theteq, 3))
                            for angle in structure.angles])))
        unique_angle_types = OrderedDict([
            (y, x) for x, y in unique_angle_types.items()
        ])
        angle_types = [
            unique_angle_types[(round(angle.type.k,
                                      3), round(angle.type.theteq, 3))]
            for angle in structure.angles
        ]
        gsd_file.angles.types = [str(y) for x, y in unique_angle_types.items()]
        gsd_file.angles.typeid = angle_types
        gsd_file.angles.group = angles

    dihedrals = [[
        dihedral.atom1.idx, dihedral.atom2.idx, dihedral.atom3.idx,
        dihedral.atom4.idx
    ] for dihedral in structure.rb_torsions]
    if dihedrals:
        dihedrals = np.asarray(dihedrals)
        gsd_file.dihedrals.N = len(dihedrals)

        unique_dihedral_types = dict(
            enumerate(
                OrderedSet([(round(dihedral.type.c0,
                                   3), round(dihedral.type.c1,
                                             3), round(dihedral.type.c2, 3),
                             round(dihedral.type.c3,
                                   3), round(dihedral.type.c4,
                                             3), round(dihedral.type.c5, 3),
                             round(dihedral.type.scee,
                                   1), round(dihedral.type.scnb, 1))
                            for dihedral in structure.rb_torsions])))
        unique_dihedral_types = OrderedDict([
            (y, x) for x, y in unique_dihedral_types.items()
        ])
        dihedral_types = [
            unique_dihedral_types[(round(dihedral.type.c0,
                                         3), round(dihedral.type.c1, 3),
                                   round(dihedral.type.c2,
                                         3), round(dihedral.type.c3, 3),
                                   round(dihedral.type.c4,
                                         3), round(dihedral.type.c5, 3),
                                   round(dihedral.type.scee,
                                         1), round(dihedral.type.scnb, 1))]
            for dihedral in structure.rb_torsions
        ]
        gsd_file.dihedrals.types = [
            str(y) for x, y in unique_dihedral_types.items()
        ]
        gsd_file.dihedrals.typeid = dihedral_types
        gsd_file.dihedrals.group = dihedrals

    gsd.hoomd.create(filename, gsd_file)

    if write_ff:
        write_forcefield(structure,
                         'ff.json',
                         ref_distance=ref_distance,
                         ref_energy=ref_energy)