def _execute(self, directory, available_resources): from openforcefield.topology import Molecule, Topology pdb_file = app.PDBFile(self.coordinate_file_path) force_field_source = ForceFieldSource.from_json(self.force_field_path) if not isinstance(force_field_source, SmirnoffForceFieldSource): raise ValueError( "Only SMIRNOFF force fields are supported by this protocol.") force_field = force_field_source.to_force_field() unique_molecules = [] charged_molecules = [] if self.apply_known_charges: charged_molecules = self._generate_known_charged_molecules() # Load in any additional, user specified charged molecules. for charged_molecule_path in self.charged_molecule_paths: charged_molecule = Molecule.from_file(charged_molecule_path, "MOL2") charged_molecules.append(charged_molecule) for component in self.substance.components: molecule = Molecule.from_smiles(smiles=component.smiles) if molecule is None: raise ValueError( f"{component} could not be converted to a Molecule") unique_molecules.append(molecule) topology = Topology.from_openmm(pdb_file.topology, unique_molecules=unique_molecules) if len(charged_molecules) > 0: system = force_field.create_openmm_system( topology, charge_from_molecules=charged_molecules) else: system = force_field.create_openmm_system(topology) if system is None: raise RuntimeError( "Failed to create a system from the specified topology and molecules." ) system_xml = openmm.XmlSerializer.serialize(system) self.system_path = os.path.join(directory, "system.xml") with open(self.system_path, "w") as file: file.write(system_xml)
def _execute(self, directory, available_resources): force_field_source = ForceFieldSource.from_json(self.force_field_path) if not isinstance(force_field_source, TLeapForceFieldSource): raise ValueError( "Only TLeap force field sources are supported by this protocol." ) super(BuildTLeapSystem, self)._execute(directory, available_resources)
def _execute(self, directory, available_resources): with open(self.force_field_path) as file: force_field_source = ForceFieldSource.parse_json(file.read()) if not isinstance(force_field_source, LigParGenForceFieldSource): raise ValueError( "Only LigParGen force field sources are supported by this protocol." ) super(BuildLigParGenSystem, self)._execute(directory, available_resources) with open(self.system_path) as file: system = openmm.XmlSerializer.deserialize(file.read()) # Apply the OPLS mixing rules. self._apply_opls_mixing_rules(system) with open(self.system_path, "w") as file: file.write(openmm.XmlSerializer.serialize(system))
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))
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, )
def _find_relevant_gradient_keys(substance, force_field_path, parameter_gradient_keys): """Extract only those keys which may be applied to the given substance. Parameters ---------- substance: Substance The substance to compare against. force_field_path: str The path to the force field which contains the parameters. parameter_gradient_keys: list of ParameterGradientKey The original list of parameter gradient keys. Returns ------- list of ParameterGradientKey The filtered list of parameter gradient keys. """ from openforcefield.topology import Molecule, Topology # noinspection PyTypeChecker if parameter_gradient_keys == UNDEFINED or len( parameter_gradient_keys) == 0: return [] with open(force_field_path) as file: force_field_source = ForceFieldSource.parse_json(file.read()) if not isinstance(force_field_source, SmirnoffForceFieldSource): return [] force_field = force_field_source.to_force_field() all_molecules = [] for component in substance.components: all_molecules.append(Molecule.from_smiles(component.smiles)) topology = Topology.from_molecules(all_molecules) labelled_molecules = force_field.label_molecules(topology) reduced_parameter_keys = [] for labelled_molecule in labelled_molecules: for parameter_key in parameter_gradient_keys: if (parameter_key.tag not in labelled_molecule or parameter_key in reduced_parameter_keys): continue contains_parameter = False for parameter in labelled_molecule[ parameter_key.tag].store.values(): if parameter.smirks != parameter_key.smirks: continue contains_parameter = True break if not contains_parameter: continue reduced_parameter_keys.append(parameter_key) return reduced_parameter_keys