def _execute(self, directory, available_resources): import mdtraj from openforcefield.topology import Molecule, Topology with open(self.force_field_path) as file: force_field_source = ForceFieldSource.parse_json(file.read()) if not isinstance(force_field_source, SmirnoffForceFieldSource): raise ValueError( "Only SMIRNOFF force fields are supported by this protocol.", ) # Load in the inputs force_field = force_field_source.to_force_field() trajectory = mdtraj.load_dcd(self.trajectory_file_path, self.coordinate_file_path) unique_molecules = [] for component in self.substance.components: molecule = Molecule.from_smiles(smiles=component.smiles) unique_molecules.append(molecule) pdb_file = app.PDBFile(self.coordinate_file_path) topology = Topology.from_openmm(pdb_file.topology, unique_molecules=unique_molecules) # Compute the difference between the energies using the reduced force field, # and the full force field. energy_corrections = None if self.use_subset_of_force_field: target_system, _ = self._build_reduced_system( force_field, topology) subset_potentials_path = os.path.join(directory, f"subset.csv") subset_potentials = self._evaluate_reduced_potential( target_system, trajectory, subset_potentials_path, available_resources) full_statistics = StatisticsArray.from_pandas_csv( self.statistics_path) energy_corrections = ( full_statistics[ObservableType.PotentialEnergy] - subset_potentials[ObservableType.PotentialEnergy]) # Build the slightly perturbed system. reverse_system, reverse_parameter_value = self._build_reduced_system( force_field, topology, -self.perturbation_scale) forward_system, forward_parameter_value = self._build_reduced_system( force_field, topology, self.perturbation_scale) self.reverse_parameter_value = openmm_quantity_to_pint( reverse_parameter_value) self.forward_parameter_value = openmm_quantity_to_pint( forward_parameter_value) # Calculate the reduced potentials. self.reverse_potentials_path = os.path.join(directory, "reverse.csv") self.forward_potentials_path = os.path.join(directory, "forward.csv") self._evaluate_reduced_potential( reverse_system, trajectory, self.reverse_potentials_path, available_resources, energy_corrections, ) self._evaluate_reduced_potential( forward_system, trajectory, self.forward_potentials_path, available_resources, energy_corrections, )
molAPO = PDBFile(f'{PDB_DIR}/{SEED_PDB}.fab.fixed.pdb') molLIG = PDBFile(f'{PDB_DIR}/{TARGET_CID}.pdb') molSMI = Chem.MolToSmiles( molPROBE, isomericSmiles=True, allBondsExplicit=True) model = Modeller(molAPO.topology, molAPO.getPositions()) model.add(molLIG.topology, molLIG.getPositions()) with open('holo.pdb', 'w+') as outfile: PDBFile.writeFile(model.topology, model.getPositions(), outfile) """ Parameterize the holo-complex """ GAFFForceField = GAFFTemplateGenerator.INSTALLED_FORCEFIELDS[-1] GAFFTemplate = GAFFTemplateGenerator(forcefield=GAFFForceField) GAFFTemplate.add_molecules( Molecule.from_smiles(molSMI, allow_undefined_stereo=True)) forcefield = app.ForceField('amber14/protein.ff14SB.xml') forcefield.registerTemplateGenerator(GAFFTemplate.generator) system00 = forcefield.createSystem(model.topology) """ Minimize the holo-complex """ holo = app.PDBFile('holo.pdb') integrator = LangevinIntegrator( LANGE_TEMPERATURE, LANGE_FRICTION, LANGE_STEPSIZE) integrator.setConstraintTolerance(LANGE_TOLERANCE) simulation = Simulation(holo.topology, system00, integrator) simulation.context.setPositions(holo.getPositions()) simulation.minimizeEnergy(ENERGY_TOLERANCE, MAX_ENERGY_ITERS)
def _generate_residue_name(residue, smiles): """Generates residue name for a particular residue which corresponds to a particular smiles pattern. Where possible (i.e for amino acids and ions) a standard residue name will be returned, otherwise a random name will be used. Parameters ---------- residue: mdtraj.core.topology.Residue The residue to assign the name to. smiles: str The SMILES pattern to generate a resiude name for. """ from mdtraj.core import residue_names from openforcefield.topology import Molecule # Define the set of residue names which should be discarded # if randomly generated as they have a reserved meaning. # noinspection PyProtectedMember forbidden_residue_names = [ *residue_names._AMINO_ACID_CODES, *residue_names._SOLVENT_TYPES, *residue_names._WATER_RESIDUES, "ADE", "CYT", "CYX", "DAD", "DGU", "FOR", "GUA", "HID", "HIE", "HIH", "HSD", "HSH", "HSP", "NMA", "THY", "URA", ] amino_residue_mappings = { "C[C@H](N)C(=O)O": "ALA", "N=C(N)NCCC[C@H](N)C(=O)O": "ARG", "NC(=O)C[C@H](N)C(=O)O": "ASN", "N[C@@H](CC(=O)O)C(=O)O": "ASP", "N[C@@H](CS)C(=O)O": "CYS", "N[C@@H](CCC(=O)O)C(=O)O": "GLU", "NC(=O)CC[C@H](N)C(=O)O": "GLN", "NCC(=O)O": "GLY", "N[C@@H](Cc1c[nH]cn1)C(=O)O": "HIS", "CC[C@H](C)[C@H](N)C(=O)O": "ILE", "CC(C)C[C@H](N)C(=O)O": "LEU", "NCCCC[C@H](N)C(=O)O": "LYS", "CSCC[C@H](N)C(=O)O": "MET", "N[C@@H](Cc1ccccc1)C(=O)O": "PHE", "O=C(O)[C@@H]1CCCN1": "PRO", "N[C@@H](CO)C(=O)O": "SER", "C[C@@H](O)[C@H](N)C(=O)O": "THR", "N[C@@H](Cc1c[nH]c2ccccc12)C(=O)O": "TRP", "N[C@@H](Cc1ccc(O)cc1)C(=O)O": "TYR", "CC(C)[C@H](N)C(=O)O": "VAL", } standardized_smiles = Component(smiles=smiles).smiles # Check for amino acids. if standardized_smiles in amino_residue_mappings: residue.name = amino_residue_mappings[standardized_smiles] return # Check for water if standardized_smiles == "O": residue.name = "HOH" # Re-assign the water atom names. These need to be set to get # correct CONECT statements. h_counter = 1 for atom in residue.atoms: if atom.element.symbol == "O": atom.name = "O1" else: atom.name = f"H{h_counter}" h_counter += 1 return # Check for ions openff_molecule = Molecule.from_smiles(smiles, allow_undefined_stereo=True) if openff_molecule.n_atoms == 1: residue.name = _ion_residue_name(openff_molecule) residue.atom(0).name = residue.name return # Randomly generate a name random_residue_name = "".join( [random.choice(string.ascii_uppercase) for _ in range(3)]) while random_residue_name in forbidden_residue_names: # Re-choose the residue name until we find a safe one. random_residue_name = "".join( [random.choice(string.ascii_uppercase) for _ in range(3)]) residue.name = random_residue_name # Assign unique atom names. element_counter = defaultdict(int) for atom in residue.atoms: atom.name = f"{atom.element.symbol}{element_counter[atom.element.symbol] + 1}" element_counter[atom.element.symbol] += 1
def _execute(self, directory, available_resources): from openforcefield.topology import Molecule, Topology force_field_source = ForceFieldSource.from_json(self.force_field_path) cutoff = pint_quantity_to_openmm(force_field_source.cutoff) # Load in the systems topology openmm_pdb_file = app.PDBFile(self.coordinate_file_path) # Create an OFF topology for better insight into the layout of the system # topology. unique_molecules = {} for component in self.substance: unique_molecule = Molecule.from_smiles(component.smiles) unique_molecules[unique_molecule.to_smiles()] = unique_molecule # Parameterize each component in the system. system_templates = {} for index, (smiles, unique_molecule) in enumerate(unique_molecules.items()): if smiles in ["O", "[H]O[H]", "[H][O][H]"]: component_system = self._build_tip3p_system( cutoff, openmm_pdb_file.topology.getUnitCellDimensions(), ) else: component_directory = os.path.join(directory, str(index)) os.makedirs(component_directory, exist_ok=True) with temporarily_change_directory(component_directory): component_system = self._parameterize_molecule( unique_molecule, force_field_source, cutoff) system_templates[smiles] = component_system # Apply the parameters to the topology. topology = Topology.from_openmm(openmm_pdb_file.topology, unique_molecules.values()) # Create the full system object from the component templates. system = self._create_empty_system(cutoff) for topology_molecule in topology.topology_molecules: smiles = topology_molecule.reference_molecule.to_smiles() system_template = system_templates[smiles] index_map = {} for index, topology_atom in enumerate(topology_molecule.atoms): index_map[topology_atom.atom.molecule_particle_index] = index # Append the component template to the full system. self._append_system(system, system_template, index_map) if openmm_pdb_file.topology.getPeriodicBoxVectors() is not None: system.setDefaultPeriodicBoxVectors( *openmm_pdb_file.topology.getPeriodicBoxVectors()) # Serialize the system object. self.system_path = os.path.join(directory, "system.xml") with open(self.system_path, "w") as file: file.write(openmm.XmlSerializer.serialize(system))