コード例 #1
0
 def testScalarQuantityConstructor(self):
     """ Tests creating a Quantity using the Quantity constructor """
     self.assertTrue(u.is_quantity(u.Quantity(5, u.centimeters)))
     self.assertTrue(u.is_quantity(u.Quantity(5, u.centimeters**-1)))
     x = u.Quantity(value=5.0, unit=100.0 * u.meters)
     self.assertTrue(u.is_quantity(x))
     self.assertEqual(x, 500 * u.meters)
コード例 #2
0
 def testNumpyDivision(self):
     """ Tests that division of numpy Quantities works correctly """
     x = u.Quantity(np.asarray([1., 2.]), u.nanometers)
     y = u.Quantity(np.asarray([3., 4.]), u.picoseconds)
     xy = x / y
     self.assertTrue(u.is_quantity(xy))
     self.assertEqual(xy.unit, u.nanometers / u.picoseconds)
     self.assertEqual(xy[0].value_in_unit(u.nanometers / u.picoseconds),
                      1 / 3)
     self.assertEqual(xy[1].value_in_unit(u.nanometers / u.picoseconds),
                      0.5)
コード例 #3
0
ファイル: charmmcrdfiles.py プロジェクト: z-gong/openmm
    def _parse(self, fname):

        crdfile = open(fname, 'r')
        readingHeader = True

        while readingHeader:
            line = crdfile.readline()
            if not len(line):
                raise CharmmFileError('Premature end of file')
            line = line.strip()
            words = line.split()
            if len(line) != 0:
                if words[0] == 'ENERGIES' or words[0] == '!ENERGIES':
                    readingHeader = False
                else:
                    self.header.append(line.strip())
            else:
                self.header.append(line.strip())

        for row in range(len(self.header)):
            if len(self.header[row].strip()) != 0:
                line = self.header[row].strip().split()
                if line[0][0:5] == 'NATOM' or line[0][0:6] == '!NATOM':
                    try:
                        line = self.header[row + 1].strip().split()
                        self.natom = int(line[0])
                        self.npriv = int(line[1])  # num. previous steps
                        self.nstep = int(line[2])  # num. steps in file
                        self.nsavc = int(line[3])  # coord save frequency
                        self.nsavv = int(line[4])  # velocities "
                        self.jhstrt = int(line[5])  # Num total steps?
                        break

                    except (ValueError, IndexError) as e:
                        raise CharmmFileError('Problem parsing CHARMM restart')

        self._scan(crdfile, '!XOLD')
        self._get_formatted_crds(crdfile, self.positionsold)

        self._scan(crdfile, '!VX')
        self._get_formatted_crds(crdfile, self.velocities)

        self._scan(crdfile, '!X')
        self._get_formatted_crds(crdfile, self.positions)

        # Convert velocities to angstroms/ps
        self.velocities = [v * ONE_TIMESCALE for v in self.velocities]

        # Add units to positions and velocities
        self.positions = u.Quantity(self.positions, u.angstroms)
        self.positionsold = u.Quantity(self.positionsold, u.angstroms)
        self.velocities = u.Quantity(self.velocities,
                                     u.angstroms / u.picoseconds)
コード例 #4
0
 def testNumpyDeepCopy(self):
     """ Check that deepcopy on numpy array does not strip units """
     x = u.Quantity(np.zeros((2, 3)), u.nanometer)
     y = copy.deepcopy(x)
     self.assertTrue(np.all(x == y))
     self.assertTrue(u.is_quantity(x))
     self.assertTrue(u.is_quantity(y))
コード例 #5
0
 def testDimensionless(self):
     """ Tests the properties of unit.dimensionless """
     x = 5 * u.dimensionless
     y = u.Quantity(5, u.dimensionless)
     self.assertTrue(u.is_quantity(x))
     self.assertTrue(u.is_quantity(y))
     self.assertNotEqual(x, 5)
     self.assertNotEqual(y, 5)
     self.assertEqual(x, y)
     self.assertEqual(x.value_in_unit_system(u.si_unit_system), 5)
     self.assertEqual(x.value_in_unit_system(u.cgs_unit_system), 5)
     self.assertEqual(x.value_in_unit_system(u.md_unit_system), 5)
     x = u.Quantity(1.0, u.dimensionless)
     y = u.Quantity(1.0, u.dimensionless)
     self.assertIsNot(x, y)
     self.assertEqual(x, y)
コード例 #6
0
    def testCollectionQuantityOperations(self):
        """ Tests that Quantity collections behave correctly """
        # Tests that __getitem__ returns a unit
        s = [1, 2, 3, 4] * u.angstroms
        self.assertTrue(u.is_quantity(s[0]))
        for i, val in enumerate(s):
            self.assertTrue(u.is_quantity(val))
            self.assertEqual(val, (i + 1) * u.angstroms)
        # Tests that __setitem__ fails when an incompatible type is added
        def fail(s):
            s[0] = 5

        self.assertRaises(AttributeError, lambda: fail(s))

        def fail(s):
            s[0] = 5 * u.joules

        self.assertRaises(TypeError, lambda: fail(s))

        def fail(s):
            s[0] /= 10 * u.meters

        self.assertRaises(AttributeError, lambda: fail(s))
        # Tests that __setitem__ converts to the unit of the container
        s[0] = 1 * u.nanometers
        self.assertEqual(s[0]._value, 10)
        # Tests that __setitem__ handles slice assignment correctly
        x = [0, 1, 2, 3, 4] * u.kelvin
        x[2:4] = [-2, -3] * u.kelvin
        self.assertEqual(x._value, [0, 1, -2, -3, 4])
        # Tests standard unit conversions
        x = [1, 2, 3] * u.centimeters
        self.assertEqual(x / u.millimeters, [10, 20, 30])
        # Test the construction of a container in which each element is a
        # Quantity, passed to the Quantity constructor
        x = u.Quantity([1 * u.angstrom, 2 * u.nanometer, 3 * u.angstrom])
        self.assertEqual(x._value, [1, 20, 3])
        self.assertEqual(x.unit, u.angstrom)
        x = u.Quantity((1, 2, 3))
        self.assertTrue(u.is_quantity(x))
        self.assertTrue(x.unit.is_dimensionless())
        x = u.Quantity(([1 * u.angstrom, 2 * u.nanometer, 3 * u.angstrom],
                        [1 * u.angstrom, 4 * u.nanometer, 3 * u.angstrom]))
        self.assertEqual(x._value, ([1, 20, 3], [1, 40, 3]))
        self.assertEqual(x.unit, u.angstrom)
        self.assertTrue(u.is_quantity(u.Quantity([])))
コード例 #7
0
 def testReduceUnit(self):
     """ Tests the reduce_unit functionality """
     x = u.nanometer**2 / u.angstrom**2
     self.assertEqual(str(x), 'nanometer**2/(angstrom**2)')
     self.assertTrue(x.is_dimensionless())
     q = u.Quantity(2.0, x)
     self.assertEqual(str(q), '2.0 nm**2/(A**2)')
     self.assertEqual(q.reduce_unit(), 200)
コード例 #8
0
 def testMutableQuantityOperations(self):
     " Tests that mutable Quantity objects do not get unexpectedly changed "
     # This used to be a bug -- t and s._value were the same object, so
     # changing t would also change s silently
     s = [1, 2, 3, 4] * u.angstroms
     t = s / u.angstroms
     self.assertEqual(t, [1, 2, 3, 4])
     self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms))
     t[0] = 2
     self.assertEqual(t, [2, 2, 3, 4])
     self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms))
     t = s.value_in_unit(u.angstroms)
     self.assertEqual(t, [1, 2, 3, 4])
     self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms))
     t[0] = 2
     self.assertEqual(t, [2, 2, 3, 4])
     self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.angstroms))
     s = [1, 2, 3, 4] * u.nanometers
     self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.nanometers))
     t = s.in_units_of(u.nanometers)
     self.assertEqual(s, t)
     t[0] = 1 * u.meters
     self.assertAlmostEqualQuantities(
         t, u.Quantity([1e9, 2, 3, 4], u.nanometers))
     self.assertEqual(s, u.Quantity([1, 2, 3, 4], u.nanometers))
コード例 #9
0
 def testNumpyFunctions(self):
     """ Tests various numpy attributes that they result in Quantities """
     a = u.Quantity(np.arange(10), u.seconds)
     self.assertEqual(a.max(), 9 * u.seconds)
     self.assertEqual(a.min(), 0 * u.seconds)
     self.assertEqual(a.mean(), 4.5 * u.seconds)
     self.assertAlmostEqualQuantities(a.std(),
                                      2.8722813232690143 * u.seconds)
     b = a.reshape((5, 2))
     self.assertTrue(u.is_quantity(b))
コード例 #10
0
    def test_setPositions_units(self):
        n_particles = self.simulation.context.getSystem().getNumParticles()
        input = unit.Quantity(np.random.randn(n_particles, 3), unit.angstroms)
        self.simulation.context.setPositions(input)
        output = self.simulation.context.getState(
            getPositions=True).getPositions(asNumpy=True)

        np.testing.assert_array_almost_equal(
            input.value_in_unit(unit.nanometers),
            output.value_in_unit(unit.nanometers))
コード例 #11
0
ファイル: charmmcrdfiles.py プロジェクト: z-gong/openmm
    def _parse(self, fname):

        with open(fname, 'r') as crdfile:
            line = crdfile.readline()

            while len(line.strip()) == 0:  # Skip whitespace, as a precaution
                line = crdfile.readline()

            intitle = True

            while intitle:
                self.title.append(line.strip())
                line = crdfile.readline()
                if len(line.strip()) == 0:
                    intitle = False
                elif line.strip()[0] != '*':
                    intitle = False
                else:
                    intitle = True

            while len(line.strip()) == 0:  # Skip whitespace
                line = crdfile.readline()

            try:
                self.natom = int(line.strip().split()[0])

                for _ in range(self.natom):
                    line = crdfile.readline().strip().split()
                    self.atomno.append(int(line[0]))
                    self.resno.append(int(line[1]))
                    self.resname.append(line[2])
                    self.attype.append(line[3])
                    pos = Vec3(float(line[4]), float(line[5]), float(line[6]))
                    self.positions.append(pos)
                    self.segid.append(line[7])
                    self.weighting.append(float(line[9]))

                if self.natom != len(self.positions):
                    raise CharmmFileError(
                        "Error parsing CHARMM .crd file: %d "
                        "atoms requires %d positions (not %d)" %
                        (self.natom, self.natom, len(self.positions)))

            except (ValueError, IndexError):
                raise CharmmFileError('Error parsing CHARMM coordinate file')

        # Apply units to the positions now. Do it this way to allow for
        # (possible) numpy functionality in the future.
        self.positions = u.Quantity(self.positions, u.angstroms)
コード例 #12
0
    def get_off_molecule(self,
                         include_conformers: bool = True) -> off.Molecule:
        """Build and openforcefield.topology.Molecule representation of the input molecule.

        Parameters:
            include_conformers: If `True` all of the input conformers are included else they are dropped.
        """

        molecule = self.attributes.to_openff_molecule()
        molecule.name = self.index
        if include_conformers:
            for conformer in self.initial_molecules:
                geometry = unit.Quantity(np.array(conformer.geometry),
                                         unit=unit.bohr)
                molecule.add_conformer(geometry.in_units_of(unit.angstrom))
        return molecule
コード例 #13
0
 def testQuantityMaths(self):
     """ Tests dimensional analysis & maths on and b/w Quantity objects """
     x = 1.3 * u.meters
     y = 75.2 * u.centimeters
     self.assertEqual((x + y) / u.meters, 2.052)
     self.assertEqual((x - y) / u.meters, 0.548)
     self.assertEqual(x / y, 1.3 / 0.752)
     self.assertEqual(x * y, 1.3 * 0.752 * u.meters**2)
     d1 = 2.0 * u.meters
     d2 = 2.0 * u.nanometers
     self.assertEqual(d1 + d2, (2 + 2e-9) * u.meters)
     self.assertAlmostEqual((d2 + d1 - (2e9 + 2) * u.nanometers)._value,
                            0,
                            places=6)
     self.assertEqual(d1 + d1, 4.0 * u.meters)
     self.assertEqual(d1 - d1, 0.0 * u.meters)
     self.assertEqual(d1 / d1, 1.0)
     self.assertEqual(d1 * u.meters, 2.0 * u.meters**2)
     self.assertEqual(u.kilograms * (d1 / u.seconds) * (d1 / u.seconds),
                      4 * u.kilograms * u.meters**2 / u.seconds**2)
     self.assertEqual(u.kilograms * (d1 / u.seconds)**2,
                      4 * u.kilograms * u.meters**2 / u.seconds**2)
     self.assertEqual(d1**3, 8.0 * u.meters**3)
     x = d1**(3 / 2)
     self.assertAlmostEqual(x._value, math.sqrt(2)**3)
     self.assertEqual(x.unit, u.meters**(3 / 2))
     self.assertAlmostEqual((d1**0.5)._value, math.sqrt(2))
     self.assertEqual((d1**0.5).unit, u.meters**0.5)
     comp = (3.0 + 4.0j) * u.meters
     self.assertTrue(u.is_quantity(comp))
     self.assertEqual(comp.unit, u.meters)
     self.assertEqual(str(comp), '(3+4j) m')
     self.assertEqual(comp + comp, (6.0 + 8.0j) * u.meters)
     self.assertEqual(comp - comp, 0 * u.meters)
     self.assertEqual(comp * comp, (3.0 + 4.0j)**2 * u.meters**2)
     self.assertAlmostEqual(comp / comp, 1)
     self.assertAlmostEqual(1.5 * u.nanometers / u.meters,
                            1.5e-9,
                            places=15)
     self.assertEqual((2.3 * u.meters)**2, 2.3**2 * u.meters**2)
     x = 4.3 * u.meters
     self.assertEqual(x / u.centimeters, 430)
     self.assertEqual(str(x / u.seconds), '4.3 m/s')
     self.assertEqual(str(8.4 / (4.2 * u.centimeters)), '2.0 /cm')
     x = 1.2 * u.meters
     self.assertEqual(x * 5, u.Quantity(6.0, u.meters))
コード例 #14
0
    def add_molecule(self, molecule: off.Molecule) -> bool:
        """
        Add a molecule to the molecule list after checking that it is not present already. If it is de-duplicate the
        record and condense the conformers and metadata.

        Args:
            molecule:
                The molecule and its conformers which we should try and add to the result.

        Returns:
            `True` if the molecule is already present and `False` if not.
        """
        # always strip the atom map as it is not preserved in a workflow
        if "atom_map" in molecule.properties:
            del molecule.properties["atom_map"]

        # make a unique molecule hash independent of atom order or conformers
        molecule_hash = molecule.to_inchikey(fixed_hydrogens=True)

        if not self.skip_unique_check and molecule_hash in self._molecules:
            # we need to align the molecules and transfer the coords and properties
            # get the mapping, drop some comparisons to match inchikey
            isomorphic, mapping = off.Molecule.are_isomorphic(
                molecule,
                self._molecules[molecule_hash],
                return_atom_map=True,
                formal_charge_matching=False,
                bond_order_matching=False,
            )
            assert isomorphic is True
            # transfer any torsion indexes for similar fragments
            if "dihedrals" in molecule.properties:
                # we need to transfer the properties; get the current molecule dihedrals indexer
                # if one is missing create a new one
                current_indexer = self._molecules[
                    molecule_hash].properties.get("dihedrals",
                                                  TorsionIndexer())

                # update it with the new molecule info
                current_indexer.update(
                    torsion_indexer=molecule.properties["dihedrals"],
                    reorder_mapping=mapping,
                )

                # store it back
                self._molecules[molecule_hash].properties[
                    "dihedrals"] = current_indexer

            if molecule.n_conformers != 0:

                # transfer the coordinates
                for conformer in molecule.conformers:
                    new_conformer = np.zeros((molecule.n_atoms, 3))
                    for i in range(molecule.n_atoms):
                        new_conformer[i] = conformer[mapping[i]].value_in_unit(
                            unit.angstrom)

                    new_conf = unit.Quantity(value=new_conformer,
                                             unit=unit.angstrom)

                    # check if the conformer is already on the molecule
                    for old_conformer in self._molecules[
                            molecule_hash].conformers:
                        if old_conformer.tolist() == new_conf.tolist():
                            break
                    else:
                        self._molecules[molecule_hash].add_conformer(
                            new_conformer * unit.angstrom)
            else:
                # molecule already in list and coords not present so just return
                return True

        else:
            if molecule.n_conformers == 0:
                # make sure this is a list to avoid errors
                molecule._conformers = []
            self._molecules[molecule_hash] = molecule
            return False
コード例 #15
0
ファイル: md_protocols.py プロジェクト: uibcdf/MolSysMT
def _equil_NPT_OpenMM_protocol_0(topology,
                                 positions,
                                 temperature=300.0 * _unit.kelvin,
                                 pressure=1.0 * _unit.atmosphere,
                                 time=1.0 * _unit.nanosecond,
                                 forcefield=None,
                                 verbose=True,
                                 progress_bar=True):

    import numpy as np
    import openmm.app as app
    import openmm as mm
    from openmmtools.integrators import LangevinIntegrator, GeodesicBAOABIntegrator

    if progress_bar:
        from tqdm import tqdm
    else:

        def tqdm(arg):
            return arg

    #item needs to be openmm.modeller

    forcefield = app.ForceField("amber99sbildn.xml", "tip3p.xml")
    topology = item.topology
    positions = item.positions

    system = forcefield_generator.createSystem(topology,
                                               contraints=app.HBonds,
                                               nonbondedMethod=app.PME,
                                               nonbondedCutoff=1.0 *
                                               _unit.nanometers,
                                               rigidWater=True,
                                               ewaldErrorTolerance=0.0005)

    ## Thermodynamic State
    kB = _unit.BOLTZMANN_CONSTANT_kB * _unit.AVOGADRO_CONSTANT_NA
    temperature = temperature
    pressure = pressure

    ## Barostat
    barostat_frequency = 25  # steps
    barostat = mm.MonteCarloBarostat(pressure, temperature, barostat_frequency)
    system.addForce(barostat)

    ## Integrator
    friction = 1.0 / _unit.picosecond
    step_size = 2.0 * _unit.femtoseconds
    integrator = LangevinIntegrator(temperature, friction, step_size)
    integrator.setConstraintTolerance(0.00001)

    ## Platform
    platform = mm.Platform.getPlatformByName('CUDA')
    properties = {'CudaPrecision': 'mixed'}

    ## Simulation
    simulation = app.Simulation(topology, system, integrator, platform,
                                properties)
    simulation.context.setPositions(positions)
    simulation.context.setVelocitiesToTemperature(temperature)

    time_equilibration = time
    time_iteration = 0.2 * _unit.picoseconds
    number_iterations = int(time_equilibration / time_iteration)
    steps_iteration = int(time_iteration / step_size)
    steps_equilibration = number_iterations * steps_iteration

    ## Reporters

    net_mass, n_degrees_of_freedom = m3t.get(system,
                                             net_mass=True,
                                             n_degrees_of_freedom=True)
    niters = number_iterations
    data = dict()
    data['time'] = _unit.Quantity(np.zeros([niters], np.float64),
                                  _unit.picoseconds)
    data['potential'] = _unit.Quantity(np.zeros([niters], np.float64),
                                       _unit.kilocalories_per_mole)
    data['kinetic'] = _unit.Quantity(np.zeros([niters], np.float64),
                                     _unit.kilocalories_per_mole)
    data['volume'] = _unit.Quantity(np.zeros([niters], np.float64),
                                    _unit.angstroms**3)
    data['density'] = _unit.Quantity(np.zeros([niters], np.float64),
                                     _unit.gram / _unit.centimeters**3)
    data['kinetic_temperature'] = unit.Quantity(np.zeros([niters], np.float64),
                                                _unit.kelvin)

    for iteration in tqdm(range(number_iterations)):
        integrator.step(steps_iteration)
        state = simulation.context.getState(getEnergy=True)
        time = state.getTime()
        potential_energy = state.getPotentialEnergy()
        kinetic_energy = state.getKineticEnergy()
        volume = state.getPeriodicBoxVolume()
        density = (net_mass / volume).in_units_of(unit.gram /
                                                  unit.centimeter**3)
        kinetic_temperature = (2.0 * kinetic_energy /
                               kB / n_degrees_of_freedom).in_units_of(
                                   unit.kelvin)  # (1/2) ndof * kB * T = KE
        data['time'][iteration] = time
        data['potential'] = potential_energy
        data['kinetic'] = kinetic_energy
        data['volume'] = volume
        data['density'] = density
        data['kinetic_temperature'] = kinetic_temperature

    final_state = simulation.context.getState(getPositions=True,
                                              getVelocities=True)
    final_positions = final_state.getPositions()
    final_velocities = final_state.getVelocities()

    return final_positions, final_velocities, data
コード例 #16
0
ファイル: openmm.py プロジェクト: exalearn/QCEngine
    def compute(self, input_model: "AtomicInput",
                config: "TaskConfig") -> "AtomicResult":
        """
        Runs OpenMM on given structure, inputs, in vacuum.
        """
        self.found(raise_error=True)

        try:
            import openmm
            from openmm import unit
        except ImportError:
            from simtk import openmm, unit

        with capture_stdout():
            from openff.toolkit import topology as offtop

        # Failure flag
        ret_data = {"success": False}

        # generate basis, not given
        if not input_model.model.basis:
            raise InputError("Method must contain a basis set.")

        if isinstance(input_model.model.basis, BasisSet):
            raise InputError(
                "QCSchema BasisSet for model.basis not implemented since not suitable for OpenMM."
            )

        # Make sure we are using smirnoff or antechamber
        basis = input_model.model.basis.lower()
        if basis in ["smirnoff", "antechamber"]:

            with capture_stdout():
                # try and make the molecule from the cmiles
                cmiles = None
                if input_model.molecule.extras:
                    cmiles = input_model.molecule.extras.get(
                        "canonical_isomeric_explicit_hydrogen_mapped_smiles",
                        None)
                    if cmiles is None:
                        cmiles = input_model.molecule.extras.get(
                            "cmiles", {}
                        ).get(
                            "canonical_isomeric_explicit_hydrogen_mapped_smiles",
                            None)

                if cmiles is not None:
                    off_mol = offtop.Molecule.from_mapped_smiles(
                        mapped_smiles=cmiles)
                    # add the conformer
                    conformer = unit.Quantity(value=np.array(
                        input_model.molecule.geometry),
                                              unit=unit.bohr)
                    off_mol.add_conformer(conformer)
                else:
                    # Process molecule with RDKit
                    rdkit_mol = RDKitHarness._process_molecule_rdkit(
                        input_model.molecule)

                    # Create an Open Force Field `Molecule` from the RDKit Molecule
                    off_mol = offtop.Molecule(rdkit_mol)

            # now we need to create the system
            openmm_system = self._generate_openmm_system(
                molecule=off_mol,
                method=input_model.model.method,
                keywords=input_model.keywords)
        else:
            raise InputError(
                "Accepted bases are: {'smirnoff', 'antechamber', }")

        # Need an integrator for simulation even if we don't end up using it really
        integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds)

        # Set platform to CPU explicitly
        platform = openmm.Platform.getPlatformByName("CPU")

        # Set number of threads to use
        # if `nthreads` is `None`, OpenMM default of all logical cores on
        # processor will be used
        nthreads = config.ncores
        if nthreads is None:
            nthreads = os.environ.get("OPENMM_CPU_THREADS")

        if nthreads:
            properties = {"Threads": str(nthreads)}
        else:
            properties = {}

        # Initialize context
        context = openmm.Context(openmm_system, integrator, platform,
                                 properties)

        # Set positions from our Open Force Field `Molecule`
        context.setPositions(off_mol.conformers[0])

        # Compute the energy of the configuration
        state = context.getState(getEnergy=True)

        # Get the potential as a unit.Quantity, put into units of hartree
        q = state.getPotentialEnergy(
        ) / unit.hartree / unit.AVOGADRO_CONSTANT_NA

        ret_data["properties"] = {"return_energy": q}

        # Execute driver
        if input_model.driver == "energy":
            ret_data["return_result"] = ret_data["properties"]["return_energy"]

        elif input_model.driver == "gradient":
            # Compute the forces
            state = context.getState(getForces=True)

            # Get the gradient as a unit.Quantity with shape (n_atoms, 3)
            gradient = state.getForces(asNumpy=True)

            # Convert to hartree/bohr and reformat as 1D array
            q = (gradient / (unit.hartree / unit.bohr)
                 ).reshape(-1) / unit.AVOGADRO_CONSTANT_NA

            # Force to gradient
            ret_data["return_result"] = -1 * q
        else:
            raise InputError(
                f"Driver {input_model.driver} not implemented for OpenMM.")

        ret_data["success"] = True
        ret_data["extras"] = input_model.extras

        # Move several pieces up a level
        ret_data["provenance"] = Provenance(
            creator="openmm",
            version=openmm.version.short_version,
            nthreads=nthreads)

        return AtomicResult(**{**input_model.dict(), **ret_data})
コード例 #17
0
 def setUp(self):
     self.data = unit.Quantity(np.arange(300), unit.nanometers)
コード例 #18
0
def test_molecule_and_water_offxml(coumarin, water, tmpdir, rfree_data, parameters):
    """Test that an offxml can parameterize a molecule and water mixture."""

    coumarin_copy = coumarin.copy(deep=True)
    MBISCharges.apply_symmetrisation(coumarin_copy)

    with tmpdir.as_cwd():

        # run the lj method to make sure the parameters match
        alpha = rfree_data.pop("alpha")
        beta = rfree_data.pop("beta")
        lj = LennardJones612(free_parameters=rfree_data, alpha=alpha, beta=beta)
        # get new Rfree data
        lj.run(coumarin_copy)

        # remake rfree
        rfree_data["alpha"] = alpha
        rfree_data["beta"] = beta

        _combine_molecules_offxml(
            molecules=[coumarin_copy],
            parameters=parameters,
            rfree_data=rfree_data,
            filename="combined.offxml",
            water_model="tip3p",
        )

        combinded_ff = ForceField(
            "combined.offxml", load_plugins=True, allow_cosmetic_attributes=True
        )
        mixed_top = Topology.from_molecules(
            molecules=[
                Molecule.from_rdkit(water.to_rdkit()),
                Molecule.from_rdkit(coumarin_copy.to_rdkit()),
            ]
        )
        system = combinded_ff.create_openmm_system(topology=mixed_top)
        # make sure we have 3 constraints
        assert system.getNumConstraints() == 3
        # check each constraint
        reference_constraints = [
            [0, 1, unit.Quantity(0.9572, unit=unit.angstroms)],
            [0, 2, unit.Quantity(0.9572, unit=unit.angstroms)],
            [1, 2, unit.Quantity(1.5139006545247014, unit=unit.angstroms)],
        ]
        for i in range(3):
            a, b, constraint = system.getConstraintParameters(i)
            assert a == reference_constraints[i][0]
            assert b == reference_constraints[i][1]
            assert constraint == reference_constraints[i][2].in_units_of(
                unit.nanometers
            )
        # now loop over the forces and make sure water was correctly parameterised
        forces = dict((force.__class__.__name__, force) for force in system.getForces())
        nonbonded_force: openmm.NonbondedForce = forces["NonbondedForce"]
        # first check water has the correct parameters
        water_reference = [
            [
                unit.Quantity(-0.834, unit.elementary_charge),
                unit.Quantity(3.1507, unit=unit.angstroms),
                unit.Quantity(0.1521, unit=unit.kilocalorie_per_mole),
            ],
            [
                unit.Quantity(0.417, unit.elementary_charge),
                unit.Quantity(1, unit=unit.angstroms),
                unit.Quantity(0, unit=unit.kilocalorie_per_mole),
            ],
            [
                unit.Quantity(0.417, unit.elementary_charge),
                unit.Quantity(1, unit=unit.angstroms),
                unit.Quantity(0, unit=unit.kilocalorie_per_mole),
            ],
        ]
        for i in range(3):
            charge, sigma, epsilon = nonbonded_force.getParticleParameters(i)
            assert charge == water_reference[i][0]
            assert sigma.in_units_of(unit.angstroms) == water_reference[i][1]
            assert (
                epsilon.in_units_of(unit.kilocalorie_per_mole) == water_reference[i][2]
            )

        # now check coumarin
        for i in range(coumarin_copy.n_atoms):
            ref_params = coumarin_copy.NonbondedForce[(i,)]
            charge, sigma, epsilon = nonbonded_force.getParticleParameters(i + 3)
            assert charge.value_in_unit(unit.elementary_charge) == float(
                ref_params.charge
            )
            assert sigma.value_in_unit(unit.nanometers) == ref_params.sigma
            assert epsilon.value_in_unit(unit.kilojoule_per_mole) == ref_params.epsilon
コード例 #19
0
ファイル: test_torchmd.py プロジェクト: torchmd/torchmd
def openmm_energy(prm,
                  structure,
                  coords,
                  box=None,
                  cutoff=None,
                  switch_dist=None):
    from openmm import unit
    from openmm import app
    import openmm
    from parmed.amber import AmberParm

    if box is not None and not np.all(box == 0):
        if cutoff is None:
            raise RuntimeError(
                "You need to provide a cutoff when passing a box")
        a = unit.Quantity(
            (box[0] * unit.angstrom, 0 * unit.angstrom, 0 * unit.angstrom))
        b = unit.Quantity(
            (0 * unit.angstrom, box[1] * unit.angstrom, 0 * unit.angstrom))
        c = unit.Quantity(
            (0 * unit.angstrom, 0 * unit.angstrom, box[2] * unit.angstrom))
        structure.box_vectors = (a, b, c)
        if isinstance(structure, AmberParm):
            system = structure.createSystem(
                nonbondedMethod=app.CutoffPeriodic,
                nonbondedCutoff=0 if cutoff is None else cutoff *
                unit.angstrom,
                switchDistance=0 if switch_dist is None else switch_dist *
                unit.angstrom,
            )
        else:
            system = structure.createSystem(
                prm,
                nonbondedMethod=app.CutoffPeriodic,
                nonbondedCutoff=0 if cutoff is None else cutoff *
                unit.angstrom,
                switchDistance=0 if switch_dist is None else switch_dist *
                unit.angstrom,
            )
        system.setDefaultPeriodicBoxVectors(a, b, c)
    else:
        if isinstance(structure, AmberParm):
            system = structure.createSystem()
        else:
            system = structure.createSystem(prm)

    disableDispersionCorrection(system)
    integrator = openmm.LangevinIntegrator(300 * unit.kelvin,
                                           1 / unit.picoseconds,
                                           2 * unit.femtoseconds)
    try:
        platform = openmm.Platform.getPlatformByName("CUDA")
        properties = {"CudaPrecision": "double"}
    except Exception:
        platform = openmm.Platform.getPlatformByName("CPU")
        properties = {}
    context = openmm.Context(system, integrator, platform, properties)

    # Run OpenMM with given coordinates
    context.setPositions(coords * unit.angstrom)
    energies = parmed.openmm.energy_decomposition(structure, context)
    state = context.getState(getForces=True)
    forces = state.getForces(asNumpy=True).value_in_unit(
        unit.kilocalories_per_mole / unit.angstrom)
    if "angle" not in energies:
        energies["angle"] = 0
    if "dihedral" not in energies:
        energies["dihedral"] = 0
    if "improper" not in energies:
        energies["improper"] = 0

    return energies, forces
コード例 #20
0
 def testNumpyQuantity(self):
     """ Tests that numpy arrays can form Quantity values """
     q = u.Quantity(np.array([1, 2, 3]), u.centimeters)
     self.assertTrue(u.is_quantity(q))
     self.assertIsInstance(q._value, np.ndarray)
     self.assertTrue(np.all(q / u.millimeters == np.array([1, 2, 3]) * 10))
コード例 #21
0
 def testString(self):
     """ Tests unit handling with strings, which should be dimensionless """
     s = u.Quantity("string")
     self.assertEqual(s.value_in_unit_system(u.md_unit_system), "string")
コード例 #22
0
 def testUnaryOperators(self):
     """ Tests unary operators on units """
     self.assertEqual(-(2.3 * u.meters), u.Quantity(-2.3, u.meters))
     self.assertEqual(-(2.3 * u.meters), -u.Quantity(2.3, u.meters))
     self.assertEqual(+(2.3 * u.meters), u.Quantity(2.3, u.meters))
     self.assertEqual(2.3 * u.meters, +u.Quantity(2.3, u.meters))
コード例 #23
0
ファイル: pdbstructure.py プロジェクト: sroet/openmm
    def __init__(self,
                 pdb_line,
                 pdbstructure=None,
                 extraParticleIdentifier='EP'):
        """Create a new pdb.Atom from an ATOM or HETATM line.

        Example line:
        ATOM   2209  CB  TYR A 299       6.167  22.607  20.046  1.00  8.12           C
        00000000011111111112222222222333333333344444444445555555555666666666677777777778
        12345678901234567890123456789012345678901234567890123456789012345678901234567890

        ATOM line format description from
          http://deposit.rcsb.org/adit/docs/pdb_atom_format.html:

        COLUMNS        DATA TYPE       CONTENTS
        --------------------------------------------------------------------------------
         1 -  6        Record name     "ATOM  "
         7 - 11        Integer         Atom serial number.
        13 - 16        Atom            Atom name.
        17             Character       Alternate location indicator.
        18 - 20        Residue name    Residue name.
        22             Character       Chain identifier.
        23 - 26        Integer         Residue sequence number.
        27             AChar           Code for insertion of residues.
        31 - 38        Real(8.3)       Orthogonal coordinates for X in Angstroms.
        39 - 46        Real(8.3)       Orthogonal coordinates for Y in Angstroms.
        47 - 54        Real(8.3)       Orthogonal coordinates for Z in Angstroms.
        55 - 60        Real(6.2)       Occupancy (Default = 1.0).
        61 - 66        Real(6.2)       Temperature factor (Default = 0.0).
        73 - 76        LString(4)      Segment identifier, left-justified.
        77 - 78        LString(2)      Element symbol, right-justified.
        79 - 80        LString(2)      Charge on the atom.

        """
        # We might modify first/final status during _finalize() methods
        self.is_first_atom_in_chain = False
        self.is_final_atom_in_chain = False
        self.is_first_residue_in_chain = False
        self.is_final_residue_in_chain = False
        # Start parsing fields from pdb line
        self.record_name = pdb_line[0:6].strip()
        if pdbstructure is not None and pdbstructure._atom_numbers_are_hex:
            self.serial_number = int(pdb_line[6:11], 16)
        else:
            try:
                self.serial_number = int(pdb_line[6:11])
            except:
                try:
                    self.serial_number = int(pdb_line[6:11], 16)
                    pdbstructure._atom_numbers_are_hex = True
                except:
                    # Just give it the next number in sequence.
                    self.serial_number = pdbstructure._next_atom_number
        self.name_with_spaces = pdb_line[12:16]
        alternate_location_indicator = pdb_line[16]

        self.residue_name_with_spaces = pdb_line[17:20]
        # In some MD codes, notably ffamber in gromacs, residue name has a fourth character in
        # column 21
        possible_fourth_character = pdb_line[20:21]
        if possible_fourth_character != " ":
            # Fourth character should only be there if official 3 are already full
            if len(self.residue_name_with_spaces.strip()) != 3:
                raise ValueError('Misaligned residue name: %s' % pdb_line)
            self.residue_name_with_spaces += possible_fourth_character
        self.residue_name = self.residue_name_with_spaces.strip()

        self.chain_id = pdb_line[21]
        if pdbstructure is not None and pdbstructure._residue_numbers_are_hex:
            self.residue_number = int(pdb_line[22:26], 16)
        else:
            try:
                self.residue_number = int(pdb_line[22:26])
            except:
                try:
                    self.residue_number = int(pdb_line[22:26], 16)
                    pdbstructure._residue_numbers_are_hex = True
                except:
                    # When VMD runs out of hex values it starts filling the residue ID field with ****.
                    # Look at the most recent atoms to figure out whether this is a new residue or not.
                    if pdbstructure._current_model is None or pdbstructure._current_model._current_chain is None or pdbstructure._current_model._current_chain._current_residue is None:
                        # This is the first residue in the model.
                        self.residue_number = pdbstructure._next_residue_number
                    else:
                        currentRes = pdbstructure._current_model._current_chain._current_residue
                        if currentRes.name_with_spaces != self.residue_name_with_spaces:
                            # The residue name has changed.
                            self.residue_number = pdbstructure._next_residue_number
                        elif self.name_with_spaces in currentRes.atoms_by_name:
                            # There is already an atom with this name.
                            self.residue_number = pdbstructure._next_residue_number
                        else:
                            self.residue_number = currentRes.number
        self.insertion_code = pdb_line[26]
        # coordinates, occupancy, and temperature factor belong in Atom.Location object
        x = float(pdb_line[30:38])
        y = float(pdb_line[38:46])
        z = float(pdb_line[46:54])
        try:
            occupancy = float(pdb_line[54:60])
        except:
            occupancy = 1.0
        try:
            temperature_factor = unit.Quantity(float(pdb_line[60:66]),
                                               unit.angstroms**2)
        except:
            temperature_factor = unit.Quantity(0.0, unit.angstroms**2)
        self.locations = {}
        loc = Atom.Location(alternate_location_indicator,
                            unit.Quantity(Vec3(x, y, z),
                                          unit.angstroms), occupancy,
                            temperature_factor, self.residue_name_with_spaces)
        self.locations[alternate_location_indicator] = loc
        self.default_location_id = alternate_location_indicator
        # segment id, element_symbol, and formal_charge are not always present
        self.segment_id = pdb_line[72:76].strip()
        self.element_symbol = pdb_line[76:78].strip()
        try:
            self.formal_charge = int(pdb_line[78:80])
        except ValueError:
            self.formal_charge = None
        # figure out atom element
        if self.element_symbol == extraParticleIdentifier:
            self.element = 'EP'
        else:
            try:
                # Try to find a sensible element symbol from columns 76-77
                self.element = element.get_by_symbol(self.element_symbol)
            except KeyError:
                self.element = None
        if pdbstructure is not None:
            pdbstructure._next_atom_number = self.serial_number + 1
            pdbstructure._next_residue_number = self.residue_number + 1
コード例 #24
0
def _combine_molecules_offxml(
    molecules: List["Ligand"],
    parameters: List[str],
    rfree_data: Dict[str, Dict[str, Union[str, float]]],
    filename: str,
    water_model: Literal["tip3p"] = "tip3p",
):
    """
    Main worker function to build the combined offxmls.
    """

    if sum([molecule.extra_sites.n_sites for molecule in molecules]) > 0:
        raise NotImplementedError(
            "Virtual sites can not be safely converted into offxml format yet."
        )

    if sum([molecule.RBTorsionForce.n_parameters for molecule in molecules]) > 0:
        raise NotImplementedError(
            "RBTorsions can not yet be safely converted into offxml format yet."
        )

    try:
        from chemper.graphs.cluster_graph import ClusterGraph
    except ModuleNotFoundError:
        raise ModuleNotFoundError(
            "chemper is required to make an offxml, please install with `conda install chemper -c conda-forge`."
        )

    fit_ab = False
    # if alpha and beta should be fit
    if "AB" in parameters:
        fit_ab = True

    rfree_codes = set()  # keep track of all rfree codes used by these molecules
    # create the master ff
    offxml = ForceField(allow_cosmetic_attributes=True, load_plugins=True)
    offxml.author = f"QUBEKit_version_{qubekit.__version__}"
    offxml.date = datetime.now().strftime("%Y_%m_%d")
    # get all of the handlers
    _ = offxml.get_parameter_handler("Constraints")
    bond_handler = offxml.get_parameter_handler("Bonds")
    angle_handler = offxml.get_parameter_handler("Angles")
    proper_torsions = offxml.get_parameter_handler("ProperTorsions")
    improper_torsions = offxml.get_parameter_handler("ImproperTorsions")
    _ = offxml.get_parameter_handler(
        "Electrostatics", handler_kwargs={"scale14": 0.8333333333, "version": 0.3}
    )
    using_plugin = False
    if parameters:
        # if we want to optimise the Rfree we need our custom handler
        vdw_handler = offxml.get_parameter_handler(
            "QUBEKitvdWTS", allow_cosmetic_attributes=True
        )
        using_plugin = True
    else:
        vdw_handler = offxml.get_parameter_handler(
            "vdW", allow_cosmetic_attributes=True
        )
    library_charges = offxml.get_parameter_handler("LibraryCharges")

    for molecule in molecules:
        rdkit_mol = molecule.to_rdkit()
        bond_types = molecule.bond_types
        # for each bond type collection create a single smirks pattern
        for bonds in bond_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol], smirks_atoms_lists=[bonds], layers="all"
            )
            qube_bond = molecule.BondForce[bonds[0]]
            bond_handler.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "length": qube_bond.length * unit.nanometers,
                    "k": qube_bond.k * unit.kilojoule_per_mole / unit.nanometers**2,
                }
            )

        angle_types = molecule.angle_types
        for angles in angle_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol],
                smirks_atoms_lists=[angles],
                layers="all",
            )
            qube_angle = molecule.AngleForce[angles[0]]
            angle_handler.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "angle": qube_angle.angle * unit.radian,
                    "k": qube_angle.k * unit.kilojoule_per_mole / unit.radians**2,
                }
            )

        torsion_types = molecule.dihedral_types
        for dihedrals in torsion_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol],
                smirks_atoms_lists=[dihedrals],
                layers="all",
            )
            qube_dihedral = molecule.TorsionForce[dihedrals[0]]
            proper_torsions.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "k1": qube_dihedral.k1 * unit.kilojoule_per_mole,
                    "k2": qube_dihedral.k2 * unit.kilojoule_per_mole,
                    "k3": qube_dihedral.k3 * unit.kilojoule_per_mole,
                    "k4": qube_dihedral.k4 * unit.kilojoule_per_mole,
                    "periodicity1": qube_dihedral.periodicity1,
                    "periodicity2": qube_dihedral.periodicity2,
                    "periodicity3": qube_dihedral.periodicity3,
                    "periodicity4": qube_dihedral.periodicity4,
                    "phase1": qube_dihedral.phase1 * unit.radians,
                    "phase2": qube_dihedral.phase2 * unit.radians,
                    "phase3": qube_dihedral.phase3 * unit.radians,
                    "phase4": qube_dihedral.phase4 * unit.radians,
                    "idivf1": 1,
                    "idivf2": 1,
                    "idivf3": 1,
                    "idivf4": 1,
                }
            )

        improper_types = molecule.improper_types
        for torsions in improper_types.values():
            impropers = [
                (improper[1], improper[0], *improper[2:]) for improper in torsions
            ]
            graph = ClusterGraph(
                mols=[rdkit_mol], smirks_atoms_lists=[impropers], layers="all"
            )
            qube_improper = molecule.ImproperTorsionForce[torsions[0]]
            # we need to multiply each k value by as they will be applied as trefoil see
            # <https://openforcefield.github.io/standards/standards/smirnoff/#impropertorsions> for more details
            # we assume we only have a k2 term for improper torsions via a periodic term
            improper_torsions.add_parameter(
                parameter_kwargs={
                    "smirks": graph.as_smirks(),
                    "k1": qube_improper.k2 * 3 * unit.kilojoule_per_mole,
                    "periodicity1": qube_improper.periodicity2,
                    "phase1": qube_improper.phase2 * unit.radians,
                }
            )

        atom_types = {}
        for atom_index, cip_type in molecule.atom_types.items():
            atom_types.setdefault(cip_type, []).append((atom_index,))
        for sym_set in atom_types.values():
            graph = ClusterGraph(
                mols=[rdkit_mol], smirks_atoms_lists=[sym_set], layers="all"
            )
            qube_non_bond = molecule.NonbondedForce[sym_set[0]]
            rfree_code = _get_parameter_code(
                molecule=molecule, atom_index=sym_set[0][0]
            )
            atom_data = {
                "smirks": graph.as_smirks(),
            }

            if rfree_code in parameters or fit_ab:
                # keep track of present codes to optimise
                rfree_codes.add(rfree_code)
            if using_plugin:
                # this is to be refit
                atom = molecule.atoms[qube_non_bond.atoms[0]]
                atom_data["volume"] = atom.aim.volume * unit.angstroms**3
            else:
                atom_data["epsilon"] = qube_non_bond.epsilon * unit.kilojoule_per_mole
                atom_data["sigma"] = qube_non_bond.sigma * unit.nanometers

            vdw_handler.add_parameter(parameter_kwargs=atom_data)

        charge_data = dict(
            (f"charge{param.atoms[0] + 1}", param.charge * unit.elementary_charge)
            for param in molecule.NonbondedForce
        )
        charge_data["smirks"] = molecule.to_smiles(mapped=True)
        library_charges.add_parameter(parameter_kwargs=charge_data)

    # now loop over all the parameters to be fit and add them as cosmetic attributes
    to_parameterize = []
    for parameter_to_fit in parameters:
        if parameter_to_fit != "AB" and parameter_to_fit in rfree_codes:
            setattr(
                vdw_handler,
                f"{parameter_to_fit.lower()}free",
                unit.Quantity(
                    rfree_data[parameter_to_fit]["r_free"], unit=unit.angstroms
                ),
            )
            to_parameterize.append(f"{parameter_to_fit.lower()}free")
    if fit_ab:
        vdw_handler.alpha = rfree_data["alpha"]
        vdw_handler.beta = rfree_data["beta"]
        to_parameterize.extend(["alpha", "beta"])
    if to_parameterize:
        vdw_handler.add_cosmetic_attribute("parameterize", ", ".join(to_parameterize))

    # now add a water model to the force field
    _add_water_model(
        force_field=offxml, water_model=water_model, using_plugin=using_plugin
    )
    offxml.to_file(filename=filename)