def mol_to_parmed(mol):
    """ Convert MDT Molecule to parmed Structure
    Args:
        mol (moldesign.Molecule):

    Returns:
        parmed.Structure
    """
    struc = parmed.Structure()
    struc.title = mol.name

    pmedatoms = []
    for atom in mol.atoms:
        pmedatm = parmed.Atom(atomic_number=atom.atomic_number,
                              name=atom.name,
                              mass=atom.mass.value_in(u.dalton),
                              number=utils.if_not_none(atom.pdbindex, -1))
        pmedatm.xx, pmedatm.xy, pmedatm.xz = atom.position.value_in(u.angstrom)
        pmedatoms.append(pmedatm)
        struc.add_atom(pmedatm,
                       resname=utils.if_not_none(atom.residue.resname, 'UNL'),
                       resnum=utils.if_not_none(atom.residue.pdbindex, -1),
                       chain=utils.if_not_none(atom.chain.name, ''))

    for bond in mol.bonds:
        struc.bonds.append(
            parmed.Bond(pmedatoms[bond.a1.index],
                        pmedatoms[bond.a2.index],
                        order=bond.order))
    return struc
Example #2
0
def test_assign_histidine():
    fn = get_fn('4lzt/4lzt_h.pdb')
    parm = pmd.load_file(fn)
    his_residues = [
        res.name for res in parm.residues
        if res.name in {'HIS', 'HIE', 'HID', 'HIP'}
    ]
    assert his_residues == ['HIS']

    pdbfixer = AmberPDBFixer(parm)
    pdbfixer.assign_histidine()
    his_residues = [
        res.name for res in pdbfixer.parm.residues
        if res.name in {'HIS', 'HIE', 'HID', 'HIP'}
    ]
    assert his_residues == ['HID']

    # Do not rename to HIS if this residue does not
    # have hydrogen.
    parm2 = pmd.Structure()
    for resnum, resname in enumerate(['HIE', 'HID', 'HIS']):
        atom = pmd.Atom(name='C', atomic_number=6)
        parm2.add_atom(atom, resname, resnum=resnum, chain='A')
    fixer2 = AmberPDBFixer(parm2)
    fixer2.assign_histidine()
    assert ['HIE', 'HID', 'HIS'] == [res.name for res in fixer2.parm.residues]
Example #3
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)
Example #4
0
 def test_duplicate_angle_type(self):
     """ Tests handling of duplicate angle 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('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.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[1]))
     self.assertRaises(
         pmd.exceptions.ParameterError, lambda: pmd.ParameterSet.
         from_structure(struct, allow_unequal_duplicates=False))
Example #5
0
def _write_pdb(xyzname, resname):

    bname = os.path.basename(xyzname)

    lines = []
    with open(xyzname, "r") as f:
        lines = f.readlines()[2:]

    s = parmed.Structure()
    r = parmed.Residue(name=resname, number=1, list=s.residues)
    s.residues.append(r)

    for i, atom_line in enumerate(lines, 1):
        data = atom_line.strip().split()
        a = parmed.Atom(list=s.atoms,
                        atomic_number=parmed.periodic_table.AtomicNum[data[0]],
                        name=data[0] + "%d" % i)
        a.number = i
        a.xx = float(data[1])
        a.xy = float(data[2])
        a.xz = float(data[3])
        r.add_atom(a)
        s.atoms.append(a)

    s.write_pdb(os.path.splitext(bname)[0] + ".pdb")
Example #6
0
 def __init__(self, parm=None):
     # TODO: make a copy?
     # Why not now? parm[:] will not correctly assign TER residue
     # self.parm = parm[:]
     if isinstance(parm, string_types):
         self.parm = parmed.load_file(parm)
     elif parm is None:
         self.parm = parmed.Structure()
     else:
         self.parm = parm
Example #7
0
 def get_structure_string(self):
     """Require `parmed` package.
     """
     import parmed as pmd
     c = self._schrodinger_structure
     s = pmd.Structure()
     fsys = c.fsys_ct if hasattr(c, 'fsys_ct') else c
     for atom in fsys.atom:
         parm_atom = pmd.Atom(name=atom.pdbname.strip(), atomic_number=atom.atomic_number)
         s.add_atom(parm_atom, atom.pdbres.strip(), atom.resnum, chain=atom.chain)
     s.coordinates = fsys.getXYZ()
     return ParmEdStructure(s).get_structure_string()
Example #8
0
 def ethane_ua(self):
     ethane = parmed.Structure()
     a1 = parmed.topologyobjects.Atom(name="C", atomic_number=6)
     a2 = parmed.topologyobjects.Atom(name="C", atomic_number=6)
     ethane.add_atom(a1, resname="RES", resnum=1)
     ethane.add_atom(a2, resname="RES", resnum=1)
     bond_type = parmed.topologyobjects.BondType(1.0, 1.0)
     bond = parmed.topologyobjects.Bond(a1, a2, type=bond_type)
     ethane.bonds.append(bond)
     ethane.bond_types.append(bond_type)
     ethane.coordinates = np.array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]])
     return ethane
Example #9
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)
def createStructureFromResidue(residue):
    # Create ParmEd structure for residue.
    structure = parmed.Structure()
    for a in residue.atoms():
        if a.element is None:
            atom = parmed.ExtraPoint(name=a.name)
        else:
            atom = parmed.Atom(atomic_number=a.element.atomic_number, name=a.name, mass=a.element.mass)
        structure.add_atom(atom, residue.name, residue.index, 'A')
        atommap[a] = atom
    for a1, a2 in topology.bonds():
        structure.bonds.append(Bond(atommap[a1], atommap[a2]))

    return structure
 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)
Example #12
0
def _structure_from_residue(residue, parent_structure):
    """Convert a ParmEd Residue to an equivalent Structure."""
    structure = pmd.Structure()
    for atom in residue.atoms:
        structure.add_atom(atom, resname=residue.name, resnum=residue.number)

    for bond in parent_structure.bonds:
        if bond.atom1 in residue.atoms and bond.atom2 in residue.atoms:
            structure.bonds.append(bond)

    idx_offset = min([a.idx for a in structure])
    for atom in structure.atoms:
        atom._idx -= idx_offset

    return structure
Example #13
0
def add_ghost_atom_to_pqr_from_atoms_center_of_mass(pqr_filename,
                                                    atom_index_list,
                                                    new_pqr_filename=None):
    """
    Add a ghost atom to a PQR file at the location of the center
    of mass of the atoms listed.
    
    Parameters:
    -----------
    pqr_filename : str
        The name of the PQR file where the ghost atom will be added
        into the file itself.
        
    atom_index_list : list
        A list of integers which are atom indices. The center of mass
        will be found for these atoms, and the ghost atom will be 
        located at that center of mass.
        
    new_pqr_filename : str or None
        If None, the pqr_filename will be overwritten. Otherwise, the
        new PQR with the ghost atom will be written to this file.
    """

    if new_pqr_filename is None:
        new_pqr_filename = pqr_filename
    pqr_struct = parmed.load_file(pqr_filename, skip_bonds=True)
    center_of_mass = np.array([[0., 0., 0.]])
    total_mass = 0.0
    for atom_index in atom_index_list:
        atom_pos = pqr_struct.coordinates[atom_index, :]
        atom_mass = pqr_struct.atoms[atom_index].mass
        center_of_mass += atom_mass * atom_pos
        total_mass += atom_mass
    center_of_mass = center_of_mass / total_mass
    ghost_atom = parmed.Atom(name="GHO",
                             mass=0.0,
                             charge=0.0,
                             solvent_radius=0.0)
    ghost_structure = parmed.Structure()
    ghost_structure.add_atom(ghost_atom, "GHO", 1)
    ghost_structure.coordinates = np.array(center_of_mass)
    complex = pqr_struct + ghost_structure
    for residue in complex.residues:
        residue.chain = ""

    complex.save(new_pqr_filename, overwrite=True)
    ghost_index = len(complex.atoms)
    return ghost_index
Example #14
0
def to_parmed(traj, all_coords=False):
    import parmed as pmd

    parm = pmd.Structure()
    for atom in traj.top.simplify().atoms:
        p_atom = pmd.Atom(name=atom.name,
                          type=atom.type,
                          atomic_number=atom.atomic_number,
                          charge=atom.charge,
                          mass=atom.mass)
        parm.add_atom(p_atom, resname=atom.resname, resnum=atom.resid)
        # chain=str(atom.molnum))
    if all_coords:
        parm.coordinates = traj.xyz
    else:
        parm.coordinates = traj.xyz[0]
    parm.box = traj.top.box
    return parm
Example #15
0
    def to_parmed(self, title='', **kwargs):
        """Create a ParmEd Structure from a Compound. """
        structure = pmd.Structure()
        structure.title = title if title else self.name
        atom_mapping = {}  # For creating bonds below
        guessed_elements = set()
        for atom in self.particles():
            atomic_number = None
            name = ''.join(char for char in atom.name if not char.isdigit())
            try:
                atomic_number = AtomicNum[atom.name]
            except KeyError:
                element = element_by_name(atom.name)
                if name not in guessed_elements:
                    warn('Guessing that "{}" is element: "{}"'.format(
                        atom, element))
                    guessed_elements.add(name)
            else:
                element = atom.name

            atomic_number = atomic_number or AtomicNum[element]
            mass = Mass[element]
            pmd_atom = pmd.Atom(atomic_number=atomic_number,
                                name=atom.name,
                                mass=mass)
            pmd_atom.xx, pmd_atom.xy, pmd_atom.xz = atom.pos * 10  # Angstroms
            structure.add_atom(pmd_atom, resname='RES', resnum=1)
            atom_mapping[atom] = pmd_atom

        for atom1, atom2 in self.bonds():
            bond = pmd.Bond(atom_mapping[atom1], atom_mapping[atom2])
            structure.bonds.append(bond)

        box = self.boundingbox
        box_vector = np.empty(6)
        box_vector[3] = box_vector[4] = box_vector[5] = 90.0
        for dim, val in enumerate(self.periodicity):
            if val:
                box_vector[dim] = val * 10
            else:
                box_vector[dim] = box.lengths[dim] * 10 + 5
        structure.box = box_vector
        return structure
Example #16
0
 def propane_ua(self):
     propane = parmed.Structure()
     a1 = parmed.topologyobjects.Atom(name="C", atomic_number=6)
     a2 = parmed.topologyobjects.Atom(name="C", atomic_number=6)
     a3 = parmed.topologyobjects.Atom(name="C", atomic_number=6)
     propane.add_atom(a1, resname="RES", resnum=1)
     propane.add_atom(a2, resname="RES", resnum=1)
     propane.add_atom(a3, resname="RES", resnum=1)
     bond_type = parmed.topologyobjects.BondType(1.5, 1.5)
     b1 = parmed.topologyobjects.Bond(a1, a2, type=bond_type)
     b2 = parmed.topologyobjects.Bond(a2, a3, type=bond_type)
     propane.bonds.append(b1)
     propane.bonds.append(b2)
     propane.bond_types.append(bond_type)
     propane.coordinates = np.array(
         [
             [0.0, 0.1, 0.2],
             [1.0, 0.3, 0.1],
             [2.0, 0.4, 0.2]
         ]
     )
     return propane
Example #17
0
    def process(self, mol, port):
        try:

            # Split the complex in components in order to apply the FF
            protein, ligand, water, excipients = oeommutils.split(
                mol, ligand_res_name=self.opt['ligand_res_name'])

            self.log.info(
                "\nComplex name: {}\nProtein atom numbers = {}\nLigand atom numbers = {}\n"
                "Water atom numbers = {}\nExcipients atom numbers = {}".format(
                    mol.GetTitle(), protein.NumAtoms(), ligand.NumAtoms(),
                    water.NumAtoms(), excipients.NumAtoms()))

            # Unique prefix name used to output parametrization files
            self.opt['prefix_name'] = mol.GetTitle()

            oe_mol_list = []
            par_mol_list = []

            # Apply FF to the Protein
            if protein.NumAtoms():
                oe_mol_list.append(protein)
                protein_structure = utils.applyffProtein(protein, self.opt)
                par_mol_list.append(protein_structure)

            # Apply FF to the ligand
            if ligand.NumAtoms():
                oe_mol_list.append(ligand)
                ligand_structure = utils.applyffLigand(ligand, self.opt)
                par_mol_list.append(ligand_structure)

            # Apply FF to water molecules
            if water.NumAtoms():
                oe_mol_list.append(water)
                water_structure = utils.applyffWater(water, self.opt)
                par_mol_list.append(water_structure)

            # Apply FF to the excipients
            if excipients.NumAtoms():
                excipient_structure = utils.applyffExcipients(
                    excipients, self.opt)
                par_mol_list.append(excipient_structure)

                # The excipient order is set equal to the order in related
                # parmed structure to avoid possible atom index mismatching
                excipients = oeommutils.openmmTop_to_oemol(
                    excipient_structure.topology,
                    excipient_structure.positions,
                    verbose=False)
                oechem.OEPerceiveBondOrders(excipients)
                oe_mol_list.append(excipients)

            # Build the overall Parmed structure
            complex_structure = parmed.Structure()

            for struc in par_mol_list:
                complex_structure = complex_structure + struc

            complx = oe_mol_list[0].CreateCopy()
            num_atom_system = complx.NumAtoms()

            for idx in range(1, len(oe_mol_list)):
                oechem.OEAddMols(complx, oe_mol_list[idx])
                num_atom_system += oe_mol_list[idx].NumAtoms()

            if not num_atom_system == complex_structure.topology.getNumAtoms():
                oechem.OEThrow.Fatal(
                    "Parmed and OE topologies mismatch atom number error")

            complx.SetTitle(mol.GetTitle())

            # Set Parmed structure box_vectors
            is_periodic = True
            try:
                vec_data = pack_utils.PackageOEMol.getData(complx,
                                                           tag='box_vectors')
                vec = pack_utils.PackageOEMol.decodePyObj(vec_data)
                complex_structure.box_vectors = vec
            except:
                is_periodic = False
                self.log.warn(
                    "System has been parametrize without periodic box vectors for vacuum simulation"
                )

            # Attach the Parmed structure to the complex
            packed_complex = pack_utils.PackageOEMol.pack(
                complx, complex_structure)

            # Attach the reference positions to the complex
            ref_positions = complex_structure.positions
            packedpos = pack_utils.PackageOEMol.encodePyObj(ref_positions)
            packed_complex.SetData(oechem.OEGetTag('OEMDDataRefPositions'),
                                   packedpos)

            # Set atom serial numbers, Ligand name and HETATM flag
            # oechem.OEPerceiveResidues(packed_complex, oechem.OEPreserveResInfo_SerialNumber)
            for at in packed_complex.GetAtoms():
                thisRes = oechem.OEAtomGetResidue(at)
                thisRes.SetSerialNumber(at.GetIdx())
                if thisRes.GetName() == 'UNL':
                    # thisRes.SetName("LIG")
                    thisRes.SetHetAtom(True)
                oechem.OEAtomSetResidue(at, thisRes)

            if packed_complex.GetMaxAtomIdx(
            ) != complex_structure.topology.getNumAtoms():
                raise ValueError(
                    "OEMol complex and Parmed structure mismatch atom numbers")

            # Check if it is possible to create the OpenMM System
            if is_periodic:
                complex_structure.createSystem(
                    nonbondedMethod=app.CutoffPeriodic,
                    nonbondedCutoff=10.0 * unit.angstroms,
                    constraints=app.HBonds,
                    removeCMMotion=False)
            else:
                complex_structure.createSystem(nonbondedMethod=app.NoCutoff,
                                               constraints=app.HBonds,
                                               removeCMMotion=False)

            self.success.emit(packed_complex)
        except Exception as e:
            # Attach error message to the molecule that failed
            self.log.error(traceback.format_exc())
            mol.SetData('error', str(e))
            # Return failed mol
            self.failure.emit(mol)

        return
def specific_ff_to_residue(
    structure,
    forcefield_selection=None,
    residues=None,
    reorder_res_in_pdb_psf=False,
    boxes_for_simulation=1,
):
    """
    Takes the mbuild Compound or mbuild Box structure and applies the selected
    force field to the corresponding residue via foyer.
    Note: a residue is defined as a molecule in this case, so it is not
    designed for applying a force field to a protein.

    Parameters
    ----------
    structure: mbuild Compound object or mbuild Box object;
        The mBuild Compound object or mbuild Box object, which contains the molecules
        (or empty box) that will have the force field applied to them.
    forcefield_selection: str or dictionary, default=None
        Apply a forcefield to the output file by selecting a force field xml file with
        its path or by using the standard force field name provided the `foyer` package.
        Example dict for FF file: {'ETH' : 'oplsaa.xml', 'OCT': 'path_to file/trappe-ua.xml'}
        Example str for FF file: 'path_to file/trappe-ua.xml'
        Example dict for standard FF names : {'ETH' : 'oplsaa', 'OCT': 'trappe-ua'}
        Example str for standard FF names: 'trappe-ua'
        Example of a mixed dict with both : {'ETH' : 'oplsaa', 'OCT': 'path_to file/'trappe-ua.xml'}
    residues: list, [str, ..., str], default=None
        Labels of unique residues in the Compound. Residues are assigned by
        checking against Compound.name.  Only supply residue names as 4 characters
        strings, as the residue names are truncated to 4 characters to fit in the
        psf and pdb file.
    reorder_res_in_pdb_psf: bool, default=False
        This option provides the ability to reorder the residues/molecules from the original
        structure's order.  If True, the residues will be reordered as they appear in the residues
        variable.  If False, the order will be the same as entered in the original structure.
    boxes_for_simulation: int [1, 2], default = 1
        Gibbs (GEMC) or grand canonical (GCMC) ensembles are examples of where the boxes_for_simulation would be 2.
        Canonical (NVT) or isothermal–isobaric (NPT) ensembles are example with the boxes_for_simulation equal to 1.
        Note: the only valid options are 1 or 2.

    Returns
    -------
    list, [structure, coulomb14scalar_dict, lj14_scalar_dict, residues_applied_list]
        structure: parmed.Structure
            parmed structure with applied force field
        coulomb14scalar_dict: dict
            a dictionary with the 1,4-colombic scalars for each residue
                (i.e., a different force field could on each residue)
        lj14_scalar_dict: dict
            a dictionary with the 1,4-LJ scalars for each residue
            (i.e., a different force field could on each residue)
        residues_applied_list: list
            list of residues (i.e., list of stings).
            These are all the residues in which the force field actually applied

    Notes
    -----
    To write the NAMD/GOMC force field, pdb, psf, and force field
    (.inp) files, the residues and forcefields must be provided in
    a str or dictionary. If a dictionary is provided all residues must
    be specified to a force field if the boxes_for_simulation is equal to 1.

    Generating an empty box (i.e., pdb and psf files):
    Enter residues = [], but the accompanying structure must be an empty mb.Box.
    However, when doing this, the forcefield_selection must be supplied,
    or it will provide an error (i.e., forcefield_selection can not be equal to None).

    In this current FF/psf/pdb writer, a residue type is essentially a molecule type.
    Therefore, it can only correctly write systems where every bead/atom in the molecule
    has the same residue name, and the residue name is specific to that molecule type.
    For example: a protein molecule with many residue names is not currently supported,
    but is planned to be supported in the future.
    """

    if has_foyer:
        from foyer import Forcefield
        from foyer.forcefields import forcefields
    else:
        print_error_message = (
            "Package foyer is not installed. "
            "Please install it using conda install -c conda-forge foyer")
        raise ImportError(print_error_message)

    if not isinstance(structure, (Compound, mb.Box)):
        print_error_message = ("ERROR: The structure expected to be of type: "
                               "{} or {}, received: {}".format(
                                   type(Compound()),
                                   type(mb.Box(lengths=[1, 1, 1])),
                                   type(structure),
                               ))
        raise TypeError(print_error_message)

    print("forcefield_selection = " + str(forcefield_selection))
    if forcefield_selection is None:
        print_error_message = (
            "Please the force field selection (forcefield_selection) as a dictionary "
            "with all the residues specified to a force field "
            '-> Ex: {"Water" : "oplsaa", "OCT": "path/trappe-ua.xml"}, '
            "Note: the file path must be specified the force field file "
            "or by using the standard force field name provided the `foyer` package."
        )
        raise TypeError(print_error_message)

    elif forcefield_selection is not None and not isinstance(
            forcefield_selection, dict):
        print_error_message = (
            "The force field selection (forcefield_selection) "
            "is not a dictionary. Please enter a dictionary "
            "with all the residues specified to a force field "
            '-> Ex: {"Water" : "oplsaa", "OCT": "path/trappe-ua.xml"}, '
            "Note: the file path must be specified the force field file "
            "or by using the standard force field name provided the `foyer` package."
        )
        raise TypeError(print_error_message)

    if residues is None or not isinstance(residues, list):
        print_error_message = (
            "Please enter the residues in the Specific_FF_to_residue function."
        )
        raise TypeError(print_error_message)

    if not isinstance(reorder_res_in_pdb_psf, bool):
        print_error_message = (
            "Please enter the reorder_res_in_pdb_psf "
            "in the Specific_FF_to_residue function (i.e., True or False).")
        raise TypeError(print_error_message)

    print_error_message_for_boxes_for_simulatiion = (
        "ERROR: Please enter boxes_for_simulation equal "
        "the integer 1 or 2.")
    if not isinstance(boxes_for_simulation, int):
        raise TypeError(print_error_message_for_boxes_for_simulatiion)

    elif isinstance(boxes_for_simulation,
                    int) and boxes_for_simulation not in [
                        1,
                        2,
                    ]:
        raise ValueError(print_error_message_for_boxes_for_simulatiion)

    forcefield_keys_list = []
    if forcefield_selection is not None:
        for res in forcefield_selection.keys():
            forcefield_keys_list.append(res)
        ff_data = forcefield_selection

    if forcefield_keys_list == [] and len(residues) != 0:
        print_error_message = "The forcefield_selection variable are not provided, but there are residues provided."
        raise ValueError(print_error_message)

    elif forcefield_keys_list != [] and len(residues) == 0:
        print_error_message = (
            "The residues variable is an empty list but there are "
            "forcefield_selection variables provided.")
        raise ValueError(print_error_message)

    user_entered_ff_with_path_dict = (
        {}
    )  # True means user entered the path, False is a standard foyer FF with no path
    for z in range(0, len(forcefield_keys_list)):
        for res_i in range(0, len(residues)):
            if residues[res_i] == forcefield_keys_list[z]:
                if (os.path.splitext(ff_data[forcefield_keys_list[z]])[1]
                        == ".xml" and len(residues) != 0):
                    user_entered_ff_with_path_dict.update(
                        {residues[res_i]: True})
                elif (os.path.splitext(ff_data[forcefield_keys_list[z]])[1]
                      == "" and len(residues) != 0):
                    user_entered_ff_with_path_dict.update(
                        {residues[res_i]: False})
                else:
                    print_error_message = (
                        r"Please make sure you are entering the correct "
                        "foyer FF name and not a path to a FF file. "
                        "If you are entering a path to a FF file, "
                        "please use the forcefield_files variable with the "
                        "proper XML extension (.xml).")
                    raise ValueError(print_error_message)

    coulomb14scalar_dict = {}
    lj14_scalar_dict = {}
    for j in range(0, len(forcefield_keys_list)):
        residue_iteration = forcefield_keys_list[j]
        if user_entered_ff_with_path_dict[residue_iteration]:
            ff_for_residue_iteration = ff_data[residue_iteration]
            try:
                read_xlm_iteration = minidom.parse(ff_for_residue_iteration)

            except:
                print_error_message = (
                    "Please make sure you are entering the correct foyer FF path, "
                    "including the FF file name.xml "
                    "If you are using the pre-build FF files in foyer, "
                    "only use the string name without any extension.")
                raise ValueError(print_error_message)
        elif not user_entered_ff_with_path_dict[residue_iteration]:
            ff_for_residue_iteration = ff_data[residue_iteration]
            ff_names_path_iteration = (forcefields.get_ff_path()[0] + "/xml/" +
                                       ff_for_residue_iteration + ".xml")
            try:
                read_xlm_iteration = minidom.parse(ff_names_path_iteration)
            except:
                print_error_message = (
                    "Please make sure you are entering the correct foyer FF name, or the "
                    "correct file extension (i.e., .xml, if required).")
                raise ValueError(print_error_message)
        lj_coul_1_4_values = read_xlm_iteration.getElementsByTagName(
            "NonbondedForce")

        for Scalar in lj_coul_1_4_values:
            coulomb14scalar_dict.update({
                residue_iteration:
                float(Scalar.getAttribute("coulomb14scale"))
            })
            lj14_scalar_dict.update(
                {residue_iteration: float(Scalar.getAttribute("lj14scale"))})

    # Check to see if it is an empty mbuild.Compound and set intial atoms to 0
    # note empty mbuild.Compound will read 1 atoms but there is really noting there
    if isinstance(structure, Compound):
        if len(structure.children) == 0:
            # there are no real atoms in the Compound so the test fails. User should use mbuild.Box
            print_error_message = (
                "ERROR: If you are not providing an empty box, "
                "you need to specify the atoms/beads as children in the mb.Compound. "
                "If you are providing and empty box, please do so by specifying and "
                "mbuild Box ({})".format(type(mb.Box(lengths=[1, 1, 1]))))
            raise TypeError(print_error_message)
        else:
            initial_no_atoms = len(structure.to_parmed().atoms)

    # calculate the initial number of atoms for later comparison
    if isinstance(structure, mb.Box):
        lengths = structure.lengths
        angles = structure.angles

        structure = mb.Compound()
        structure.box = mb.Box(lengths=lengths, angles=angles)
        initial_no_atoms = 0

    # add the FF to the residues
    compound_box_infor = structure.to_parmed(residues=residues)
    new_structure = pmd.Structure()
    new_structure.box = compound_box_infor.box

    # prepare all compound and remove nested compounds
    no_layers_to_check_for_residues = 3

    print_error_message_all_res_not_specified = (
        "ERROR: All the residues are not specified, or "
        "the residues entered does not match the residues that "
        "were found and built for structure.")
    for j in range(0, no_layers_to_check_for_residues):
        new_compound_iter = mb.Compound()
        new_compound_iter.periodicity = structure.periodicity
        if structure.name in residues:
            if len(structure.children) == 0:
                warn(
                    "Warning: This residue is the atom, and is a single atom., "
                    + str(structure.name))
                new_compound_iter.add(mb.compound.clone(structure))

            elif len(structure.children) > 0:

                new_compound_iter.add(mb.compound.clone(structure))

        else:
            for child in structure.children:
                if len(child.children) == 0:
                    if child.name not in residues:
                        raise ValueError(
                            print_error_message_all_res_not_specified)

                    else:
                        new_compound_iter.add(mb.compound.clone(child))

                elif len(child.children) > 0:
                    if child.name in residues:
                        new_compound_iter.add(mb.compound.clone(child))
                    else:
                        for sub_child in child.children:
                            if sub_child.name in residues:
                                new_compound_iter.add(
                                    mb.compound.clone(sub_child))

                            else:
                                if len(sub_child.children) == 0 and (
                                        child.name not in residues):

                                    raise ValueError(
                                        print_error_message_all_res_not_specified
                                    )

        structure = new_compound_iter

    residues_applied_list = []
    residue_orig_order_list = []
    for child in structure.children:
        if child.name not in residue_orig_order_list:
            residue_orig_order_list.append(child.name)
    for res_reorder_iter in range(0, len(residues)):
        if residues[res_reorder_iter] not in residue_orig_order_list:
            text_to_print_1 = (
                "All the residues were not used from the forcefield_selection "
                "string or dictionary. There may be residues below other "
                "specified residues in the mbuild.Compound hierarchy. "
                "If so, all the highest listed residues pass down the force "
                "fields through the hierarchy. Alternatively, residues that "
                "are not in the structure may have been specified. ")
            text_to_print_2 = (
                "Note: This warning will appear if you are using the CHARMM pdb and psf writers "
                +
                "2 boxes, and the boxes do not contain all the residues in each box."
            )
            if boxes_for_simulation == 1:
                warn(text_to_print_1)
                raise ValueError(text_to_print_1)
            if boxes_for_simulation == 2:
                warn(text_to_print_1 + text_to_print_2)

    if not reorder_res_in_pdb_psf:
        residues = residue_orig_order_list
    elif reorder_res_in_pdb_psf:
        print(
            "INFO: the output file are being reordered in via the residues list's sequence."
        )

    for i in range(0, len(residues)):
        children_in_iteration = False
        new_compound_iteration = mb.Compound()
        new_compound_iter.periodicity = structure.periodicity
        new_structure_iteration = pmd.Structure()
        new_structure_iteration.box = compound_box_infor.box
        for child in structure.children:
            if ff_data.get(child.name) is None:
                print_error_message = "ERROR: All residues are not specified in the force_field dictionary"
                raise ValueError(print_error_message)

            if child.name == residues[i]:
                children_in_iteration = True
                new_compound_iteration.add(mb.compound.clone(child))

        if children_in_iteration:
            if user_entered_ff_with_path_dict[residues[i]]:
                ff_iteration = Forcefield(ff_data[residues[i]])
                residues_applied_list.append(residues[i])
            elif not user_entered_ff_with_path_dict[residues[i]]:
                ff_iteration = Forcefield(name=ff_data[residues[i]])
                residues_applied_list.append(residues[i])

            new_compound_iteration.box = None
            new_structure_iteration = ff_iteration.apply(
                new_compound_iteration, residues=[residues[i]])
            new_structure = new_structure + new_structure_iteration

    structure = new_structure

    # calculate the final number of atoms
    final_no_atoms = len(structure.atoms)

    if final_no_atoms != initial_no_atoms:
        print_error_message = (
            "ERROR: The initial number of atoms sent to the force field analysis is "
            "not the same as the final number of atoms analyzed. "
            "The initial number of atoms was {} and the final number of atoms was {}. "
            "Please ensure that all the residues names that are in the initial "
            "Compound are listed in the residues list "
            "(i.e., the residues variable).".format(initial_no_atoms,
                                                    final_no_atoms))
        raise ValueError(print_error_message)

    return [
        structure,
        coulomb14scalar_dict,
        lj14_scalar_dict,
        residues_applied_list,
    ]
Example #19
0
 def test_no_bonds(self):
     with pytest.raises(ValueError):
         ConstrainedMolecule(parmed.Structure())
Example #20
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
Example #21
0
def from_itp_mol2(path, mol_name):
    """ Fix mol2 files that have atom type
        put in both the atom name and atom type fields
        
        Parameters
        ---------
        path : str
        mol_name : str
        
        Notes
        -----
        Will generate a new mol2 file with of the form
        {}_new.mol2
        """
    
    #itp_file = path + 'tip3p.itp'
    #itp_file = path + 'dspc.itp'
    itp_file = path + mol_name + '.itp'
    mol2_file = path + mol_name + '.mol2'
    
    itplines = open(itp_file,'r').readlines()
    itplines = itp_utils.remove_comments(itplines)
    
    
    mol2_file_out = path + mol_name + "_new.mol2"
    
    cmpd2 = mb.load(mol2_file)
    cmpd2.name=mol_name
    

    #parmed won't read this mol2 file in properly directly
    temp_parmed = pmd.Structure()
    temp_parmed = cmpd2.to_parmed(residues=[cmpd2.name])

    atom_name_list = []
    atom_type_list = []

    #search for relavant info
    atoms_directive = itp_utils.find_directive('atoms', itplines)
    index = atoms_directive
    
    keep_iterating = True
    while keep_iterating == True:
        index += 1
        if itplines[index].find('bonds') == -1:
            
            atom_info = itplines[index].split()
            
            if len(atom_info) >= 7:
                atom_name_list.append(atom_info[4])
                atom_type_list.append(atom_info[1])
        else:
            keep_iterating = False


    #set the properties in the parmed structure
    for i, atom in enumerate(temp_parmed):
        atom.name = atom_name_list[i]
        atom.type = atom_type_list[i]


    temp_parmed.save(mol2_file_out, overwrite=True)
Example #22
0
def applyffExcipients(excipients, opt):
    """
    This function applies the selected force field to the
    excipients

    Parameters:
    -----------
    excipients: OEMol molecule
        The excipients molecules to parametrize
    opt: python dictionary
        The options used to parametrize the excipients

    Return:
    -------
    excipient_structure: Parmed structure instance
        The parametrized excipient parmed structure
    """

    # OpenMM topology and positions from OEMol
    topology, positions = oeommutils.oemol_to_openmmTop(excipients)

    # Try to apply the selected FF on the excipients
    forcefield = app.ForceField(opt['protein_forcefield'])

    # List of the unrecognized excipients
    unmatched_res_list = forcefield.getUnmatchedResidues(topology)

    # Unique unrecognized excipient names
    templates = set()
    for res in unmatched_res_list:
        templates.add(res.name)

    if templates:  # Some excipients are not recognized
        oechem.OEThrow.Info("The following excipients are not recognized "
                            "by the protein FF: {}"
                            "\nThey will be parametrized by using the FF: {}".format(templates, opt['other_forcefield']))

        # Create a bit vector mask used to split recognized from un-recognize excipients
        bv = oechem.OEBitVector(excipients.GetMaxAtomIdx())
        bv.NegateBits()

        # Dictionary containing the name and the parmed structures of the unrecognized excipients
        unrc_excipient_structures = {}

        # Dictionary used to skip already selected unrecognized excipients and count them
        unmatched_excp = {}

        # Ordered list of the unrecognized excipients
        unmatched_res_order = []

        for r_name in templates:
            unmatched_excp[r_name] = 0

        hv = oechem.OEHierView(excipients)

        for chain in hv.GetChains():
            for frag in chain.GetFragments():
                for hres in frag.GetResidues():
                    r_name = hres.GetOEResidue().GetName()
                    if r_name not in unmatched_excp:
                        continue
                    else:
                        unmatched_res_order.append(r_name)
                        if unmatched_excp[r_name]:  # Test if we have selected the unknown excipient
                            # Set Bit mask
                            atms = hres.GetAtoms()
                            for at in atms:
                                bv.SetBitOff(at.GetIdx())
                            unmatched_excp[r_name] += 1
                        else:
                            unmatched_excp[r_name] = 1
                            #  Create AtomBondSet to extract from the whole excipient system
                            #  the current selected FF unknown excipient
                            atms = hres.GetAtoms()
                            bond_set = set()
                            for at in atms:
                                bv.SetBitOff(at.GetIdx())
                                bonds = at.GetBonds()
                                for bond in bonds:
                                    bond_set.add(bond)
                            atom_bond_set = oechem.OEAtomBondSet(atms)
                            for bond in bond_set:
                                atom_bond_set.AddBond(bond)

                            # Create the unrecognized excipient OEMol
                            unrc_excp = oechem.OEMol()
                            if not oechem.OESubsetMol(unrc_excp, excipients, atom_bond_set):
                                oechem.OEThrow.Fatal("Is was not possible extract the residue: {}".format(r_name))

                            # Charge the unrecognized excipient
                            if not oequacpac.OEAssignCharges(unrc_excp,
                                                             oequacpac.OEAM1BCCCharges(symmetrize=True)):
                                oechem.OEThrow.Fatal("Is was not possible to "
                                                     "charge the extract residue: {}".format(r_name))

                            # If GAFF or GAFF2 is selected as FF check for tleap command
                            if opt['other_forcefield'] in ['GAFF', 'GAFF2']:
                                ff_utils.ParamLigStructure(oechem.OEMol(), opt['other_forcefield']).checkTleap

                            if opt['other_forcefield'] == 'SMIRNOFF':
                                unrc_excp = oeommutils.sanitizeOEMolecule(unrc_excp)

                            # Parametrize the unrecognized excipient by using the selected FF
                            pmd = ff_utils.ParamLigStructure(unrc_excp, opt['other_forcefield'],
                                                             prefix_name=opt['prefix_name']+'_'+r_name)
                            unrc_excp_struc = pmd.parameterize()
                            unrc_excp_struc.residues[0].name = r_name
                            unrc_excipient_structures[r_name] = unrc_excp_struc

        # Recognized FF excipients
        pred_rec = oechem.OEAtomIdxSelected(bv)
        rec_excp = oechem.OEMol()
        oechem.OESubsetMol(rec_excp, excipients, pred_rec)

        if rec_excp.NumAtoms() > 0:
            top_known, pos_known = oeommutils.oemol_to_openmmTop(rec_excp)
            ff_rec = app.ForceField(opt['protein_forcefield'])
            try:
                omm_system = ff_rec.createSystem(top_known, rigidWater=False)
                rec_struc = parmed.openmm.load_topology(top_known, omm_system, xyz=pos_known)
            except:
                oechem.OEThrow.Fatal("Error in the recognised excipient parametrization")

        # Unrecognized FF excipients
        bv.NegateBits()
        pred_unrc = oechem.OEAtomIdxSelected(bv)
        unrc_excp = oechem.OEMol()
        oechem.OESubsetMol(unrc_excp, excipients, pred_unrc)

        # Unrecognized FF excipients coordinates
        oe_coord_dic = unrc_excp.GetCoords()
        unrc_coords = np.ndarray(shape=(unrc_excp.NumAtoms(), 3))
        for at_idx in oe_coord_dic:
            unrc_coords[at_idx] = oe_coord_dic[at_idx]

        # It is important the order used to assemble the structures. In order to
        # avoid mismatch between the coordinates and the structures, it is convenient
        # to use the unrecognized residue order
        unmatched_res_order_count = []
        i = 0
        while i < len(unmatched_res_order):
            res_name = unmatched_res_order[i]
            for j in range(i+1, len(unmatched_res_order)):
                if unmatched_res_order[j] == res_name:
                    continue
                else:
                    break
            if i == (len(unmatched_res_order) - 1):
                num = 1
                unmatched_res_order_count.append((res_name, num))
                break
            else:
                num = j - i
                unmatched_res_order_count.append((res_name, num))
                i = j

        # Merge all the unrecognized Parmed structure
        unrc_struc = parmed.Structure()

        for pair in unmatched_res_order_count:
            res_name = pair[0]
            nums = pair[1]
            unrc_struc = unrc_struc + nums*unrc_excipient_structures[res_name]

        # Set the unrecognized coordinates
        unrc_struc.coordinates = unrc_coords

        # Set the parmed excipient structure merging
        # the unrecognized and recognized parmed
        # structures together
        if rec_excp.NumAtoms() > 0:
            excipients_structure = unrc_struc + rec_struc
        else:
            excipients_structure = unrc_struc

        return excipients_structure
    else:  # All the excipients are recognized by the selected FF
        omm_system = forcefield.createSystem(topology, rigidWater=False)
        excipients_structure = parmed.openmm.load_topology(topology, omm_system, xyz=positions)

        return excipients_structure
Example #23
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()
Example #24
0
def reparm(ligands, base):
    print(
        '**Running reparameterization of ligand(s) using open force fields\'s SMIRNOFF with openff 2.0.0**'
    )
    # Load already parm'd system
    in_prmtop = base + '.prmtop'
    in_crd = base + '.inpcrd'

    # Create parmed strucuture
    orig_structure = parmed.amber.AmberParm(in_prmtop, in_crd)

    # Split orig_stucuture into unique structure instances e.g. protein, water, ligand, etc.
    pieces = orig_structure.split()
    for piece in pieces:
        # TODO: Figure out how to know which piece is which
        print(f"There are {len(piece[1])} instance(s) of {piece[0]}")

    # Generate an openff topology for the ligand
    # Openff Molecule does not support mol2 so conversion is needed
    ligs_w_sdf = []
    for ligand in ligands:
        obabel[ligand[0], '-O', util.get_base(ligand[0]) + '.sdf']()
        ligs_w_sdf.append(
            (ligand[0], ligand[1], util.get_base(ligand[0]) + '.sdf'))

    # Keep track of ligands that were successfully reparmed so we know to skip them when putting the pieces back together
    reparmed_pieces = []
    complex_structure = parmed.Structure()
    force_field = ForceField("openff_unconstrained-2.0.0.offxml")

    for lig in ligs_w_sdf:
        # Set up openff topology
        ligand_off_molecule = Molecule(lig[2])
        ligand_pdbfile = PDBFile(lig[0])
        ligand_off_topology = Topology.from_openmm(
            ligand_pdbfile.topology,
            unique_molecules=[ligand_off_molecule],
        )
        # Parameterizing the ligand
        # Find ligand "piece", reparm, add to the new structure
        for piece in pieces:
            new_ligand_structure = None
            # TODO: Figure out how to know which piece is which
            if (ligand_off_molecule.n_atoms == len(piece[0].atoms)):
                if (ligand_off_molecule.n_bonds == len(piece[0].bonds)):
                    if ([
                            atom.atomic_number
                            for atom in ligand_off_molecule.atoms
                    ] == [atom.element for atom in piece[0].atoms]):
                        print('Found ligand piece', piece)
                        try:
                            # Since the method of matching the piece to ligand is imperfect, ligands that are isomers could mess things up.
                            # So try any piece that matches and see if we get an error
                            print('Reparameterizing ligand using SMIRNOFF')
                            ligand_system = force_field.create_openmm_system(
                                ligand_off_topology)
                            new_ligand_structure = parmed.openmm.load_topology(
                                ligand_off_topology.to_openmm(),
                                ligand_system,
                                xyz=piece[0].positions,
                            )
                            # A quick check to make sure things were not messed up during param
                            if check_discrepencies(new_ligand_structure,
                                                   piece):
                                # Add the newly parameterized ligand the complex structure
                                reparmed_pieces.append(piece)
                                new_ligand_structure *= len(piece[1])
                                complex_structure += parmed.amber.AmberParm.from_structure(
                                    new_ligand_structure)
                            break
                        except:
                            pass

    # Stick all the pieces back together
    for piece in pieces:
        if (piece not in reparmed_pieces):
            curr_structure = parmed.Structure()
            curr_structure += piece[0]
            curr_structure *= len(piece[1])
            complex_structure += parmed.amber.AmberParm.from_structure(
                curr_structure)

    # print("Unique atom names:",sorted(list({atom.atom_type.name for atom in complex_structure})),)
    # print("Number of unique atom types:", len({atom.atom_type for atom in complex_structure}))
    # print("Number of unique epsilons:", len({atom.epsilon for atom in complex_structure}))
    # print("Number of unique sigmas:", len({atom.sigma for atom in complex_structure}))

    # # Copy over the original coordinates and box vectors
    complex_structure.coordinates = orig_structure.coordinates
    complex_structure.box_vectors = orig_structure.box_vectors

    # Save the newly parameterized system
    complex_structure.save(base + ".prmtop", overwrite=True)
    complex_structure.save(base + ".inpcrd", overwrite=True)
Example #25
0
    def convert(self, obj):
        """Write selection at current trajectory frame to :class:`~parmed.structure.Structure`.

        Parameters
        -----------
        obj : AtomGroup or Universe or :class:`Timestep`
        """
        try:
            import parmed as pmd
        except ImportError:
            raise ImportError('ParmEd is required for ParmEdConverter but '
                              'is not installed. Try installing it with \n'
                              'pip install parmed')
        try:
            # make sure to use atoms (Issue 46)
            ag_or_ts = obj.atoms
        except AttributeError:
            if isinstance(obj, base.Timestep):
                raise ValueError("Writing Timesteps to ParmEd "
                                 "objects is not supported")
            else:
                raise_from(TypeError("No atoms found in obj argument"), None)

        # Check for topology information
        missing_topology = []
        try:
            names = ag_or_ts.names
        except (AttributeError, NoDataError):
            names = itertools.cycle(('X', ))
            missing_topology.append('names')
        try:
            resnames = ag_or_ts.resnames
        except (AttributeError, NoDataError):
            resnames = itertools.cycle(('UNK', ))
            missing_topology.append('resnames')

        if missing_topology:
            warnings.warn(
                "Supplied AtomGroup was missing the following attributes: "
                "{miss}. These will be written with default values. "
                "Alternatively these can be supplied as keyword arguments."
                "".format(miss=', '.join(missing_topology)))

        try:
            positions = ag_or_ts.positions
        except:
            positions = [None] * ag_or_ts.n_atoms

        try:
            velocities = ag_or_ts.velocities
        except:
            velocities = [None] * ag_or_ts.n_atoms

        atom_kwargs = []
        for atom, name, resname, xyz, vel in zip(ag_or_ts, names, resnames,
                                                 positions, velocities):
            akwargs = {'name': name}
            chain_seg = {'segid': atom.segid}
            for attrname in ('mass', 'charge', 'type', 'altLoc', 'tempfactor',
                             'occupancy', 'gbscreen', 'solventradius',
                             'nbindex', 'rmin', 'epsilon', 'rmin14',
                             'epsilon14', 'id'):
                try:
                    akwargs[MDA2PMD.get(attrname,
                                        attrname)] = getattr(atom, attrname)
                except AttributeError:
                    pass
            try:
                el = atom.element.lower().capitalize()
                akwargs['atomic_number'] = SYMB2Z[el]
            except (KeyError, AttributeError):
                try:
                    tp = atom.type.lower().capitalize()
                    akwargs['atomic_number'] = SYMB2Z[tp]
                except (KeyError, AttributeError):
                    pass
            try:
                chain_seg['chain'] = atom.chainID
            except AttributeError:
                pass
            try:
                chain_seg['inscode'] = atom.icode
            except AttributeError:
                pass
            atom_kwargs.append(
                (akwargs, resname, atom.resid, chain_seg, xyz, vel))

        struct = pmd.Structure()

        for akwarg, resname, resid, kw, xyz, vel in atom_kwargs:
            atom = pmd.Atom(**akwarg)
            if xyz is not None:
                atom.xx, atom.xy, atom.xz = xyz

            if vel is not None:
                atom.vx, atom.vy, atom.vz = vel

            atom.atom_type = pmd.AtomType(
                akwarg['name'],
                None,
                akwarg['mass'],
                atomic_number=akwargs.get('atomic_number'))
            struct.add_atom(atom, resname, resid, **kw)

        try:
            struct.box = ag_or_ts.dimensions
        except AttributeError:
            struct.box = None

        if hasattr(ag_or_ts, 'universe'):
            atomgroup = {
                atom: index
                for index, atom in enumerate(list(ag_or_ts))
            }
            get_atom_indices = functools.partial(get_indices_from_subset,
                                                 atomgroup=atomgroup,
                                                 universe=ag_or_ts.universe)
        else:
            get_atom_indices = lambda x: x

        # bonds
        try:
            params = ag_or_ts.bonds.atomgroup_intersection(ag_or_ts,
                                                           strict=True)
        except AttributeError:
            pass
        else:
            for p in params:
                atoms = [
                    struct.atoms[i] for i in map(get_atom_indices, p.indices)
                ]
                try:
                    for obj in p.type:
                        bond = pmd.Bond(*atoms, type=obj.type, order=obj.order)
                        struct.bonds.append(bond)
                    if isinstance(obj.type, pmd.BondType):
                        struct.bond_types.append(bond.type)
                        bond.type.list = struct.bond_types
                except (TypeError, AttributeError):
                    order = p.order if p.order is not None else 1
                    btype = getattr(p.type, 'type', None)

                    bond = pmd.Bond(*atoms, type=btype, order=order)
                    struct.bonds.append(bond)
                    if isinstance(bond.type, pmd.BondType):
                        struct.bond_types.append(bond.type)
                        bond.type.list = struct.bond_types

        # dihedrals
        try:
            params = ag_or_ts.dihedrals.atomgroup_intersection(ag_or_ts,
                                                               strict=True)
        except AttributeError:
            pass
        else:
            for p in params:
                atoms = [
                    struct.atoms[i] for i in map(get_atom_indices, p.indices)
                ]
                try:
                    for obj in p.type:
                        imp = getattr(obj, 'improper', False)
                        ign = getattr(obj, 'ignore_end', False)
                        dih = pmd.Dihedral(*atoms,
                                           type=obj.type,
                                           ignore_end=ign,
                                           improper=imp)
                        struct.dihedrals.append(dih)
                        if isinstance(dih.type, pmd.DihedralType):
                            struct.dihedral_types.append(dih.type)
                            dih.type.list = struct.dihedral_types
                except (TypeError, AttributeError):
                    btype = getattr(p.type, 'type', None)
                    imp = getattr(p.type, 'improper', False)
                    ign = getattr(p.type, 'ignore_end', False)
                    dih = pmd.Dihedral(*atoms,
                                       type=btype,
                                       improper=imp,
                                       ignore_end=ign)
                    struct.dihedrals.append(dih)
                    if isinstance(dih.type, pmd.DihedralType):
                        struct.dihedral_types.append(dih.type)
                        dih.type.list = struct.dihedral_types

        for param, pmdtype, trackedlist, typelist, clstype in (
            ('ureybradleys', pmd.UreyBradley, struct.urey_bradleys,
             struct.urey_bradley_types, pmd.BondType),
            ('angles', pmd.Angle, struct.angles, struct.angle_types,
             pmd.AngleType), ('impropers', pmd.Improper, struct.impropers,
                              struct.improper_types, pmd.ImproperType),
            ('cmaps', pmd.Cmap, struct.cmaps, struct.cmap_types,
             pmd.CmapType)):
            try:
                params = getattr(ag_or_ts, param)
                values = params.atomgroup_intersection(ag_or_ts, strict=True)
            except AttributeError:
                pass
            else:
                for v in values:
                    atoms = [
                        struct.atoms[i]
                        for i in map(get_atom_indices, v.indices)
                    ]

                    try:
                        for parmed_obj in v.type:
                            p = pmdtype(*atoms, type=parmed_obj.type)
                            trackedlist.append(p)
                            if isinstance(p.type, clstype):
                                typelist.append(p.type)
                                p.type.list = typelist
                    except (TypeError, AttributeError):
                        vtype = getattr(v.type, 'type', None)

                        p = pmdtype(*atoms, type=vtype)
                        trackedlist.append(p)
                        if isinstance(p.type, clstype):
                            typelist.append(p.type)
                            p.type.list = typelist
        return struct
Example #26
0
    def patch(self, top_string, crd_string):
        INTOP = "in.top"
        INRST = "in.rst"
        OUTTOP = "out.top"
        OUTRST = "out.rst"

        with util.in_temp_dir():
            with open(INTOP, "wt") as outfile:
                outfile.write(top_string)
            with open(INRST, "wt") as outfile:
                outfile.write(crd_string)

            base = pmd.load_file(INTOP)
            crd = pmd.load_file(INRST)
            base.coordinates = crd.coordinates

            # create a new structure to add our dummy atoms to
            parm = pmd.Structure()

            # add in atom type for our dummy particles
            atype = pmd.AtomType("SDUM", 0, mass=12.0, charge=0.0)
            atype.set_lj_params(0.0, 0.0)

            for i in range(self.n_tensors):
                a1 = pmd.Atom(
                    name="S1",
                    atomic_number=atype.atomic_number,
                    type=str(atype),
                    charge=atype.charge,
                    mass=atype.mass,
                    solvent_radius=1.0,
                    screen=0.5,
                )
                a1.atom_type = atype

                a2 = pmd.Atom(
                    name="S2",
                    atomic_number=atype.atomic_number,
                    type=str(atype),
                    charge=atype.charge,
                    mass=atype.mass,
                    solvent_radius=1.0,
                    screen=0.5,
                )
                a2.atom_type = atype

                parm.add_atom(a1, resname="SDM", resnum=i)
                parm.add_atom(a2, resname="SDM", resnum=i)

            # we add noise here because we'll get NaN if the particles ever
            # end up exactly on top of each other
            parm.positions = np.zeros((2 * self.n_tensors, 3))

            # combine the old system with the new dummy atoms
            comb = base + parm
            last_index = comb.residues[-1].idx
            self.resids = list(range(last_index - self.n_tensors + 2, last_index + 2))

            comb.write_parm(OUTTOP)
            comb.write_rst7(OUTRST)
            with open(OUTTOP, "rt") as infile:
                top_string = infile.read()
            with open(OUTRST, "rt") as infile:
                crd_string = infile.read()
        return top_string, crd_string