def test_simtk_list_of_quantities_to_pint(): """Test conversion from Quantity lists, lists of Quantity""" list_of_quantities = [val * simtk_unit.meter for val in range(10)] quantity_list = simtk_unit.meter * [val for val in range(10)] assert list_of_quantities != quantity_list assert all(from_simtk(list_of_quantities) == from_simtk(quantity_list))
def _convert_periodic_torsion_force(force): # TODO: Can impropers be separated out from a PeriodicTorsionForce? # Maybe by seeing if a quartet is in mol/top.propers or .impropers from openff.interchange.components.smirnoff import SMIRNOFFProperTorsionHandler proper_torsion_handler = SMIRNOFFProperTorsionHandler() n_parametrized_torsions = force.getNumTorsions() for idx in range(n_parametrized_torsions): atom1, atom2, atom3, atom4, per, phase, k = force.getTorsionParameters( idx) # TODO: Process layered torsions top_key = TopologyKey(atom_indices=(atom1, atom2, atom3, atom4), mult=0) while top_key in proper_torsion_handler.slot_map: top_key.mult += 1 pot_key = PotentialKey(id=f"{atom1}-{atom2}-{atom3}-{atom4}", mult=top_key.mult) pot = Potential( parameters={ "periodicity": int(per) * unit.dimensionless, "phase": from_simtk(phase), "k": from_simtk(k), "idivf": 1 * unit.dimensionless, }) proper_torsion_handler.slot_map.update({top_key: pot_key}) proper_torsion_handler.potentials.update({pot_key: pot}) return proper_torsion_handler
def _charge_increment_to_potentials( cls, atom_indices: Tuple[int, ...], parameter: ChargeIncrementModelHandler.ChargeIncrementType, ) -> Tuple[Dict[TopologyKey, PotentialKey], Dict[PotentialKey, Potential]]: """Maps a matched charge increment parameter to a set of potentials.""" matches = {} potentials = {} for i, atom_index in enumerate(atom_indices): topology_key = TopologyKey(atom_indices=(atom_index, )) potential_key = PotentialKey( id=parameter.smirks, mult=i, associated_handler="ChargeIncrementModel") # TODO: Handle the cases where n - 1 charge increments have been defined, # maybe by implementing this in the TK? charge_increment = getattr(parameter, f"charge_increment{i + 1}") potential = Potential( parameters={"charge_increment": from_simtk(charge_increment)}) matches[topology_key] = potential_key potentials[potential_key] = potential return matches, potentials
def _compute_partial_charges(cls, molecule: Molecule, method: str) -> unit.Quantity: """Call out to the toolkit's toolkit wrappers to generate partial charges""" molecule = copy.deepcopy(molecule) molecule.assign_partial_charges(method) return from_simtk(molecule.partial_charges)
def _convert_harmonic_angle_force(force): from openff.interchange.components.smirnoff import SMIRNOFFAngleHandler angle_handler = SMIRNOFFAngleHandler() n_parametrized_angles = force.getNumAngles() for idx in range(n_parametrized_angles): atom1, atom2, atom3, angle, k = force.getAngleParameters(idx) top_key = TopologyKey(atom_indices=(atom1, atom2, atom3)) pot_key = PotentialKey(id=f"{atom1}-{atom2}-{atom3}") pot = Potential(parameters={ "angle": from_simtk(angle), "k": from_simtk(k) }) angle_handler.slot_map.update({top_key: pot_key}) angle_handler.potentials.update({pot_key: pot}) return angle_handler
def _convert_harmonic_bond_force(force): from openff.interchange.components.smirnoff import SMIRNOFFBondHandler bond_handler = SMIRNOFFBondHandler() n_parametrized_bonds = force.getNumBonds() for idx in range(n_parametrized_bonds): atom1, atom2, length, k = force.getBondParameters(idx) top_key = TopologyKey(atom_indices=(atom1, atom2)) pot_key = PotentialKey(id=f"{atom1}-{atom2}") pot = Potential(parameters={ "length": from_simtk(length), "k": from_simtk(k) }) bond_handler.slot_map.update({top_key: pot_key}) bond_handler.potentials.update({pot_key: pot}) return bond_handler
def _convert_nonbonded_force(force): from openff.interchange.components.smirnoff import ( SMIRNOFFElectrostaticsHandler, SMIRNOFFvdWHandler, ) vdw_handler = SMIRNOFFvdWHandler() electrostatics = SMIRNOFFElectrostaticsHandler(method="pme") n_parametrized_particles = force.getNumParticles() for idx in range(n_parametrized_particles): charge, sigma, epsilon = force.getParticleParameters(idx) top_key = TopologyKey(atom_indices=(idx, )) pot_key = PotentialKey(id=f"{idx}") pot = Potential(parameters={ "sigma": from_simtk(sigma), "epsilon": from_simtk(epsilon), }) vdw_handler.slot_map.update({top_key: pot_key}) vdw_handler.potentials.update({pot_key: pot}) electrostatics.slot_map.update({top_key: pot_key}) electrostatics.potentials.update( {pot_key: Potential(parameters={"charge": from_simtk(charge)})}) vdw_handler.cutoff = force.getCutoffDistance() electrostatics.cutoff = force.getCutoffDistance() if force.getNonbondedMethod() == openmm.NonbondedForce.PME: electrostatics.method = "pme" elif force.getNonbondedMethod() in { openmm.NonbondedForce.CutoffPeriodic, openmm.NonbondedForce.CutoffNonPeriodic, }: # TODO: Store reaction-field dielectric electrostatics.method = "reactionfield" elif force.getNonbondedMethod() == openmm.NonbondedForce.NoCutoff: raise Exception("NonbondedMethod NoCutoff is not supported") return vdw_handler, electrostatics
def _library_charge_to_potentials( cls, atom_indices: Tuple[int, ...], parameter: LibraryChargeHandler.LibraryChargeType, ) -> Tuple[Dict[TopologyKey, PotentialKey], Dict[PotentialKey, Potential]]: """Maps a matched library charge parameter to a set of potentials.""" matches = {} potentials = {} for i, (atom_index, charge) in enumerate(zip(atom_indices, parameter.charge)): topology_key = TopologyKey(atom_indices=(atom_index, )) potential_key = PotentialKey(id=parameter.smirks, mult=i, associated_handler="LibraryCharges") potential = Potential(parameters={"charge": from_simtk(charge)}) matches[topology_key] = potential_key potentials[potential_key] = potential return matches, potentials