Пример #1
0
    def _prep_sim(self, coords, external_forces=[]):

        try:
            from simtk.openmm import Platform, LangevinIntegrator, Vec3
            from simtk.openmm.app import Modeller, ForceField, \
                CutoffNonPeriodic, PME, Simulation, HBonds
            from simtk.unit import angstrom, nanometers, picosecond, \
                kelvin, Quantity, molar
        except ImportError:
            raise ImportError(
                'Please install PDBFixer and OpenMM in order to use ClustENM.')

        positions = Quantity([Vec3(*xyz) for xyz in coords], angstrom)
        modeller = Modeller(self._topology, positions)

        if self._sol == 'imp':
            forcefield = ForceField(*self._force_field)

            system = forcefield.createSystem(modeller.topology,
                                             nonbondedMethod=CutoffNonPeriodic,
                                             nonbondedCutoff=1.0 * nanometers,
                                             constraints=HBonds)

        if self._sol == 'exp':
            forcefield = ForceField(*self._force_field)

            modeller.addSolvent(forcefield,
                                padding=self._padding * nanometers,
                                ionicStrength=self._ionicStrength * molar)

            system = forcefield.createSystem(modeller.topology,
                                             nonbondedMethod=PME,
                                             nonbondedCutoff=1.0 * nanometers,
                                             constraints=HBonds)

        for force in external_forces:
            system.addForce(force)

        integrator = LangevinIntegrator(self._temp * kelvin, 1 / picosecond,
                                        0.002 * picosecond)

        # precision could be mixed, but single is okay.
        platform = self._platform if self._platform is None else Platform.getPlatformByName(
            self._platform)
        properties = None

        if self._platform is None:
            properties = {'Precision': 'single'}
        elif self._platform in ['CUDA', 'OpenCL']:
            properties = {'Precision': 'single'}

        simulation = Simulation(modeller.topology, system, integrator,
                                platform, properties)

        simulation.context.setPositions(modeller.positions)

        return simulation
Пример #2
0
def check_hydrogens(molecule, ID):
    # Check that Hydrogens are in structure
    if len(molecule.top.select("name == H")) == 0:
        # If absent, then add Hydrogens using the Amber99sb force-field
        try:
            from simtk.openmm.app import PDBFile, Modeller, ForceField
            pdb = PDBFile(ID + ".pdb")
            modeller = Modeller(pdb.topology, pdb.positions)
            forcefield = ForceField('amber99sb.xml','tip3p.xml')
            modeller.addHydrogens(forcefield)
            PDBFile.writeFile(modeller.topology, modeller.positions, open(ID + ".pdb", 'w'))
            molecule = md.load(ID + ".pdb").remove_solvent()
        except:
            warnings.warn("""PDB topology missing Hydrogens. Either manually add
            or install OpenMM through SIMTK to automatically correct.""")
            pass
    return molecule
def check_hydrogens(molecule, ID):
    # Check that Hydrogens are in structure
    if len(molecule.top.select("name == H")) == 0:
        # If absent, then add Hydrogens using the Amber99sb force-field
        try:
            from simtk.openmm.app import PDBFile, Modeller, ForceField
            pdb = PDBFile(ID + ".pdb")
            modeller = Modeller(pdb.topology, pdb.positions)
            forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
            modeller.addHydrogens(forcefield)
            PDBFile.writeFile(modeller.topology, modeller.positions,
                              open(ID + ".pdb", 'w'))
            molecule = md.load(ID + ".pdb").remove_solvent()
        except:
            warnings.warn(
                """PDB topology missing Hydrogens. Either manually add
            or install OpenMM through SIMTK to automatically correct.""")
            pass
    return molecule
Пример #4
0
    def __init__(self, pdb_path, offset_size=2):
        # OpenMM init
        self.pdb_path = pdb_path
        self.pdb = PDBFile(self.pdb_path)
        self.forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
        self.modeller = Modeller(self.pdb.topology, self.pdb.positions)

        # Remove any water that might be present in the PDB file
        self.modeller.deleteWater()

        # Add any hydrogens not present
        self.modeller.addHydrogens(self.forcefield)
        self.system = self.forcefield.createSystem(self.modeller.topology,
                                                   nonbondedMethod=PME,
                                                   nonbondedCutoff=1 *
                                                   u.nanometer,
                                                   constraints=HBonds)
        self.integrator = LangevinIntegrator(300 * u.kelvin, 1 / u.picosecond,
                                             0.002 * u.picoseconds)
        self.simulation = Simulation(self.modeller.topology, self.system,
                                     self.integrator)
        self.pdb_positions = self.modeller.getPositions()

        # Initialize bond dictionary and positions for chemcoord
        self.cc_bonds = {}
        self.offset_size = offset_size
        self._init_pdb_bonds()
        self.set_cc_positions(self.pdb_positions)

        # Perform initial minimization, which updates self.pdb_positions
        min_energy, min_positions = self.run_simulation()

        # Reset the positions after the minimization
        self.set_cc_positions(self.pdb_positions)
        self.torsion_indices = self._get_torsion_indices()
        self.starting_positions = min_positions
        self.starting_torsions = np.array([
            self.zmat.loc[self.torsion_indices[:, 0], 'dihedral'],
            self.zmat.loc[self.torsion_indices[:, 1], 'dihedral']
        ]).T
        self.seed_offsets()
    def test_add_solvent(self):
        """Test using simtk.opnmm.app.Modeller to add solvent to a small molecule parameterized by template generator"""
        # Select a molecule to add solvent around
        from simtk.openmm.app import NoCutoff, Modeller
        from simtk import unit
        molecule = self.molecules[0]
        openmm_topology = molecule.to_topology().to_openmm()
        openmm_positions = molecule.conformers[0]
        # Try adding solvent without residue template generator; this will fail
        from simtk.openmm.app import ForceField
        forcefield = ForceField('tip3p.xml')
        # Add solvent to a system containing a small molecule
        modeller = Modeller(openmm_topology, openmm_positions)
        try:
            modeller.addSolvent(forcefield, model='tip3p', padding=6.0*unit.angstroms)
        except ValueError as e:
            pass

        # Create a generator that knows about a few molecules
        generator = self.TEMPLATE_GENERATOR(molecules=self.molecules)
        # Add to the forcefield object
        forcefield.registerTemplateGenerator(generator.generator)
        # Add solvent to a system containing a small molecule
        # This should succeed
        modeller.addSolvent(forcefield, model='tip3p', padding=6.0*unit.angstroms)
Пример #6
0
 def add_hydrogens_by_openmm(self):
     from simtk.openmm.app import ForceField, Modeller, PDBFile
     from pdbfixer import PDBFixer
     fixer = PDBFixer(self.name)
     field = ForceField('amber99sb.xml', 'tip3p.xml')
     fixer.findMissingResidues()
     fixer.findMissingAtoms()
     fixer.addMissingAtoms()
     fixer.addMissingHydrogens(7.0)
     modeller = Modeller(fixer.topology, fixer.positions)
     modeller.addHydrogens(forcefield=field)
     modeller.deleteWater()
     PDBFile.writeModel(modeller.topology, modeller.positions, open(self.shotname+'_h.pdb', 'w'))
---SYSTEM PREPARATION---
    setup AM1-BCC charges for the solute, add solvent, set non-bonded method etc
'''
ligand_mol = Molecule.from_file('ethanol.sdf', file_format='sdf')

forcefield_kwargs = {'constraints': app.HBonds, 'rigidWater': True, 'removeCMMotion': True, 'hydrogenMass': 4 * unit.amu }

system_generator = SystemGenerator(
    forcefields=['amber/ff14SB.xml', 'amber/tip4pew_standard.xml'],
    small_molecule_forcefield='gaff-2.11',
    molecules=[ligand_mol],
    forcefield_kwargs=forcefield_kwargs)

ligand_pdb = PDBFile('ethanol.pdb')

modeller = Modeller(ligand_pdb.topology, ligand_pdb.positions)

modeller.addSolvent(system_generator.forcefield, model='tip4pew', padding=12.0 * unit.angstroms)

system = system_generator.forcefield.createSystem(modeller.topology, nonbondedMethod=PME,
        nonbondedCutoff=9.0 * unit.angstroms, constraints=HBonds)

'''
---FINISHED SYSTEM PREPARATION---
'''

'''
---ALCHEMICAL CONFIGURATION---
    define solute indexes, set up the alchemical region + factory, and specify steric/electrostatic lambda coupling for solvation
'''
# determines solute indexes
Пример #8
0
    'rigidWater': True,
    'removeCMMotion': False,
    'hydrogenMass': 4 * unit.amu
}
system_generator = SystemGenerator(
    forcefields=['amber/ff14SB.xml', 'amber/tip3p_standard.xml'],
    small_molecule_forcefield='gaff-2.11',
    molecules=[ligand_mol],
    forcefield_kwargs=forcefield_kwargs)

# Use Modeller to combine the protein and ligand into a complex
print('Reading protein')
protein_pdb = PDBFile(pdb_in)

print('Preparing complex')
modeller = Modeller(protein_pdb.topology, protein_pdb.positions)
print('System has %d atoms' % modeller.topology.getNumAtoms())

# This next bit is black magic.
# Modeller needs topology and positions. Lots of trial and error found that this is what works to get these from
# an openforcefield Molecule object that was created from a RDKit molecule.
# The topology part is described in the openforcefield API but the positions part grabs the first (and only)
# conformer and passes it to Modeller. It works. Don't ask why!
modeller.add(ligand_mol.to_topology().to_openmm(), ligand_mol.conformers[0])

print('System has %d atoms' % modeller.topology.getNumAtoms())

# Solvate
print('Adding solvent...')
# we use the 'padding' option to define the periodic box. The PDB file does not contain any
# unit cell information so we just create a box that has a 10A padding around the complex.
Пример #9
0
                if chain.get_id() == self.chain:
                    return 1
                else:
                    return 0

        p = PDBParser(PERMISSIVE=1)
        structure = p.get_structure(f'{pdbid}', f'{pdbid}_fixed.pdb')
        pdb_chain_file = f'chain_{chain}.pdb'
        io_w_no_h = PDBIO()
        io_w_no_h.set_structure(structure)
        io_w_no_h.save(f'{pdbid}_chain{chain}.pdb', ChainSelect(chain))

    print("The fixed.pdb file with selected chain is ready.")
    # load pdb to Modeller
    pdb = PDBFile(f'{pdbid}_chain{chain}.pdb')
    molecule = Modeller(pdb.topology, pdb.positions)
    print("Done loading pdb to Modeller.")
    # load force field
    forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
    print("Done loading force field.")
    print("OpenMM version:", version.version)
    # prepare system
    molecule.addSolvent(forcefield,
                        padding=12 * unit.angstrom,
                        model='tip3p',
                        positiveIon='Na+',
                        negativeIon='Cl-',
                        ionicStrength=0 * unit.molar)
    print("Done adding solvent.")
    PDBxFile.writeFile(molecule.topology,
                       molecule.positions,
Пример #10
0
    'removeCMMotion': False,
    'hydrogenMass': 4 * unit.amu
}
system_generator = SystemGenerator(
    forcefields=['amber/ff14SB.xml', 'amber/tip3p_standard.xml'],
    small_molecule_forcefield='openff_unconstrained-1.2.1.offxml',
    # small_molecule_forcefield='gaff-2.11',
    molecules=other_mols,
    forcefield_kwargs=forcefield_kwargs)

# Use Modeller to combine the protein and ligand into a complex
print('Reading protein')
protein_pdb = PDBFile(opt.receptor)

print('Preparing complex')
modeller = Modeller(protein_pdb.topology, protein_pdb.positions)
print('System has %d atoms' % modeller.topology.getNumAtoms())

# This next bit is black magic.
# Modeller needs topology and positions. Lots of trial and error found that this is what works to get these from
# an openforcefield Molecule object that was created from a RDKit molecule.
# The topology part is described in the openforcefield API but the positions part grabs the first (and only)
# conformer and passes it to Modeller. It works. Don't ask why!
if len(other_mols) != 0:
    for other_mol in other_mols:
        modeller.add(other_mol.to_topology().to_openmm(),
                     other_mol.conformers[0])
    #modeller.add(ligand_mol.to_topology().to_openmm(), ligand_mol.conformers[0])

# Generate ligand with solvent for FEP
if opt.ligand:
Пример #11
0
pdbid = '2JIU'
chain = 'B'
experiment = '2_dimensional'
work_dir = f'/home/guoj1/data_projects/cv_selection/metadynamics/{experiment}/{pdbid}'
temperature = 310.15 * unit.kelvin
pressure = 1.0 * unit.atmospheres
cv_min_1 = -19.44
cv_max_1 = -0.82
cv_std_1 = 4.24
cv_min_2 = 0.48
cv_max_2 = 13.63
cv_std_2 = 2.30

# load pdb to Modeller
pdb = PDBFile(f'{pdbid}_chain{chain}_minequi.pdb')
molecule = Modeller(pdb.topology, pdb.positions)
print("Done loading pdb to Modeller.")
# load force field
forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
print("Done loading force field.")
print("OpenMM version:", version.version)

# prepare the system (using heavy hydrogens and constrain all hygrogen atom-involved bonds)
system = forcefield.createSystem(pdb.topology,
                                 nonbondedMethod=PME,
                                 rigidWater=True,
                                 nonbondedCutoff=1 * unit.nanometer,
                                 hydrogenMass=4 * unit.amu,
                                 constraints=HBonds)

# specify the set of key atoms and calculate key dihedrals and distances
ligand_mol = Molecule.from_file('ligand1.sdf', file_format='sdf')
print(ligand_mol)
# can't read as PDB as "No toolkits in registry can read file"
#complex_pdb = Molecule(open('complex1.pdb', 'rb'), file_format='pdb')

# Use Modeller to combine the protein and ligand into a complex
print('Reading protein')
protein_pdb = PDBFile('protein.pdb')

# reading the ligand gives lots of warnings about "duplicate atom" but this seems incorrect
print('Reading ligand')
ligand_pdb = PDBFile('ligand1.pdb')

print('Preparing complex')
# Approach 1
modeller = Modeller(protein_pdb.topology, protein_pdb.positions)
modeller.add(ligand_pdb.topology, ligand_pdb.positions)
PDBFile.writeFile(modeller.topology, modeller.positions,
                  open('complex1.pdb', 'w'))

# Approach 2
# protein_pdb = parmed.load_file('protein.pdb')
# ligand_pdb = parmed.load_file('ligand1.pdb')
# complex = protein_pdb + ligand_pdb
# complex.save('complex1.pdb')

complex_pdb = PDBFile('complex1.pdb')

print('Preparing system')
forcefield_kwargs = {
    'constraints': app.HBonds,
Пример #13
0
def calculate_protein_energetics():
    """
    * Create an OpenMM system using the first fragment.
    * Add each fragment into the system.
    * Calculate the energy of the system and print.
    """

    os.chdir('group2')
    # Necessary due to size of calculation
    sys.setrecursionlimit(15000)

    frag1 = PDBFile('frag1/no_QUP_frag1.pdb')
    forcefield = ForceField(
        'frag1/QUBE_pro_frag1.xml',
        'frag2/QUBE_pro_frag2_plus.xml',
        'frag3/QUBE_pro_frag3_plus.xml',
        'frag4/QUBE_pro_frag4_plus.xml',
    )

    modeller = Modeller(frag1.topology, frag1.positions)

    frag2 = PDBFile('frag2/no_QUP_frag2.pdb')
    modeller.add(frag2.topology, frag2.positions)

    frag3 = PDBFile('frag3/no_QUP_frag3.pdb')
    modeller.add(frag3.topology, frag3.positions)

    frag4 = PDBFile('frag4/no_QUP_frag4.pdb')
    modeller.add(frag4.topology, frag4.positions)

    system = forcefield.createSystem(
        modeller.topology,
        nonbondedMethod=NoCutoff,
    )

    system = apply_opls_combo(system)

    integrator = LangevinIntegrator(
        298.15 * unit.kelvin,  # Temperature of heat bath
        1.0 / unit.picoseconds,  # Friction coefficient
        2.0 * unit.femtoseconds,  # Time step
    )

    platform = Platform.getPlatformByName('CPU')
    simulation = Simulation(modeller.topology, system, integrator, platform)
    simulation.context.setPositions(modeller.positions)
    print('energy from openmm library')
    print(simulation.context.getState(getEnergy=True).getPotentialEnergy())

    positions = simulation.context.getState(getPositions=True).getPositions()

    with open('output.pdb', 'w') as out_file:
        PDBFile.writeFile(simulation.topology, positions, out_file)

    structure = parmed.load_file('output.pdb')
    energy_comps = parmed.openmm.energy_decomposition_system(structure, system)

    total_energy = 0.0
    for comp in energy_comps:
        total_energy += comp[1]
        print(*comp)

    print(f'Total energy {total_energy: 6.6f}')
system_generator = SystemGenerator(
    forcefields=['amber/ff14SB.xml', 'amber/tip3p_standard.xml'],
    small_molecule_forcefield='gaff-2.11',
    molecules=[ligand_mol],
    forcefield_kwargs=forcefield_kwargs)

# Use Modeller to combine the protein and ligand into a complex
print('Reading protein')
protein_pdb = PDBFile('protein.pdb')

# reading the ligand gives lots of warnings about "duplicate atom" but this seems incorrect
print('Reading ligand')
ligand_pdb = PDBFile('ligand1.pdb')

print('Preparing complex')
modeller = Modeller(protein_pdb.topology, protein_pdb.positions)
print('System has %d atoms' % modeller.topology.getNumAtoms())
modeller.add(ligand_pdb.topology, ligand_pdb.positions)
print('System has %d atoms' % modeller.topology.getNumAtoms())

box_vectors = unit.Quantity(np.diag([100, 100, 100]), unit.angstrom)
modeller.topology.setPeriodicBoxVectors(box_vectors)

# Solvate
print('Adding solvent...')
modeller.addSolvent(system_generator.forcefield,
                    model='tip3p')  #, padding=5.0*unit.angstroms)
print('System has %d atoms' % modeller.topology.getNumAtoms())

PDBFile.writeFile(modeller.topology, modeller.positions,
                  open('complex1.pdb', 'w'))
Пример #15
0
"""
Testing the funnel hypothesis
"""
from math import pi
from simtk.openmm.app import PDBFile, ForceField, Modeller, PME, HBonds
from simtk.openmm import LangevinIntegrator
from simtk.unit import kelvin, nanometer, picosecond, picoseconds
import chemcoord as cc
import numpy as np
import pandas as pd
import util

pdb = PDBFile('1ubq.pdb')
forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
modeller = Modeller(pdb.topology, pdb.positions)
modeller.addHydrogens(forcefield)

system = forcefield.createSystem(modeller.topology,
                                 nonbondedMethod=PME,
                                 nonbondedCutoff=1 * nanometer,
                                 constraints=HBonds)
integrator = LangevinIntegrator(300 * kelvin, 1 / picosecond,
                                0.002 * picoseconds)
pdb_bonds = modeller.topology.bonds()
atoms = modeller.topology.atoms()
positions = modeller.getPositions()

cc_bonds = {}
cc_positions = np.zeros((3, modeller.topology.getNumAtoms()))
atom_names = []
Пример #16
0
class MoleculeUtil(object):
    """
    A class for managing a molecule defined by a PDB file
    """
    np.random.seed(20)

    def __init__(self, pdb_path, offset_size=2):
        # OpenMM init
        self.pdb_path = pdb_path
        self.pdb = PDBFile(self.pdb_path)
        self.forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')
        self.modeller = Modeller(self.pdb.topology, self.pdb.positions)

        # Remove any water that might be present in the PDB file
        self.modeller.deleteWater()

        # Add any hydrogens not present
        self.modeller.addHydrogens(self.forcefield)
        self.system = self.forcefield.createSystem(self.modeller.topology,
                                                   nonbondedMethod=PME,
                                                   nonbondedCutoff=1 *
                                                   u.nanometer,
                                                   constraints=HBonds)
        self.integrator = LangevinIntegrator(300 * u.kelvin, 1 / u.picosecond,
                                             0.002 * u.picoseconds)
        self.simulation = Simulation(self.modeller.topology, self.system,
                                     self.integrator)
        self.pdb_positions = self.modeller.getPositions()

        # Initialize bond dictionary and positions for chemcoord
        self.cc_bonds = {}
        self.offset_size = offset_size
        self._init_pdb_bonds()
        self.set_cc_positions(self.pdb_positions)

        # Perform initial minimization, which updates self.pdb_positions
        min_energy, min_positions = self.run_simulation()

        # Reset the positions after the minimization
        self.set_cc_positions(self.pdb_positions)
        self.torsion_indices = self._get_torsion_indices()
        self.starting_positions = min_positions
        self.starting_torsions = np.array([
            self.zmat.loc[self.torsion_indices[:, 0], 'dihedral'],
            self.zmat.loc[self.torsion_indices[:, 1], 'dihedral']
        ]).T
        self.seed_offsets()

    def _add_backbone_restraint(self):
        # https://github.com/ParmEd/ParmEd/wiki/OpenMM-Tricks-and-Recipes#positional-restraints
        positions = self.modeller.getPositions()
        force = CustomExternalForce('k*((x-x0)^2+(y-y0)^2+(z-z0)^2)')
        force.addGlobalParameter(
            'k', 5.0 * u.kilocalories_per_mole / u.angstroms**2)
        force.addPerParticleParameter('x0')
        force.addPerParticleParameter('y0')
        force.addPerParticleParameter('z0')

        for index, atom in enumerate(self.modeller.topology.atoms()):
            if atom.name in ('CA', 'C', 'N'):
                coord = positions[index]
                force.addParticle(index, coord.value_in_unit(u.nanometers))

        self.restraint_force_id = self.system.addForce(force)

    def _remove_backbone_restraint(self):
        self.system.removeForce(self.restraint_force_id)

    def _fix_backbone(self):
        for index, atom in enumerate(self.modeller.topology.atoms()):
            if atom.name in ('CA', 'C', 'N'):
                self.system.setParticleMass(index, 0)

    def seed_offsets(self):
        self.offsets = np.random.choice([0, 0, -1, 1],
                                        self.starting_torsions.shape)

    def get_torsions(self):
        return np.array([
            self.zmat.loc[self.torsion_indices[:, 0], 'dihedral'],
            self.zmat.loc[self.torsion_indices[:, 1], 'dihedral']
        ]).T

    def set_torsions(self, new_torsions):
        self.zmat.safe_loc[self.torsion_indices[:, 0],
                           'dihedral'] = new_torsions[:, 0]
        self.zmat.safe_loc[self.torsion_indices[:, 1],
                           'dihedral'] = new_torsions[:, 1]

    def get_offset_torsions(self, scale_factor):
        """
        Calculates and returns new torsion angles based on randomly generated
        offsets.

        Args:
            scale_factor: the relative scale of the offset relative to
                          self.offset_size
        Returns:
            The new torsion angles
        """
        total_offset = self.offset_size * scale_factor
        new_torsions = np.zeros(shape=self.starting_torsions.shape)
        new_torsions[:, 0] = self.starting_torsions[:, 0] + \
            (self.offsets[:, 0] * total_offset)
        new_torsions[:, 1] = self.starting_torsions[:, 1] + \
            (self.offsets[:, 1] * total_offset)
        return new_torsions

    def run_simulation(self):
        """
        Run a simulation to calculate the current configuration's energy level.
        Note that the atoms will likely move somewhat during the calculation,
        since energy minimization is used.

        Returns:
            A tuple of the form (potential_energy, updated_positions)
        """
        # Delete solvent that's based on previous positions
        cartesian = self.zmat.get_cartesian().sort_index()
        self.simulation.context.setPositions([
            Vec3(x, y, z)
            for x, y, z in zip(cartesian['x'], cartesian['y'], cartesian['z'])
        ])

        # self._add_backbone_restraint()
        # self._fix_backbone()

        self.modeller.addSolvent(self.forcefield, padding=1.0 * u.nanometer)
        self.simulation.minimizeEnergy(maxIterations=200)
        state = self.simulation.context.getState(getEnergy=True,
                                                 getPositions=True)
        p_energy = state.getPotentialEnergy()
        positions = state.getPositions(asNumpy=True)

        # Clean up - remove solvent and backbone restraint (for next iteration)
        self.modeller.deleteWater()

        # self._remove_backbone_restraint()

        return p_energy, positions

    def _init_pdb_bonds(self):
        """Construct a dictionary describing the PDB's bonds for chemcoord use"""
        for index in range(self.modeller.topology.getNumAtoms()):
            self.cc_bonds[index] = set()

        for bond in self.modeller.topology.bonds():
            self.cc_bonds[bond[0].index].add(bond[1].index)
            self.cc_bonds[bond[1].index].add(bond[0].index)

    def set_cc_positions(self, positions):
        """
        Calculates the zmat from an OpenMM modeller

        Args:
            positions (list): A list 
        """
        cc_df = self._get_cartesian_df(positions)
        self.cartesian = cc.Cartesian(cc_df)
        self.cartesian.set_bonds(self.cc_bonds)
        self.cartesian._give_val_sorted_bond_dict(use_lookup=True)
        self.zmat = self.cartesian.get_zmat(use_lookup=True)

    def _get_cartesian_df(self, positions):
        cc_positions = np.zeros((3, self.modeller.topology.getNumAtoms()))
        atom_names = []
        for index, atom in enumerate(self.modeller.topology.atoms()):
            pos = positions[index] / u.nanometer
            atom_names.append(atom.name)
            cc_positions[:, index] = pos

        cc_df = pd.DataFrame({
            'atom': atom_names,
            'x': cc_positions[0, :],
            'y': cc_positions[1, :],
            'z': cc_positions[2, :]
        })
        return cc_df

    def _get_torsion_indices(self):
        """
        Calculates indices into the zmatrix which correspond to phi
        and psi angles.

        Args:
            zmat: the zmatrix specifying the molecule
        Returns:
            a numpy.array, with first column as phi_indices, second column
            as psi_indices
        """
        phi_indices = []
        psi_indices = []

        for i in range(len(self.zmat.index)):
            b_index = self.zmat.loc[i, 'b']
            a_index = self.zmat.loc[i, 'a']
            d_index = self.zmat.loc[i, 'd']

            # If this molecule references a magic string (origin, e_x, e_y, e_z, etc)
            if isinstance(b_index, str) or isinstance(
                    a_index, str) or isinstance(d_index, str):
                continue

            # Psi angles
            if (self.zmat.loc[i, 'atom'] == 'N') & \
                    (self.zmat.loc[b_index, 'atom'] == 'CA') & \
                    (self.zmat.loc[a_index, 'atom'] == 'C') & \
                    (self.zmat.loc[d_index, 'atom'] == 'N'):
                psi_indices.append(i)

            elif (self.zmat.loc[i, 'atom'] == 'N') & \
                    (self.zmat.loc[b_index, 'atom'] == 'C') & \
                    (self.zmat.loc[a_index, 'atom'] == 'CA') & \
                    (self.zmat.loc[d_index, 'atom'] == 'N'):
                psi_indices.append(i)

            elif (self.zmat.loc[i, 'atom'] == 'C') & \
                    (self.zmat.loc[b_index, 'atom'] == 'N') & \
                    (self.zmat.loc[a_index, 'atom'] == 'CA') & \
                    (self.zmat.loc[d_index, 'atom'] == 'C'):
                phi_indices.append(i)

            elif (self.zmat.loc[i, 'atom'] == 'C') & \
                    (self.zmat.loc[b_index, 'atom'] == 'CA') & \
                    (self.zmat.loc[a_index, 'atom'] == 'N') & \
                    (self.zmat.loc[d_index, 'atom'] == 'C'):
                phi_indices.append(i)

        return np.array([phi_indices, psi_indices]).T
Пример #17
0
# Read the molfile into RDKit, add Hs and create an openforcefield Molecule object
print('Reading ligand')
rdkitmol = Chem.MolFromMolFile(mol_in)
print('Adding hydrogens')
rdkitmolh = Chem.AddHs(rdkitmol, addCoords=True)
# ensure the chiral centers are all defined
Chem.AssignAtomChiralTagsFromStructure(rdkitmolh)
ligand_mol = Molecule(rdkitmolh)

print('Reading protein')
protein_pdb = PDBFile(pdb_in)

# Use Modeller to combine the protein and ligand into a complex
print('Preparing complex')
modeller = Modeller(protein_pdb.topology, protein_pdb.positions)

# This next bit is black magic.
# Modeller needs topology and positions. Lots of trial and error found that this is what works to get these from
# an openforcefield Molecule object that was created from a RDKit molecule.
# The topology part is described in the openforcefield API but the positions part grabs the first (and only)
# conformer and passes it to Modeller. It works. Don't ask why!
modeller.add(ligand_mol.to_topology().to_openmm(), ligand_mol.conformers[0])
# modeller.topology.setPeriodicBoxVectors(
#     [Vec3(x=8.461, y=0.0, z=0.0),
#     Vec3(x=0.0, y=8.461, z=0.0),
#     Vec3(x=0.0, y=0.0, z=8.461)])

print('System has %d atoms' % modeller.topology.getNumAtoms())

with open(output_complex, 'w') as outfile: