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 #2
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 #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
Example #4
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 #5
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 #6
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 #7
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 #8
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 #9
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 #10
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 #11
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 #12
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 #13
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 #14
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 #15
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 #16
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 #17
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 #18
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 #19
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 #20
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()
    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 #22
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
Example #23
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 #24
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 #25
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 #26
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 #27
0
    def collect_minimum(self,
                        explorer,
                        coordinates=None,
                        potential_energy=None,
                        similarity_criterion='least_rmsd',
                        similarity_threshold=Quantity(0.01, u.angstroms)):

        new_minimum = True
        inherent_structure_index = None

        if similarity_criterion == 'least_rmsd':
            similarity = explorer.distance.least_rmsd
        else:
            raise NotImplementedError

        for minimum_index in reversed(range(self.n_minima)):
            if similarity(self.minima[minimum_index]) < similarity_threshold:
                new_minimum = False
                inherent_structure_index = minimum_index
                break

        if new_minimum:

            if coordinates is None:
                coordinates = explorer.get_coordinates()
            if potential_energy is None:
                potential_energy = explorer.get_potential_energy()

            self.minima.append(coordinates)
            self.potential_energy_minima.append(potential_energy)
            inherent_structure_index = self.n_minima
            self.basins_network.add_node(inherent_structure_index)
            self.n_minima += 1

            if self.global_minimum_potential_energy > potential_energy:
                self.global_minimum_index = inherent_structure_index
                self.global_minimum_potential_energy = potential_energy

        return inherent_structure_index
Example #28
0
 def _assign_openmm_positions(self, configuration):
     from simtk.unit import Quantity
     positions = Quantity(value=configuration.reshape(-1, _SPATIAL_DIM),
                          unit=self._length_scale)
     self._openmm_context.setPositions(positions)
Example #29
0
    def _run(self, state, minimize):
        assert abs(state.alpha - self._alpha) < 1e-6  # run Monte Carlo
        if minimize:
            state = self._run_min_mc(state)
        else:
            state = self._run_mc(state)

        # add units to coordinates and velocities (we store in Angstrom, openmm
        # uses nm
        coordinates = Quantity(state.positions, angstrom)
        velocities = Quantity(state.velocities, angstrom / picosecond)
        box_vectors = Quantity(state.box_vector, angstrom)

        # set the positions
        self._simulation.context.setPositions(coordinates)

        # if explicit solvent, then set the box vectors
        if self._options.solvation == "explicit":
            self._simulation.context.setPeriodicBoxVectors(
                [box_vectors[0].value_in_unit(nanometer), 0.0, 0.0],
                [0.0, box_vectors[1].value_in_unit(nanometer), 0.0],
                [0.0, 0.0, box_vectors[2].value_in_unit(nanometer)],
            )

        # run energy minimization
        if minimize:
            self._simulation.minimizeEnergy(maxIterations=self._options.minimize_steps)

        # set the velocities
        self._simulation.context.setVelocities(velocities)

        # run timesteps
        self._simulation.step(self._options.timesteps)

        # extract coords, vels, energy and strip units
        if self._options.solvation == "implicit":
            snapshot = self._simulation.context.getState(
                getPositions=True, getVelocities=True, getEnergy=True
            )
        elif self._options.solvation == "explicit":
            snapshot = self._simulation.context.getState(
                getPositions=True,
                getVelocities=True,
                getEnergy=True,
                enforcePeriodicBox=True,
            )
        coordinates = snapshot.getPositions(asNumpy=True).value_in_unit(angstrom)
        velocities = snapshot.getVelocities(asNumpy=True).value_in_unit(
            angstrom / picosecond
        )
        _check_for_nan(coordinates, velocities, self._rank)

        # if explicit solvent, the recover the box vectors
        if self._options.solvation == "explicit":
            box_vector = snapshot.getPeriodicBoxVectors().value_in_unit(angstrom)
            box_vector = np.array(
                (box_vector[0][0], box_vector[1][1], box_vector[2][2])
            )
        # just store zeros for implicit solvent
        else:
            box_vector = np.zeros(3)

        # get the energy
        e_potential = (
            snapshot.getPotentialEnergy().value_in_unit(kilojoule / mole)
            / GAS_CONSTANT
            / self._temperature
        )

        # store in state
        state.positions = coordinates
        state.velocities = velocities
        state.energy = e_potential
        state.box_vector = box_vector

        return state
Example #30
0
class Langevin():

    _explorer = None
    _initialized = False
    _context = None
    _integrator = None

    _timestep = Quantity(value=2.0, unit=u.femtosecond)
    _temperature = Quantity(value=298.0, unit=u.kelvin)
    _collision_rate = Quantity(value=1.0, unit=1.0 / u.picosecond)

    def __init__(self, explorer):

        self._explorer = explorer

    def _initialize(self):

        system = self._explorer.context.getSystem()
        platform = self._explorer.context.getPlatform()
        properties = {}
        if platform.getName() == 'CUDA':
            properties['CudaPrecision'] = 'mixed'

        self._integrator = LangevinIntegrator(self._temperature,
                                              self._collision_rate,
                                              self._timestep)
        self._context = Context(system, self._integrator, platform, properties)
        self._initialized = True

    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()

    def get_parameters(self):

        parameters = {
            'timestep': self._timestep,
            'temperature': self._temperature,
            'collision_rate': self._collision_rate
        }

        return parameters

    def replicate_parameters(self, explorer):

        timestep = explorer.md.langevin._timestep
        temperature = explorer.md.langevin._temperature
        collision_rate = explorer.md.langevin._collision_rate

        self.set_paramters(temperature, collision_rate, timestep)

    def _set_coordinates(self, coordinates):

        self._context.setPositions(coordinates)

    def _get_coordinates(self):

        return self._context.getState(getPositions=True).getPositions(
            asNumpy=True)

    def _set_velocities(self, velocities):

        self._context.setVelocities(velocities)

    def _get_velocities(self):

        return self._context.getState(getVelocities=True).getVelocities(
            asNumpy=True)

    def _coordinates_to_explorer(self):

        self._explorer.set_coordinates(self._get_coordinates())

    def _coordinates_from_explorer(self):

        self._set_coordinates(self._explorer.get_coordinates())

    def _velocities_to_explorer(self):

        self._explorer.set_velocities(self._get_velocities())

    def _velocities_from_explorer(self):

        self._set_velocities(self._explorer.get_velocities())

    def get_time(self):

        return self._context.getState().getTime()

    def run(self, steps=0):

        if not self._initialized:

            self._initialize()

        self._coordinates_from_explorer()
        self._velocities_from_explorer()
        self._integrator.step(steps)
        self._coordinates_to_explorer()
        self._velocities_to_explorer()

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

        return self.run(*args, **kwargs)