Example #1
0
    def getBoxVectors(self, asNumpy=False):
        """Get the periodic box vectors.

        Parameters:
         - asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
         """
        if asNumpy:
            if self._numpyBoxVectors is None:
                self._numpyBoxVectors = []
                self._numpyBoxVectors.append(
                    Quantity(
                        numpy.array(
                            self.boxVectors[0].value_in_unit(nanometers)),
                        nanometers))
                self._numpyBoxVectors.append(
                    Quantity(
                        numpy.array(
                            self.boxVectors[1].value_in_unit(nanometers)),
                        nanometers))
                self._numpyBoxVectors.append(
                    Quantity(
                        numpy.array(
                            self.boxVectors[2].value_in_unit(nanometers)),
                        nanometers))
            return self._numpyBoxVectors
        return self.boxVectors
Example #2
0
    def __init__(
        self,
        sigma: unit.Quantity,
        point: unit.Quantity,
        radius: unit.Quantity,
        atom_idx: int,
        active_at: int = -1,
    ):
        """
        Flat well restraint that becomes active when atom moves outside of radius.
        Parameters
        ----------
        sigma : float, unit'd
        point : np.array, unit'd
        radius : float, unit'd
        atom_idx : list
            list of atoms idxs
        active_at : int
            Integer to indicccate at which state the restraint is fully active. Either 0 (for
            lambda 0), or 1 (for lambda 1) or -1 (always active)
        """

        assert type(sigma) == unit.Quantity
        assert type(point) == unit.Quantity
        super().__init__(sigma, point.value_in_unit(unit.angstrom), active_at)

        self.atom_idx = atom_idx
        self.cutoff_radius = (radius.value_in_unit(unit.angstrom)
                              )  # slightly decrease radius
Example #3
0
    def getBoxVectors(self, asNumpy=False):
        """Get the periodic box vectors.

        Parameters:
         - asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
        """
        if self.boxVectors is None:
            raise AttributeError('Box information not found in %s' % self.file)
        if asNumpy:
            if self._numpyBoxVectors is None:
                self._numpyBoxVectors = []
                self._numpyBoxVectors.append(
                    Quantity(
                        np.array(self.boxVectors[0].value_in_unit(nanometers)),
                        nanometers))
                self._numpyBoxVectors.append(
                    Quantity(
                        np.array(self.boxVectors[1].value_in_unit(nanometers)),
                        nanometers))
                self._numpyBoxVectors.append(
                    Quantity(
                        np.array(self.boxVectors[2].value_in_unit(nanometers)),
                        nanometers))
            return self._numpyBoxVectors
        return self.boxVectors
    def __init__(self,
                 explorer,
                 n_confinements_per_basin=250,
                 md_time_before_quench=Quantity(1.0, u.picoseconds),
                 similarity_threshold=Quantity(0.01, u.angstroms),
                 quench=L_BFGS,
                 md=Langevin):

        from openexplorer import PES, KTN

        self.explorer = explorer

        self.quench = quench(self.explorer)
        self.md = md(self.explorer)

        self.n_confinements_per_basin = n_confinements_per_basin

        self.md_time_before_quench = md_time_before_quench
        md_timestep = self.md.get_parameters()['timestep']
        self.md_steps_before_quench = int(self.md_time_before_quench /
                                          md_timestep)
        self.similarity_threshold = similarity_threshold

        self.pes = PES(self.explorer.topology,
                       self.explorer.context.getSystem())
        self.ktn = KTN(self.explorer.topology,
                       self.explorer.context.getSystem())

        self.reset()
Example #5
0
def get_graph(collection, record_name):
    # get record and trajectory
    record = collection.get_record(record_name, specification="default")
    entry = collection.get_entry(record_name)
    from openff.toolkit.topology import Molecule

    mol = Molecule.from_qcschema(entry)

    try:
        trajectory = record.get_trajectory()
    except:
        return None

    if trajectory is None:
        return None

    g = esp.Graph(mol)

    # energy is already hartree
    g.nodes["g"].data["u_ref"] = torch.tensor(
        [
            Quantity(
                snapshot.properties.scf_total_energy,
                esp.units.HARTREE_PER_PARTICLE,
            ).value_in_unit(esp.units.ENERGY_UNIT) for snapshot in trajectory
        ],
        dtype=torch.get_default_dtype(),
    )[None, :]

    g.nodes["n1"].data["xyz"] = torch.tensor(
        np.stack(
            [
                Quantity(
                    snapshot.get_molecule().geometry,
                    unit.bohr,
                ).value_in_unit(esp.units.DISTANCE_UNIT)
                for snapshot in trajectory
            ],
            axis=1,
        ),
        requires_grad=True,
        dtype=torch.get_default_dtype(),
    )

    g.nodes["n1"].data["u_ref_prime"] = torch.stack(
        [
            torch.tensor(
                Quantity(
                    snapshot.dict()["return_result"],
                    esp.units.HARTREE_PER_PARTICLE / unit.bohr,
                ).value_in_unit(esp.units.FORCE_UNIT),
                dtype=torch.get_default_dtype(),
            ) for snapshot in trajectory
        ],
        dim=1,
    )

    return g
Example #6
0
    def set_parameters(self, tolerance=Quantity(1.0, u.kilojoules_per_mole),
            initial_step_size=Quantity(0.01, u.angstroms)):

        if not self._initialized:
            self._initialize()

        self._tolerance = tolerance.in_units_of(u.kilojoules_per_mole)
        self._initial_step_size = initial_step_size.in_units_of(u.nanometers)
        self._integrator.setGlobalVariableByName('step_size', self._initial_step_size._value)
Example #7
0
def h5_to_dataset(df):
    def get_smiles(x):
        try:
            return x["offmol"].to_smiles()
        except:
            return np.nan

    df["smiles"] = df.apply(get_smiles, axis=1)
    df = df.dropna()
    groups = df.groupby("smiles")
    gs = []
    for name, group in groups:
        mol_ref = group["offmol"][0]
        assert all(mol_ref == entry for entry in group["offmol"])
        g = esp.Graph(mol_ref)

        u_ref = np.concatenate(group["energies"].values)
        u_ref_prime = np.concatenate(group["gradients"].values,
                                     axis=0).transpose(1, 0, 2)
        xyz = np.concatenate(group["xyz"].values, axis=0).transpose(1, 0, 2)

        assert u_ref_prime.shape[0] == xyz.shape[0] == mol_ref.n_atoms
        assert u_ref.shape[0] == u_ref_prime.shape[1] == xyz.shape[1]

        # energy is already hartree
        g.nodes["g"].data["u_ref"] = torch.tensor(
            Quantity(u_ref, esp.units.HARTREE_PER_PARTICLE).value_in_unit(
                esp.units.ENERGY_UNIT),
            dtype=torch.get_default_dtype(),
        )[None, :]

        g.nodes["n1"].data["xyz"] = torch.tensor(
            Quantity(
                xyz,
                unit.bohr,
            ).value_in_unit(esp.units.DISTANCE_UNIT),
            requires_grad=True,
            dtype=torch.get_default_dtype(),
        )

        g.nodes["n1"].data["u_ref_prime"] = torch.tensor(
            Quantity(
                u_ref_prime,
                esp.units.HARTREE_PER_PARTICLE / unit.bohr,
            ).value_in_unit(esp.units.FORCE_UNIT),
            dtype=torch.get_default_dtype(),
        )

        gs.append(g)

    return esp.data.dataset.GraphDataset(gs)
Example #8
0
File: runner.py Project: cing/meld
    def get_energy(self, state):
        # set the coordinates
        coordinates = Quantity(state.positions, angstrom)

        # set the box vectors
        self._simulation.context.setPositions(coordinates)
        if self._options.solvation == "explicit":
            box_vector = state.box_vector / 10.  # Angstrom to nm
            self._simulation.context.setPeriodicBoxVectors(
                [box_vector[0], 0., 0.],
                [0., box_vector[1], 0.],
                [0., 0., box_vector[2]],
            )

        # get the energy
        snapshot = self._simulation.context.getState(
            getPositions=True, getVelocities=True, getEnergy=True
        )
        snapshot = self._simulation.context.getState(getEnergy=True)
        e_potential = snapshot.getPotentialEnergy()
        e_potential = (
            e_potential.value_in_unit(kilojoule / mole)
            / GAS_CONSTANT
            / self._temperature
        )
        return e_potential
Example #9
0
 def to_python(self):
     """Casts string args to ints, floats, bool..."""
     for i in self:
         if i.val == '':
             i.val = None
         elif i.name == "HR_K_PARAM":  # Workaround for complex unit
             i.val = Quantity(
                 float(i.val),
                 simtk.unit.kilojoule_per_mole / simtk.unit.nanometer**2)
         elif i.type == str:
             continue
         elif i.type == int:
             i.val = int(i.val)
         elif i.type == float:
             i.val = float(i.val)
         elif i.type == bool:
             if i.val.lower() in ['true', '1', 'y', 'yes']:
                 i.val = True
             elif i.val.lower() in ['false', '0', 'n', 'no']:
                 i.val = False
             else:
                 raise ValueError(f"Can't convert {i.val} into bool type.")
         elif i.type == Quantity:
             try:
                 i.val = self.parse_quantity(i.val)
             except AttributeError:
                 raise ValueError(f"Can't parse: {i.name} = {i.val}")
         else:
             raise ValueError(f"Can't parse: {i.name} = {i.val}")
Example #10
0
def periodic_box_vectors_from_xml(xmlfile):
    """Extracts periodic box vectors from OpenMM XML state file.

    Box vectors are returned in the format expected by the box vector setting
    function of OpenMM's topology.
    """

    # parse XML file:
    tree = et.parse(xmlfile)
    root = tree.getroot()

    # name of box vector field in XML file:
    pbv = "PeriodicBoxVectors"

    # box vectors need to be tuple of tuples:
    box_vectors = tuple([
        tuple([float(x) for x in root.find(pbv).find("A").attrib.values()]),
        tuple([float(x) for x in root.find(pbv).find("B").attrib.values()]),
        tuple([float(x) for x in root.find(pbv).find("C").attrib.values()])
    ])

    # add units:
    box_vectors = Quantity(box_vectors, nanometer)

    # return dimensions to caller:
    return (box_vectors)
Example #11
0
    def compute_energy(self, param, offset, platform=None):
        """ Computes energy for a given structure with a given parameter set

        Parameters
        ----------
        param: chemistry.charmm.CharmmParameterSet
        platform: simtk.openmm.Platform to evaluate energy on (if None, will select automatically)
        """
        # Create Context.
        integrator = mm.VerletIntegrator(0.004 * u.picoseconds)
        system = self.structure.createSystem(param)
        if platform != None:
            context = mm.Context(system, integrator, platform)
        else:
            context = mm.Context(system, integrator)

        # Compute potential energies for all snapshots.
        self.mm_energy = Quantity(value=np.zeros([self.n_frames], np.float64), unit=kilojoules_per_mole)
        for i in range(self.n_frames):
            context.setPositions(self.openmm_positions(i))
            state = context.getState(getEnergy=True)
            self.mm_energy[i] = state.getPotentialEnergy()

        # Subtract off minimum of mm_energy
        self.mm_energy -= self.mm_energy.min() + Quantity(value=float(offset.value), unit=kilojoules_per_mole)
        self.delta_energy = self.qm_energy - self.mm_energy

        # Compute deviation between MM and QM energies with offset
        # self.delta_energy = mm_energy - self.qm_energy + Quantity(value=offset, unit=kilojoule_per_mole)

        # Clean up.
        del context
        del system
        del integrator
Example #12
0
    def compute_energy(self, param, offset, platform=None,):
        """ Computes energy for a given structure with a given parameter set

        Parameters
        ----------
        param: parmed.charmm.CharmmParameterSet
        platform: simtk.openmm.Platform to evaluate energy on (if None, will select automatically)
        """

        if self.n_frames == 0:
            raise Exception("self.n_frames = 0! There are no frames to compute energy for.")

        # Check if context exists.
        if not self.context:
            self.create_context(param, platform)
        else:
            # copy new torsion parameters
            self.copy_torsions()

        # Compute potential energies for all snapshots.
        self.mm_energy = Quantity(value=np.zeros([self.n_frames], np.float64), unit=kilojoules_per_mole)
        for i in range(self.n_frames):
            self.context.setPositions(self.positions[i])
            state = self.context.getState(getEnergy=True)
            self.mm_energy[i] = state.getPotentialEnergy()

        # Subtract off minimum of mm_energy and add offset
        min_energy = self.mm_energy.min()
        self.mm_energy -= min_energy
        self.mm_energy += offset
        self.delta_energy = (self.qm_energy - self.mm_energy)
Example #13
0
    def compute_energy(self, param, offset=None, platform=None):
        """ Computes energy for a given structure with a given parameter set

        Parameters
        ----------
        param: parmed.charmm.CharmmParameterSet
        platform: simtk.openmm.Platform to evaluate energy on (if None, will select automatically)
        """

        # Save initial mm energy
        save = False
        if not self._have_mm_energy:
            save = True

        # calculate energy
        super(QMDataBase, self).compute_energy(param, platform)

        # Subtract off minimum of mm_energy and add offset
        energy_unit = kilojoules_per_mole

        min_energy = self.mm_energy.min()
        self.mm_energy -= min_energy
        if save:
            self.initial_mm = deepcopy(self.mm_energy)
        if offset:
            offset = Quantity(value=offset.value, unit=energy_unit)
            self.mm_energy += offset
        self.delta_energy = (self.qm_energy - self.mm_energy)
Example #14
0
    def compute_energy(self, param, platform=None):
        """ Computes energy for a given structure with a given parameter set

        Parameters
        ----------
        offset :
        param: parmed.charmm.CharmmParameterSet
        platform: simtk.openmm.Platform to evaluate energy on (if None, will select automatically)
        """

        if self.n_frames == 0:
            raise Exception(
                "self.n_frames = 0! There are no frames to compute energy for."
            )

        # Check if context exists.
        if not self.context:
            self.create_context(param, platform)
        else:
            # copy new torsion parameters
            self.copy_torsions(param, platform)

        # Compute potential energies for all snapshots.
        self.mm_energy = Quantity(value=np.zeros([self.n_frames], np.float64),
                                  unit=kilojoules_per_mole)
        for i in range(self.n_frames):
            self.context.setPositions(self.positions[i])
            state = self.context.getState(getEnergy=True)
            self.mm_energy[i] = state.getPotentialEnergy()
Example #15
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
Example #16
0
    def calculate_energy(
        self,
        coordinate_list: unit.Quantity,
        lambda_value: float = 0.0,
        original_neural_network: bool = True,
        requires_grad_wrt_coordinates: bool = True,
        requires_grad_wrt_parameters: bool = True,
        include_restraint_energy_contribution: bool = True,
    ):
        """
        Given a coordinate set (x) the energy is calculated in kJ/mol.

        Parameters
        ----------
        x : list, [N][K][3] unit'd (distance unit)
            initial configuration
        lambda_value : float
            between 0.0 and 1.0 - at zero contributions of alchemical atoms are zero

        Returns
        -------
        NamedTuple
        """

        assert type(coordinate_list) == unit.Quantity
        assert 0.0 <= float(lambda_value) <= 1.0
        logger.debug(
            f"Including restraints: {include_restraint_energy_contribution}")

        logger.debug(f"Batch-size: {len(coordinate_list)}")

        coordinates = torch.tensor(
            coordinate_list.value_in_unit(unit.nanometer),
            requires_grad=requires_grad_wrt_coordinates,
            device=self.device,
            dtype=torch.float32,
        )
        logger.debug(f"coordinates tensor: {coordinates.size()}")

        energy_in_kT, restraint_energy_contribution_in_kT = self._calculate_energy(
            coordinates,
            lambda_value,
            original_neural_network,
            include_restraint_energy_contribution,
        )

        energy = np.array([e.item() for e in energy_in_kT]) * kT

        restraint_energy_contribution = (
            np.array([e.item()
                      for e in restraint_energy_contribution_in_kT]) * kT)
        if requires_grad_wrt_parameters:
            return DecomposedEnergy(energy, restraint_energy_contribution,
                                    energy_in_kT)
        else:
            return DecomposedEnergy(energy, restraint_energy_contribution,
                                    energy_in_kT.detach())
Example #17
0
    def set_parameters(self,
                       tolerance=Quantity(1.0, u.kilojoules_per_mole /
                                          u.nanometers),
                       max_iter=0):

        self._tolerance = tolerance.in_units_of(u.kilojoules_per_mole /
                                                u.nanometers)
        self._max_iter = max_iter

        self._initialize()
Example #18
0
    def set_parameters(self,
                       timestep=Quantity(1.0, u.femtoseconds),
                       tolerance=None,
                       alpha=0.1,
                       dt_max=Quantity(10.0, u.femtoseconds),
                       f_inc=1.1,
                       f_dec=0.5,
                       f_alpha=0.99,
                       N_min=5):

        self._timestep = timestep.in_units_of(u.picoseconds)
        self._tolerance = tolerance
        self._alpha = alpha
        self._dt_max = dt_max.in_units_of(u.picoseconds)
        self._f_inc = f_inc
        self._f_dec = f_dec
        self._f_alpha = f_alpha
        self._N_min = N_min

        self._initialize()
Example #19
0
 def __init__(self, positions, topology, structure, torsions, directions, steps, qm_energies):
     """Create new TorsionScanSet object"""
     assert isinstance(topology, object)
     super(TorsionScanSet, self).__init__(positions, topology)
     self.structure = structure
     self.qm_energy = Quantity(value=qm_energies, unit=kilojoules_per_mole)
     self.mm_energy = Quantity()
     self.delta_energy = Quantity()
     self.torsion_index = torsions
     self.direction = directions
     self.steps = steps
Example #20
0
 def parse_quantity(self, val: str) -> Union[Quantity, None]:
     if val == '':
         return None
     match_obj = self.quantity_regexp.match(val)
     value, unit = match_obj.groups()
     try:
         unit = getattr(simtk.unit, unit)
     except AttributeError:
         raise ValueError(
             f"I Can't recognise unit {unit} in expresion {val}. Example of valid quantity: 12.3 femtosecond."
         )
     return Quantity(value=float(value), unit=unit)
Example #21
0
    def set_parameters(self,
                       temperature=Quantity(value=298.0, unit=u.kelvin),
                       collision_rate=Quantity(value=1.0,
                                               unit=1.0 / u.picosecond),
                       timestep=Quantity(value=2.0, unit=u.femtosecond)):

        self._timestep = timestep
        self._temperature = temperature
        self._collision_rate = collision_rate

        if self._initialized:

            self._integrator.setFriction(
                self._collision_rate.value_in_unit(u.picosecond**-1))
            self._integrator.setTemperature(
                self._temperature.value_in_unit(u.kelvin))
            self._integrator.setStepSize(
                self._timestep.value_in_unit(u.picoseconds))

        else:

            self._initialize()
Example #22
0
    def getPositions(self, asNumpy=False):
        """Get the atomic positions.

        Parameters:
         - asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
        """
        if asNumpy:
            if self._numpyPositions is None:
                self._numpyPositions = Quantity(
                    np.array(self.positions.value_in_unit(nanometers)),
                    nanometers)
            return self._numpyPositions
        return self.positions
Example #23
0
 def __init__(self,
              positions,
              topology,
              structure,
              torsions,
              qm_energies,
              angles=None,
              steps=None,
              directions=None,
              optimized=None,
              time=None):
     """Create new TorsionScanSet object"""
     assert isinstance(topology, object)
     super(QMDataBase, self).__init__(positions, topology, structure, time)
     self.qm_energy = Quantity(value=qm_energies, unit=kilojoules_per_mole)
     self.initial_mm = Quantity()
     self.delta_energy = Quantity()
     self.torsion_index = torsions
     self.direction = directions
     self.steps = steps
     self.angles = angles
     self.optimized = optimized
     self.phis = {}
Example #24
0
    def getPositions(self, asNumpy=False, frame=0):
        """Get the atomic positions.

        Parameters:
         - asNumpy (boolean=False) if true, the values are returned as a numpy array instead of a list of Vec3s
         - frame (int=0) the index of the frame for which to get positions
         """
        if asNumpy:
            if self._numpyPositions is None:
                self._numpyPositions = [None]*len(self._positions)
            if self._numpyPositions[frame] is None:
                self._numpyPositions[frame] = Quantity(numpy.array(self._positions[frame].value_in_unit(nanometers)), nanometers)
            return self._numpyPositions[frame]
        return self._positions[frame]
Example #25
0
    def __init__(self,
                 explorer,
                 md_time_before_quench=Quantity(1.0, u.picoseconds),
                 quench=L_BFGS,
                 md=Langevin):

        from openexplorer import PES

        self.explorer = explorer

        self.quench = quench(self.explorer)
        self.md = md(self.explorer)

        self.md.set_parameters(temperature=Quantity(500.0, u.kelvin))

        self.md_time_before_quench = md_time_before_quench
        md_timestep = self.md.get_parameters()['timestep']
        self.md_steps_before_quench = int(self.md_time_before_quench /
                                          md_timestep)

        self.pes = PES(self.explorer.topology,
                       self.explorer.context.getSystem())

        self.reset()
Example #26
0
def sample_velocities(masses: Quantity, temperature: Quantity) -> np.array:
    """Sample Maxwell-Boltzmann velocities ~ N(0, sqrt(kB T / m)"""
    n_particles = len(masses)
    spatial_dim = 3

    v_unscaled = np.random.randn(n_particles, spatial_dim)

    # intended to be consistent with timemachine.integrator:langevin_coefficients
    sigma = np.sqrt(BOLTZ * temperature.value_in_unit(kelvin)) * np.sqrt(
        1 / masses)
    v_scaled = v_unscaled * np.expand_dims(sigma, axis=1)

    assert v_scaled.shape == (n_particles, spatial_dim)

    return v_scaled
Example #27
0
    def getVelocities(self, asNumpy=False):
        """Get the atomic velocities.

        Parameters:
         - asNumpy (boolean=False) if true, the vectors are returned as numpy arrays instead of Vec3s
         """
        if asNumpy:
            if self._numpyVelocities is None:
                self._numpyVelocities = Quantity(
                    numpy.array(
                        self.velocities.value_in_unit(nanometers /
                                                      picoseconds)),
                    nanometers / picoseconds)
            return self._numpyVelocities
        return self.velocities
    def getVelocities(self, asNumpy=False):
        """Get the atomic velocities.

        Parameters
        ----------
        asNumpy : bool=False
            if true, the vectors are returned as numpy arrays instead of Vec3s
        """
        if self.velocities is None:
            raise AttributeError('velocities not found in %s' % self.file)
        if asNumpy:
            if self._numpyVelocities is None:
                self._numpyVelocities = Quantity(np.array(self.velocities.value_in_unit(nanometers/picoseconds)), nanometers/picoseconds)
            return self._numpyVelocities
        return self.velocities
Example #29
0
def _from_omm_quantity(val: simtk_unit.Quantity):
    """Helper function to convert float or array quantities tagged with SimTK/OpenMM units to
    a Pint-compatible quantity"""
    unit_ = val.unit
    val_ = val.value_in_unit(unit_)
    if type(val_) in {float, int}:
        unit_ = val.unit
        return val_ * unit.Unit(str(unit_))
    elif type(val_) in {tuple, list, np.ndarray}:
        array = np.asarray(val_)
        return array * unit.Unit(str(unit_))
    else:
        raise UnitValidationError(
            "Found a simtk.unit.Unit wrapped around something other than a float-like "
            f"or np.ndarray-like. Found a unit wrapped around type {type(val_)}."
        )
Example #30
0
    def baseline_energy(self, g, suffix=None):
        if suffix is None:
            suffix = "_" + self.forcefield

        from openmmforcefields.generators import SystemGenerator

        # define a system generator
        system_generator = SystemGenerator(
            small_molecule_forcefield=self.forcefield, )

        mol = g.mol
        # mol.assign_partial_charges("formal_charge")
        # create system
        system = system_generator.create_system(
            topology=mol.to_topology().to_openmm(),
            molecules=mol,
        )

        # parameterize topology
        topology = g.mol.to_topology().to_openmm()

        integrator = openmm.LangevinIntegrator(TEMPERATURE, COLLISION_RATE,
                                               STEP_SIZE)

        # create simulation
        simulation = Simulation(topology=topology,
                                system=system,
                                integrator=integrator)

        us = []

        xs = (Quantity(
            g.nodes["n1"].data["xyz"].detach().numpy(),
            esp.units.DISTANCE_UNIT,
        ).value_in_unit(unit.nanometer).transpose((1, 0, 2)))

        for x in xs:
            simulation.context.setPositions(x)
            us.append(
                simulation.context.getState(
                    getEnergy=True).getPotentialEnergy().value_in_unit(
                        esp.units.ENERGY_UNIT))

        g.nodes["g"].data["u%s" % suffix] = torch.tensor(us)[None, :]

        return g
Example #31
0
class L_BFGS():

    _explorer = None
    _initialized = False

    _tolerance = Quantity(1.0, u.kilojoules_per_mole / u.nanometers)
    _max_iter = 0

    def __init__(self, explorer):

        self._explorer = explorer

    def _initialize(self):

        self._initialized = True

    def set_parameters(self,
                       tolerance=Quantity(1.0, u.kilojoules_per_mole /
                                          u.nanometers),
                       max_iter=0):

        self._tolerance = tolerance.in_units_of(u.kilojoules_per_mole /
                                                u.nanometers)
        self._max_iter = max_iter

        self._initialize()

    def replicate_parameters(self, explorer):

        tolerance = explorer.quench.l_bfgs._tolerance
        max_iter = explorer.quench.l_bfgs._max_iter

        self.set_parameters(tolerance, max_iter)

    def run(self):

        if not self._initialized:

            self._initialize()

        LocalEnergyMinimizer.minimize(self._explorer.context, self._tolerance,
                                      self._max_iter)

    def __call__(self, *args, **kwargs):

        return self.run(*args, **kwargs)
Example #32
0
def deserialize_box_vectors(xmlInput, is_file=True):
    """
    Takes an XML string or file and converts to a 3x3 simtk.unit.Quantity for
    representing parmed or OpenMM box vectors.

    Parameters
    ----------
    xmlInput : str, Required
        The name of the file to read for XML, or, if is_file is False, then 
        read the xmlInput string itself as the XML
        
    is_file : bool, Optional, default: True
        If reading the XML to a file is desired, then enter a valid file path
        and name. If is_file is false, then the xmlInput string is read as
        the XML itself.

    Returns
    -------
    result : simtk.unit.Quantity
        The box vectors in a 3x3 simtk.unit.Quantity object for easy input to
        parmed or OpenMM.
    """
    if is_file:
        tree = ET.parse(xmlInput)
        xmlBox_vectors = tree.getroot()
    else:
        xmlBox_vectors = ET.fromstring(xmlInput)

    assert xmlBox_vectors.text is not None
    xmlA = xmlBox_vectors.find('A')
    xmlAx = float(xmlA.find('x').text)
    xmlAy = float(xmlA.find('y').text)
    xmlAz = float(xmlA.find('z').text)
    xmlB = xmlBox_vectors.find('B')
    xmlBx = float(xmlB.find('x').text)
    xmlBy = float(xmlB.find('y').text)
    xmlBz = float(xmlB.find('z').text)
    xmlC = xmlBox_vectors.find('C')
    xmlCx = float(xmlC.find('x').text)
    xmlCy = float(xmlC.find('y').text)
    xmlCz = float(xmlC.find('z').text)
    box_vectors = Quantity(
        [[xmlAx, xmlAy, xmlAz], [xmlBx, xmlBy, xmlBz], [xmlCx, xmlCy, xmlCz]],
        unit=nanometer)
    return box_vectors
Example #33
0
    def __init__(self, positions, topology, structure, time=None):
        """Create new TorsionScanSet object"""
        assert isinstance(topology, object)
        super(DataBase, self).__init__(positions, topology, time)
        self.structure = structure
        self.mm_energy = Quantity()
        self.positions = positions
        self.context = None
        self.system = None
        self.integrator = mm.VerletIntegrator(0.004 * picoseconds)

        # Don't allow an empty TorsionScanSet to be created
        if self.n_frames == 0:
            msg = 'DataBase has no frames!\n'
            msg += '\n'
            msg += 'DataBase provided were:\n'
            msg += str(positions)
            raise Exception(msg)
Example #34
0
    def __init__(self, positions, topology, structure, torsions, directions, steps, qm_energies):
        """Create new TorsionScanSet object"""
        assert isinstance(topology, object)
        super(TorsionScanSet, self).__init__(positions, topology)
        self.structure = structure
        self.qm_energy = Quantity(value=qm_energies, unit=kilojoules_per_mole)
        self.mm_energy = Quantity()
        self.delta_energy = Quantity()
        self.torsion_index = torsions
        self.direction = directions
        self.steps = steps
        self.positions = positions
        self.context = None
        self.system = None
        self.integrator = mm.VerletIntegrator(0.004*u.picoseconds)
        self.energy = np.array

        # Don't allow an empty TorsionScanSet to be created
        if self.n_frames == 0:
            msg = 'TorsionScanSet has no frames!\n'
            msg += '\n'
            msg += 'positions provided were:\n'
            msg += str(positions)
            raise Exception(msg)
Example #35
0
class TorsionScanSet(Trajectory):
    """container object for torsion scan

    A TorsionScanSet should be constructed by loading Gaussian 09 torsion scan log files from disk
    with an mdtraj.Topology object

    Examples
    --------
    >>> torsion_set = read_scan_logfile('../examples/data/pyrrole/torsion-scan/PRL.scan2.neg.log', '../examples/data/pyrrole/pyrrol.psf')
    >>> print(torsion_set)
    <torsions.TorsionScanSet with 40 frames, 22 atoms, 1 residues, without MM Energy>


    Attributes
    ----------
    structure: ParmEd.Structure
    qm_energy: simtk.unit.Quantity((n_frames), unit=kilojoule/mole)
    mm_energy: simtk.unit.Quantity((n_frames), unit=kilojoule/mole)
    delta_energy: simtk.unit.Quantity((n_frames), unit=kilojoule/mole)
    torsion_index: {np.ndarray, shape(n_frames, 4)}
    step: {np.ndarray, shape(n_frame, 3)}
    direction: {np.ndarray, shape(n_frame)}. 0 = negative, 1 = positive
    """

    def __init__(self, positions, topology, structure, torsions, directions, steps, qm_energies):
        """Create new TorsionScanSet object"""
        assert isinstance(topology, object)
        super(TorsionScanSet, self).__init__(positions, topology)
        self.structure = structure
        self.qm_energy = Quantity(value=qm_energies, unit=kilojoules_per_mole)
        self.mm_energy = Quantity()
        self.delta_energy = Quantity()
        self.torsion_index = torsions
        self.direction = directions
        self.steps = steps
        self.positions = positions
        self.context = None
        self.system = None
        self.integrator = mm.VerletIntegrator(0.004*u.picoseconds)
        self.energy = np.array

        # Don't allow an empty TorsionScanSet to be created
        if self.n_frames == 0:
            msg = 'TorsionScanSet has no frames!\n'
            msg += '\n'
            msg += 'positions provided were:\n'
            msg += str(positions)
            raise Exception(msg)

    def create_context(self, param, platform=None):
        self.structure.load_parameters(param, copy_parameters=False)
        self.system = self.structure.createSystem()
        if platform != None:
            self.context = mm.Context(self.system, self.integrator, platform)
        else:
            self.context = mm.Context(self.system, self.integrator)

    def copy_torsions(self):
        forces = {self.system.getForce(i).__class__.__name__: self.system.getForce(i)
                  for i in range(self.system.getNumForces())}
        torsion_force = forces['PeriodicTorsionForce']

        # create new force
        new_torsion_force = self.structure.omm_dihedral_force()
        # copy parameters
        for i in range(new_torsion_force.getNumTorsions()):
            torsion = new_torsion_force.getTorsionParameters(i)
            torsion_force.setTorsionParameters(i, *torsion)
        # update parameters in context
        torsion_force.updateParametersInContext(self.context)

        #clean up
        del new_torsion_force

    def to_dataframe(self):
        """ convert TorsionScanSet to pandas dataframe """

        data = []
        for i in range(self.n_frames):
            if len(self.mm_energy) == self.n_frames and len(self.delta_energy) == self.n_frames:
                data.append((self.torsion_index[i], self.direction[i], self.steps[i], self.qm_energy[i], self.mm_energy[i],
                             self.delta_energy[i]))
            else:
                data.append((self.torsion_index[i], self.direction[i], self.steps[i], self.qm_energy[i], float('nan'), float('nan')))

        torsion_set = pd.DataFrame(data, columns=[ "torsion", "scan_direction", "step_point_total", "QM_energy KJ/mol",
                                                   "MM_energy KJ/mole", "delta KJ/mole"])

        return torsion_set

    def _string_summary_basic(self):
        """Basic summary of TorsionScanSet in string form."""
        energy_str = 'with MM Energy' if self._have_mm_energy else 'without MM Energy'
        value = "torsions.TorsionScanSet with %d frames, %d atoms, %d residues, %s" % (
                     self.n_frames, self.n_atoms, self.n_residues, energy_str)
        return value

    def extract_geom_opt(self):
        key = []
        for i, step in enumerate(self.steps):
            try:
                if step[1] != self.steps[i+1][1]:
                    key.append(i)
            except IndexError:
                key.append(i)
        new_torsionScanSet = self.slice(key)
        return new_torsionScanSet

    def compute_energy(self, param, offset, platform=None,):
        """ Computes energy for a given structure with a given parameter set

        Parameters
        ----------
        param: parmed.charmm.CharmmParameterSet
        platform: simtk.openmm.Platform to evaluate energy on (if None, will select automatically)
        """

        if self.n_frames == 0:
            raise Exception("self.n_frames = 0! There are no frames to compute energy for.")

        # Check if context exists.
        if not self.context:
            self.create_context(param, platform)
        else:
            # copy new torsion parameters
            self.copy_torsions()

        # Compute potential energies for all snapshots.
        self.mm_energy = Quantity(value=np.zeros([self.n_frames], np.float64), unit=kilojoules_per_mole)
        for i in range(self.n_frames):
            self.context.setPositions(self.positions[i])
            state = self.context.getState(getEnergy=True)
            self.mm_energy[i] = state.getPotentialEnergy()

        # Subtract off minimum of mm_energy and add offset
        min_energy = self.mm_energy.min()
        self.mm_energy -= min_energy
        self.mm_energy += offset
        self.delta_energy = (self.qm_energy - self.mm_energy)

        # Compute deviation between MM and QM energies with offset
        #self.delta_energy = mm_energy - self.qm_energy + Quantity(value=offset, unit=kilojoule_per_mole)


    @property
    def _have_mm_energy(self):
        return len(self.mm_energy) is not 0

    # @property
    # def _unique_torsions(self):
    # Not returning the right amount. debug
    #     torsions = []
    #     for i in range(len(self.torsion_index)):
    #         try:
    #             if (self.torsion_index[i] != self.torsion_index[i+1]).all():
    #                 torsions.append(self.torsion_index[i]), torsions.append(self.torsion_index[i+1])
    #         except:
    #             pass
    #     return len(torsions), torsions


    def __getitem__(self, key):
        "Get a slice of this trajectory"
        return self.slice(key)

    def slice(self, key, copy=True):
        """Slice trajectory, by extracting one or more frames into a separate object

        This method can also be called using index bracket notation, i.e
        `traj[1] == traj.slice(1)`

        Parameters
        ----------
        key : {int, np.ndarray, slice}
            The slice to take. Can be either an int, a list of ints, or a slice
            object.
        copy : bool, default=True
            Copy the arrays after slicing. If you set this to false, then if
            you modify a slice, you'll modify the original array since they
            point to the same data.
        """
        xyz = self.xyz[key]
        time = self.time[key]
        torsions = self.torsion_index[key]
        direction = self.direction[key]
        steps = self.steps[key]
        qm_energy = self.qm_energy[key]
        unitcell_lengths, unitcell_angles = None, None
        if self.unitcell_angles is not None:
            unitcell_angles = self.unitcell_angles[key]
        if self.unitcell_lengths is not None:
            unitcell_lengths = self.unitcell_lengths[key]

        if copy:
            xyz = xyz.copy()
            time = time.copy()
            topology = deepcopy(self._topology)
            structure = deepcopy(self.structure)
            torsions = torsions.copy()
            direction = direction.copy()
            steps = steps.copy()
            qm_energy = qm_energy.copy()

            if self.unitcell_angles is not None:
                unitcell_angles = unitcell_angles.copy()
            if self.unitcell_lengths is not None:
                unitcell_lengths = unitcell_lengths.copy()

        newtraj = self.__class__(
            xyz, topology, structure, torsions, direction, steps, qm_energy)

        if self._rmsd_traces is not None:
            newtraj._rmsd_traces = np.array(self._rmsd_traces[key],
                                            ndmin=1, copy=True)
        return newtraj
Example #36
0
class TorsionScanSet(Trajectory):
    """container object for torsion scan

    A TorsionScanSet should be constructed by loading Gaussian 09 torsion scan log files from disk
    with an mdtraj.Topology object

    Examples
    --------
    >>> torsion_set = read_scan_logfile('FRG.scanN.dir.log')
    >>> print torsion_set
    <torsions.TorsionScanSet with 346 frames, 22 atoms, 1 residues, 4 unique torsions without MM Energy at 0x10b099b10>


    Attributes
    ----------
    structure: chemistry.Structure
    qm_energy: simtk.unit.Quantity((n_frames), unit=kilojoule/mole)
    mm_energy: simtk.unit.Quantity((n_frames), unit=kilojoule/mole)
    delta_energy: simtk.unit.Quantity((n_frames), unit=kilojoule/mole)
    torsion_index: {np.ndarray, shape(n_frames, 4)}
    step: {np.ndarray, shape(n_frame, 3)}
    direction: {np.ndarray, shape(n_frame)}. 0 = negative, 1 = positive
    """

    def __init__(self, positions, topology, structure, torsions, directions, steps, qm_energies):
        """Create new TorsionScanSet object"""
        assert isinstance(topology, object)
        super(TorsionScanSet, self).__init__(positions, topology)
        self.structure = structure
        self.qm_energy = Quantity(value=qm_energies, unit=kilojoules_per_mole)
        self.mm_energy = Quantity()
        self.delta_energy = Quantity()
        self.torsion_index = torsions
        self.direction = directions
        self.steps = steps

    def to_dataframe(self):
        """ convert TorsionScanSet to pandas dataframe """

        data = []
        for i in range(self.n_frames):
            if len(self.mm_energy) == self.n_frames and len(self.delta_energy) == self.n_frames:
                data.append(
                    (
                        self.torsion_index[i],
                        self.direction[i],
                        self.steps[i],
                        self.qm_energy[i],
                        self.mm_energy[i],
                        self.delta_energy[i],
                    )
                )
            else:
                data.append(
                    (
                        self.torsion_index[i],
                        self.direction[i],
                        self.steps[i],
                        self.qm_energy[i],
                        float("nan"),
                        float("nan"),
                    )
                )

        torsion_set = pd.DataFrame(
            data,
            columns=[
                "torsion",
                "scan_direction",
                "step_point_total",
                "QM_energy KJ/mol",
                "MM_energy KJ/mole",
                "delta KJ/mole",
            ],
        )

        return torsion_set

    def _string_summary_basic(self):
        """Basic summary of TorsionScanSet in string form."""
        energy_str = "with MM Energy" if self._have_mm_energy else "without MM Energy"
        value = "torsions.TorsionScanSet with %d frames, %d atoms, %d residues,  %s" % (
            self.n_frames,
            self.n_atoms,
            self.n_residues,
            energy_str,
        )
        return value

    def extract_geom_opt(self):
        key = []
        for i, step in enumerate(self.steps):
            try:
                if step[1] != self.steps[i + 1][1]:
                    key.append(i)
            except IndexError:
                key.append(i)
        new_torsionScanSet = self.slice(key)
        return new_torsionScanSet

    def compute_energy(self, param, offset, platform=None):
        """ Computes energy for a given structure with a given parameter set

        Parameters
        ----------
        param: chemistry.charmm.CharmmParameterSet
        platform: simtk.openmm.Platform to evaluate energy on (if None, will select automatically)
        """
        # Create Context.
        integrator = mm.VerletIntegrator(0.004 * u.picoseconds)
        system = self.structure.createSystem(param)
        if platform != None:
            context = mm.Context(system, integrator, platform)
        else:
            context = mm.Context(system, integrator)

        # Compute potential energies for all snapshots.
        self.mm_energy = Quantity(value=np.zeros([self.n_frames], np.float64), unit=kilojoules_per_mole)
        for i in range(self.n_frames):
            context.setPositions(self.openmm_positions(i))
            state = context.getState(getEnergy=True)
            self.mm_energy[i] = state.getPotentialEnergy()

        # Subtract off minimum of mm_energy
        self.mm_energy -= self.mm_energy.min() + Quantity(value=float(offset.value), unit=kilojoules_per_mole)
        self.delta_energy = self.qm_energy - self.mm_energy

        # Compute deviation between MM and QM energies with offset
        # self.delta_energy = mm_energy - self.qm_energy + Quantity(value=offset, unit=kilojoule_per_mole)

        # Clean up.
        del context
        del system
        del integrator
        # print('Heap at end of compute_energy'), hp.heeap()

    @property
    def _have_mm_energy(self):
        return len(self.mm_energy) is not 0

    # @property
    # def _unique_torsions(self):
    # Not returning the right amount. debug
    #     torsions = []
    #     for i in range(len(self.torsion_index)):
    #         try:
    #             if (self.torsion_index[i] != self.torsion_index[i+1]).all():
    #                 torsions.append(self.torsion_index[i]), torsions.append(self.torsion_index[i+1])
    #         except:
    #             pass
    #     return len(torsions), torsions

    def __getitem__(self, key):
        "Get a slice of this trajectory"
        return self.slice(key)

    def slice(self, key, copy=True):
        """Slice trajectory, by extracting one or more frames into a separate object

        This method can also be called using index bracket notation, i.e
        `traj[1] == traj.slice(1)`

        Parameters
        ----------
        key : {int, np.ndarray, slice}
            The slice to take. Can be either an int, a list of ints, or a slice
            object.
        copy : bool, default=True
            Copy the arrays after slicing. If you set this to false, then if
            you modify a slice, you'll modify the original array since they
            point to the same data.
        """
        xyz = self.xyz[key]
        time = self.time[key]
        torsions = self.torsion_index[key]
        direction = self.direction[key]
        steps = self.steps[key]
        qm_energy = self.qm_energy[key]
        unitcell_lengths, unitcell_angles = None, None
        if self.unitcell_angles is not None:
            unitcell_angles = self.unitcell_angles[key]
        if self.unitcell_lengths is not None:
            unitcell_lengths = self.unitcell_lengths[key]

        if copy:
            xyz = xyz.copy()
            time = time.copy()
            topology = deepcopy(self._topology)
            structure = deepcopy(self.structure)
            torsions = torsions.copy()
            direction = direction.copy()
            steps = steps.copy()
            qm_energy = qm_energy.copy()

            if self.unitcell_angles is not None:
                unitcell_angles = unitcell_angles.copy()
            if self.unitcell_lengths is not None:
                unitcell_lengths = unitcell_lengths.copy()

        newtraj = self.__class__(xyz, topology, structure, torsions, direction, steps, qm_energy)

        if self._rmsd_traces is not None:
            newtraj._rmsd_traces = np.array(self._rmsd_traces[key], ndmin=1, copy=True)
        return newtraj