Пример #1
0
 def test_two_particle_vsite(self):
     """ Tests assignment of 2-particle virtual site """
     struct = pmd.Structure()
     struct.add_atom(pmd.Atom(name='C', atomic_number=6), 'RES', 1)
     struct.add_atom(pmd.Atom(name='C', atomic_number=6), 'RES', 1)
     struct.add_atom(pmd.ExtraPoint(name='EP', atomic_number=0), 'RES', 1)
     struct.bond_types.append(pmd.BondType(10, 1.0))
     struct.bond_types.append(pmd.BondType(10, 0.5))
     struct.bond_types.claim()
     struct.bonds.append(pmd.Bond(struct[0], struct[1],
                                  type=struct.bond_types[0])
     )
     struct.bonds.append(pmd.Bond(struct[1], struct[2],
                                  type=struct.bond_types[1])
     )
     # This should be a two-particle virtual site
     struct.coordinates = [[0, 0, 0], [0, 0, 1], [0, 0, 1.5]]
     system = mm.System()
     system.addParticle(struct[0].mass)
     system.addParticle(struct[1].mass)
     system.addParticle(struct[2].mass)
     struct.omm_set_virtual_sites(system)
     # Make sure the third atom is a virtual site
     self.assertTrue(system.isVirtualSite(2))
     self.assertIsInstance(system.getVirtualSite(2), mm.TwoParticleAverageSite)
Пример #2
0
    def test_urey_bradley_type(self):
        """ Tests handling getting urey-bradley types from Structure """
        warnings.filterwarnings('error',
                                category=pmd.exceptions.ParameterWarning)
        struct = pmd.Structure()
        struct.add_atom(pmd.Atom('CA', type='CX'), 'ALA', 1)
        struct.add_atom(pmd.Atom('CB', type='CY'), 'ALA', 1)
        struct.add_atom(pmd.Atom('CC', type='CZ'), 'ALA', 1)
        struct.add_atom(pmd.Atom('CD', type='CX'), 'GLY', 2)
        struct.add_atom(pmd.Atom('CE', type='CY'), 'GLY', 2)
        struct.add_atom(pmd.Atom('CF', type='CZ'), 'GLY', 2)
        struct.bond_types.append(pmd.BondType(100.0, 1.0))
        struct.bond_types.claim()
        struct.bonds.extend([
            pmd.Bond(struct[0], struct[1], type=struct.bond_types[0]),
            pmd.Bond(struct[1], struct[2], type=struct.bond_types[0]),
            pmd.Bond(struct[3], struct[4], type=struct.bond_types[0]),
            pmd.Bond(struct[4], struct[5], type=struct.bond_types[0]),
        ])
        struct.angle_types.append(pmd.AngleType(10.0, 120.0))
        struct.angle_types.append(pmd.AngleType(11.0, 109.0))
        struct.angle_types.claim()
        struct.angles.append(
            pmd.Angle(struct[0],
                      struct[1],
                      struct[2],
                      type=struct.angle_types[0]))
        struct.angles.append(
            pmd.Angle(struct[3],
                      struct[4],
                      struct[5],
                      type=struct.angle_types[0]))
        struct.urey_bradley_types.append(pmd.BondType(150.0, 2.0))
        struct.urey_bradley_types.claim()
        struct.urey_bradleys.extend([
            pmd.UreyBradley(struct[0],
                            struct[2],
                            type=struct.urey_bradley_types[0]),
            pmd.UreyBradley(struct[3],
                            struct[5],
                            type=struct.urey_bradley_types[0]),
        ])

        params = pmd.ParameterSet.from_structure(struct)
        self.assertEqual(len(params.urey_bradley_types), 2)
        for key, ubt in iteritems(params.urey_bradley_types):
            self.assertEqual(len(key), 3)
            self.assertEqual(ubt.req, 2.0)
            self.assertEqual(ubt.k, 150.0)
        warnings.filterwarnings('default',
                                category=pmd.exceptions.ParameterWarning)
Пример #3
0
 def test_duplicate_bond_type(self):
     """ Tests handling of duplicate bond type in ParameterSet """
     struct = pmd.Structure()
     struct.add_atom(pmd.Atom('CA', type='CX'), 'ALA', 1)
     struct.add_atom(pmd.Atom('CB', type='CY'), 'ALA', 1)
     struct.add_atom(pmd.Atom('CD', type='CX'), 'GLY', 2)
     struct.add_atom(pmd.Atom('CE', type='CY'), 'GLY', 2)
     struct.bond_types.append(pmd.BondType(10.0, 1.0))
     struct.bond_types.append(pmd.BondType(11.0, 1.1))
     struct.bond_types.claim()
     struct.bonds.append(pmd.Bond(struct[0], struct[1], type=struct.bond_types[0]))
     struct.bonds.append(pmd.Bond(struct[2], struct[3], type=struct.bond_types[1]))
     with self.assertRaises(pmd.exceptions.ParameterError):
         pmd.ParameterSet.from_structure(struct, allow_unequal_duplicates=False)
Пример #4
0
 def test_ep_exceptions(self):
     """ Test Nonbonded exception handling with virtual sites """
     # Analyze the exception parameters for bonding pattern
     #
     # E1 -- A1 -- A2 -- A3 -- A4 -- A5 -- E5
     #             |     |     |
     #             E2    E3    E4
     struct = pmd.Structure()
     ep1 = ExtraPoint(name='E1', type='EP', atomic_number=0, weights=[1, 2])
     ep2 = ExtraPoint(name='E2', type='EP', atomic_number=0)
     ep3 = ExtraPoint(name='E3', type='EP', atomic_number=0)
     ep4 = ExtraPoint(name='E4', type='EP', atomic_number=0)
     ep5 = ExtraPoint(name='E5', type='EP', atomic_number=0)
     self.assertIs(ep1.parent, None)
     self.assertEqual(ep1.bond_partners, [])
     self.assertEqual(ep1.angle_partners, [])
     self.assertEqual(ep1.dihedral_partners, [])
     self.assertEqual(ep1.tortor_partners, [])
     self.assertEqual(ep1.exclusion_partners, [])
     a1 = pmd.Atom(name='A1', type='AX', charge=0.1, atomic_number=6)
     a2 = pmd.Atom(name='A2', type='AY', charge=0.1, atomic_number=6)
     a3 = pmd.Atom(name='A3', type='AZ', charge=0.1, atomic_number=7)
     a4 = pmd.Atom(name='A4', type='AX', charge=0.1, atomic_number=6)
     a5 = pmd.Atom(name='A5', type='AY', charge=0.1, atomic_number=6)
     a1.rmin = a2.rmin = a3.rmin = a4.rmin = a5.rmin = 0.5
     a1.epsilon = a2.epsilon = a3.epsilon = a4.epsilon = a5.epsilon = 1.0
     bond_type = pmd.BondType(10.0, 1.0)
     bond_type2 = pmd.BondType(10.0, 2.0)
     bond_type3 = pmd.BondType(10.0, 0.5)
     bond_type4 = pmd.BondType(10.0, math.sqrt(2))
     angle_type = pmd.AngleType(10.0, 90)
     dihedral_type = pmd.DihedralType(10.0, 2, 0)
     struct.add_atom(a1, 'RES', 1)
     struct.add_atom(a2, 'RES', 1)
     struct.add_atom(a3, 'RES', 1)
     struct.add_atom(a4, 'RES', 1)
     struct.add_atom(a5, 'RES', 1)
     struct.add_atom(ep1, 'RES', 1)
     struct.add_atom(ep2, 'RES', 1)
     struct.add_atom(ep3, 'RES', 1)
     struct.add_atom(ep4, 'RES', 1)
     struct.add_atom(ep5, 'RES', 1)
     struct.bonds.extend([
         pmd.Bond(a1, ep1, type=bond_type),
         pmd.Bond(ep2, a2, type=bond_type),
         pmd.Bond(a3, ep3, type=bond_type3),
         pmd.Bond(a4, ep4, type=bond_type)
     ])
     struct.bonds.extend([
         pmd.Bond(a1, a2, type=bond_type),
         pmd.Bond(a4, a3, type=bond_type4),
         pmd.Bond(a3, a2, type=bond_type4),
         pmd.Bond(a4, a5, type=bond_type2),
         pmd.Bond(a5, ep5, type=bond_type)
     ])
     struct.angles.extend([
         pmd.Angle(a1, a2, a3, type=angle_type),
         pmd.Angle(a2, a3, a4, type=angle_type),
         pmd.Angle(a3, a4, a5, type=angle_type)
     ])
     struct.dihedrals.extend([
         pmd.Dihedral(a1, a2, a3, a4, type=dihedral_type),
         pmd.Dihedral(a2, a3, a4, a5, type=dihedral_type)
     ])
     struct.bond_types.extend(
         [bond_type, bond_type3, bond_type2, bond_type4])
     struct.angle_types.append(angle_type)
     struct.dihedral_types.append(dihedral_type)
     # Test exclusions now
     a1.exclude(a5)
     system = struct.createSystem()
Пример #5
0
def to_parmed(off_system: "System") -> pmd.Structure:
    """Convert an OpenFF System to a ParmEd Structure"""
    structure = pmd.Structure()
    _convert_box(off_system.box, structure)

    if "Electrostatics" in off_system.handlers.keys():
        has_electrostatics = True
        electrostatics_handler = off_system.handlers["Electrostatics"]
    else:
        has_electrostatics = False

    for topology_molecule in off_system.topology.topology_molecules:  # type: ignore[union-attr]
        for atom in topology_molecule.atoms:
            atomic_number = atom.atomic_number
            element = pmd.periodic_table.Element[atomic_number]
            mass = pmd.periodic_table.Mass[element]
            structure.add_atom(
                pmd.Atom(
                    atomic_number=atomic_number,
                    mass=mass,
                ),
                resname="FOO",
                resnum=0,
            )

    if "Bonds" in off_system.handlers.keys():
        bond_handler = off_system.handlers["Bonds"]
        bond_type_map: Dict = dict()
        for pot_key, pot in bond_handler.potentials.items():
            k = pot.parameters["k"].to(kcal_mol_a2).magnitude / 2
            length = pot.parameters["length"].to(unit.angstrom).magnitude
            bond_type = pmd.BondType(k=k, req=length)
            bond_type_map[pot_key] = bond_type
            structure.bond_types.append(bond_type)

        for top_key, pot_key in bond_handler.slot_map.items():
            idx_1, idx_2 = top_key.atom_indices
            bond_type = bond_type_map[pot_key]
            bond = pmd.Bond(
                atom1=structure.atoms[idx_1],
                atom2=structure.atoms[idx_2],
                type=bond_type,
            )
            structure.bonds.append(bond)

    structure.bond_types.claim()

    if "Angles" in off_system.handlers.keys():
        angle_handler = off_system.handlers["Angles"]
        angle_type_map: Dict = dict()
        for pot_key, pot in angle_handler.potentials.items():
            k = pot.parameters["k"].to(kcal_mol_rad2).magnitude / 2
            theta = pot.parameters["angle"].to(unit.degree).magnitude
            # TODO: Look up if AngleType already exists in struct
            angle_type = pmd.AngleType(k=k, theteq=theta)
            angle_type_map[pot_key] = angle_type
            structure.angle_types.append(angle_type)

        for top_key, pot_key in angle_handler.slot_map.items():
            idx_1, idx_2, idx_3 = top_key.atom_indices
            angle_type = angle_type_map[pot_key]
            structure.angles.append(
                pmd.Angle(
                    atom1=structure.atoms[idx_1],
                    atom2=structure.atoms[idx_2],
                    atom3=structure.atoms[idx_3],
                    type=angle_type,
                ))
            structure.angle_types.append(angle_type)

    structure.angle_types.claim()

    # ParmEd treats 1-4 scaling factors at the level of each DihedralType,
    # whereas SMIRNOFF captures them at the level of the non-bonded handler,
    # so they need to be stored here for processing dihedrals
    vdw_14 = off_system.handlers["vdW"].scale_14  # type: ignore[attr-defined]
    if has_electrostatics:
        coul_14 = off_system.handlers[
            "Electrostatics"].scale_14  # type: ignore[attr-defined]
    else:
        coul_14 = 1.0
    vdw_handler = off_system.handlers["vdW"]
    if "ProperTorsions" in off_system.handlers.keys():
        proper_torsion_handler = off_system.handlers["ProperTorsions"]
        proper_type_map: Dict = dict()
        for pot_key, pot in proper_torsion_handler.potentials.items():
            k = pot.parameters["k"].to(kcal_mol).magnitude
            periodicity = pot.parameters["periodicity"]
            phase = pot.parameters["phase"].magnitude
            proper_type = pmd.DihedralType(
                phi_k=k,
                per=periodicity,
                phase=phase,
                scnb=1 / vdw_14,
                scee=1 / coul_14,
            )
            proper_type_map[pot_key] = proper_type
            structure.dihedral_types.append(proper_type)

        for top_key, pot_key in proper_torsion_handler.slot_map.items():
            idx_1, idx_2, idx_3, idx_4 = top_key.atom_indices
            dihedral_type = proper_type_map[pot_key]
            structure.dihedrals.append(
                pmd.Dihedral(
                    atom1=structure.atoms[idx_1],
                    atom2=structure.atoms[idx_2],
                    atom3=structure.atoms[idx_3],
                    atom4=structure.atoms[idx_4],
                    type=dihedral_type,
                ))
            structure.dihedral_types.append(dihedral_type)

            key1 = TopologyKey(atom_indices=(idx_1, ))
            key4 = TopologyKey(atom_indices=(idx_4, ))
            vdw1 = vdw_handler.potentials[vdw_handler.slot_map[key1]]
            vdw4 = vdw_handler.potentials[vdw_handler.slot_map[key4]]
            sig1, eps1 = _lj_params_from_potential(vdw1)
            sig4, eps4 = _lj_params_from_potential(vdw4)
            sig = (sig1 + sig4) * 0.5
            eps = (eps1 * eps4)**0.5
            nbtype = pmd.NonbondedExceptionType(rmin=sig * 2**(1 / 6),
                                                epsilon=eps * vdw_14,
                                                chgscale=coul_14)
            structure.adjusts.append(
                pmd.NonbondedException(structure.atoms[idx_1],
                                       structure.atoms[idx_4],
                                       type=nbtype))
            structure.adjust_types.append(nbtype)

    structure.dihedral_types.claim()
    structure.adjust_types.claim()

    #    if False:  # "ImroperTorsions" in off_system.term_collection.terms:
    #        improper_term = off_system.term_collection.terms["ImproperTorsions"]
    #        for improper, smirks in improper_term.smirks_map.items():
    #            idx_1, idx_2, idx_3, idx_4 = improper
    #            pot = improper_term.potentials[improper_term.smirks_map[improper]]
    #            # TODO: Better way of storing periodic data in generally, probably need to improve Potential
    #            n = re.search(r"\d", "".join(pot.parameters.keys())).group()
    #            k = pot.parameters["k" + n].m  # kcal/mol
    #            periodicity = pot.parameters["periodicity" + n].m  # dimless
    #            phase = pot.parameters["phase" + n].m  # degree
    #
    #            dihedral_type = pmd.DihedralType(per=periodicity, phi_k=k, phase=phase)
    #            structure.dihedrals.append(
    #                pmd.Dihedral(
    #                    atom1=structure.atoms[idx_1],
    #                    atom2=structure.atoms[idx_2],
    #                    atom3=structure.atoms[idx_3],
    #                    atom4=structure.atoms[idx_4],
    #                    type=dihedral_type,
    #                )
    #            )

    vdw_handler = off_system.handlers["vdW"]
    for pmd_idx, pmd_atom in enumerate(structure.atoms):
        top_key = TopologyKey(atom_indices=(pmd_idx, ))
        smirks = vdw_handler.slot_map[top_key]
        potential = vdw_handler.potentials[smirks]
        element = pmd.periodic_table.Element[pmd_atom.element]
        sigma, epsilon = _lj_params_from_potential(potential)

        atom_type = pmd.AtomType(
            name=element + str(pmd_idx + 1),
            number=pmd_idx,
            atomic_number=pmd_atom.atomic_number,
            mass=pmd.periodic_table.Mass[element],
        )

        atom_type.set_lj_params(eps=epsilon, rmin=sigma * 2**(1 / 6) / 2)
        pmd_atom.atom_type = atom_type
        pmd_atom.type = atom_type.name
        pmd_atom.name = pmd_atom.type

    for pmd_idx, pmd_atom in enumerate(structure.atoms):
        if has_electrostatics:
            top_key = TopologyKey(atom_indices=(pmd_idx, ))
            partial_charge = electrostatics_handler.charges[
                top_key]  # type: ignore[attr-defined]
            unitless_ = partial_charge.to(unit.elementary_charge).magnitude
            pmd_atom.charge = float(unitless_)
            pmd_atom.atom_type.charge = float(unitless_)
        else:
            pmd_atom.charge = 0

    # Assign dummy residue names, GROMACS will not accept empty strings
    for res in structure.residues:
        res.name = "FOO"

    structure.positions = off_system.positions.to(
        unit.angstrom).magnitude  # type: ignore[attr-defined]
    for idx, pos in enumerate(structure.positions):
        structure.atoms[idx].xx = pos._value[0]
        structure.atoms[idx].xy = pos._value[1]
        structure.atoms[idx].xz = pos._value[2]

    return structure
Пример #6
0
    def merge(self):
        def dummify(atom):
            atom.atom_type.epsilon = 0
            atom.atom_type.charge = 0
            atom.atom_type.rmin = 0
            atom.atom_type.name = "du"
            atom.atom_type.atomic_number = 0
            atom.charge = 0
            atom.name = "du"
            atom.type = "du"
            return atom

        self.map = []

        N = 0
        for r, (res1, res2) in enumerate(
                zip(self.system1.residues, self.system2.residues)):
            incr = 0
            N += len(res1.atoms)

            map = {}

            for i, atom1 in enumerate(res1.atoms):
                for j, atom2 in enumerate(res2.atoms):
                    if atom1.xx == atom2.xx and atom1.xy == atom2.xy and atom1.xz == atom2.xz:
                        map[i] = j
                        break
                    if j == len(self.system2.residues[r]) - 1:
                        du = _copy.deepcopy(atom1)
                        dummify(du)
                        self.system2.add_atom(du, res2.name, res2.number)
                        map[i] = N + incr
                        incr += 1
                        break

            rev_map = lambda x: list(map.keys())[list(map.values()).index(x)]

            for j, atom2 in enumerate(res2.atoms):
                try:
                    rev_map(j)
                except ValueError:
                    # calling the property enables index update - this seemingly pointless line is needed
                    du = _copy.deepcopy(atom2)
                    dummify(du)
                    self.system1.add_atom(du, res1.name, res1.number)
                    self.system1.atoms[-1].idx
                    map[len(res1.atoms) - 1] = j

            for j, atom2 in enumerate(res2.atoms):
                # calling the property enables index update - these two seemingly pointless lines are needed
                atom2.idx
                atom2._idx = rev_map(j)
                atom2.idx

            res2.sort()

        self.system1.atoms.sort()
        self.system2.atoms.sort()

        # bonds - needed since parmed doesn't write nonbonded atoms
        bonds_1 = {
            tuple(sorted([x.atom1.idx, x.atom2.idx])): x.type
            for x in self.system1.bonds
        }
        bonds_2 = {
            tuple(sorted([x.atom1.idx, x.atom2.idx])): x.type
            for x in self.system2.bonds
        }

        common_keys = set(bonds_1.keys()).intersection(bonds_2.keys())
        unique_bonds_1 = set(bonds_1.keys()) - common_keys
        unique_bonds_2 = set(bonds_2.keys()) - common_keys

        for i, j in ((1, 2), (2, 1)):
            exec("bonds_i, bonds_j = bonds_%d, bonds_%d" % (i, j), locals(),
                 globals())
            exec("unique_bonds_i = unique_bonds_%d" % i, locals(), globals())
            exec("system_j = self.system%d" % j, locals(), globals())
            for key in unique_bonds_i:
                val = bonds_i[key]
                if val not in system_j.bond_types:
                    bond_type = _pmd.BondType(val.k, val.req,
                                              system_j.bond_types)
                    system_j.bond_types.append(bond_type)
                    bonds_j[key] = system_j.bond_types[-1]
                else:
                    bonds_j[key] = system_j.bond_types[
                        system_j.bond_types.index(val)]
            system_j.bonds = bonds_j
            system_j.bonds = _pmd.TrackedList([
                _pmd.Bond(system_j.atoms[m], system_j.atoms[n], type=t)
                for (m, n), t in sorted(bonds_j.items())
            ])
        '''
Пример #7
0
    def _add_particles(self, topol):
        err_msg = 'Unknown spin label type {{}}. Allowed values are: {}'
        err_msg = err_msg.format(', '.join(self.ALLOWED_TYPES))

        # we use the same radius and screen as for oxygen
        if not self.explicit:
            radius, screen = self._find_radius_and_screen(topol)

        # find all the unique types of spin labels
        types = set(self.params.values())

        # create the bond types
        bond_types = {}
        for t in types:
            bond_k, bond_r = self.bond_params[t]
            topol.bond_types.append(
                pmd.BondType(bond_k, bond_r, list=topol.bond_types))
            bt = topol.bond_types[-1]
            bond_types[t] = bt

        # create the angle types
        angle_types = {}
        for t in types:
            angle_k, angle_theta = self.angle_params[t]
            topol.angle_types.append(
                pmd.AngleType(angle_k, angle_theta, list=topol.angle_types))
            at = topol.angle_types[-1]
            angle_types[t] = at

        # create the torsion types
        tors_types = {}
        for t in types:
            tors_k, tors_per, tors_phase = self.tors_params[t]
            topol.dihedral_types.append(
                pmd.DihedralType(tors_k,
                                 tors_per,
                                 tors_phase,
                                 list=topol.dihedral_types))
            tt = topol.dihedral_types[-1]
            tors_types[t] = tt

        for key in self.params:
            if self.params[key] not in self.ALLOWED_TYPES:
                raise ValueError(err_msg.format(self.params[key]))

            # create the particle
            atom = pmd.Atom(None, 8, 'OND', 'OND', 0.0, 16.00)
            if not self.explicit:
                atom.radii = radius
                atom.screen = screen

            # add to system
            topol.add_atom_to_residue(atom, topol.residues[key])

            # find the other atoms
            ca = topol.view[':{},@CA'.format(key + 1)].atoms[0]
            cb = topol.view[':{},@CB'.format(key + 1)].atoms[0]
            n = topol.view[':{},@N'.format(key + 1)].atoms[0]

            # add bond
            topol.bonds.append(pmd.Bond(atom, ca,
                                        bond_types[self.params[key]]))

            # add angle
            topol.angles.append(
                pmd.Angle(cb, ca, atom, angle_types[self.params[key]]))

            # add torsion
            topol.dihedrals.append(
                pmd.Dihedral(n,
                             ca,
                             cb,
                             atom,
                             type=tors_types[self.params[key]]))

            # set position
            ca_pos = np.array((ca.xx, ca.xy, ca.xz))
            n_pos = np.array((n.xx, n.xy, n.xz))
            cb_pos = np.array((cb.xx, cb.xy, cb.xz))

            direction = np.linalg.norm(ca_pos - n_pos)
            new_pos = cb_pos - self.bond_params[
                self.params[key]][1].value_in_unit(u.angstrom) * direction

            atom.xx = new_pos[0]
            atom.xy = new_pos[1]
            atom.xz = new_pos[2]
        topol.remake_parm()

        # setup the new non-bonded parameters
        for t in types:
            indices = [
                index + 1 for index in self.params if self.params[index] == t
            ]
            selection_string = '(:{residue_mask})&(@{atom_name})'.format(
                residue_mask=','.join(str(i) for i in indices), atom_name=t)
            print topol.LJ_radius
            action = pmd.tools.addLJType(
                topol,
                selection_string,
                radius=self.lj_params[t][0].value_in_unit(u.angstrom),
                epsilon=self.lj_params[t][1].value_in_unit(
                    u.kilocalorie_per_mole))
            action.execute()
            print topol.LJ_radius