diff --git a/devtools/conda-envs/beta_rc_env.yaml b/devtools/conda-envs/beta_rc_env.yaml index e391e89c2..ece29d13c 100644 --- a/devtools/conda-envs/beta_rc_env.yaml +++ b/devtools/conda-envs/beta_rc_env.yaml @@ -18,7 +18,7 @@ dependencies: - openmm >=7.6 - openff-forcefields >=2023.05.1 - smirnoff99Frosst - - openff-units >=0.2 + - openff-units =0.2.0 - openff-utilities >=0.1.5 - openff-interchange-base >=0.2 - openff-nagl >=0.2.2 diff --git a/devtools/conda-envs/openeye-examples.yaml b/devtools/conda-envs/openeye-examples.yaml index aaccedbc6..c60a9662d 100644 --- a/devtools/conda-envs/openeye-examples.yaml +++ b/devtools/conda-envs/openeye-examples.yaml @@ -17,7 +17,7 @@ dependencies: - openff-forcefields >=2023.05.1 - smirnoff99Frosst - openff-amber-ff-ports >=0.0.3 - - openff-units >=0.2 + - openff-units =0.2.0 - openff-utilities >=0.1.5 - openff-interchange-base >=0.3.3 - openff-nagl >=0.2.2 diff --git a/devtools/conda-envs/openeye.yaml b/devtools/conda-envs/openeye.yaml index 5ac0190a8..634e2f95f 100644 --- a/devtools/conda-envs/openeye.yaml +++ b/devtools/conda-envs/openeye.yaml @@ -16,7 +16,7 @@ dependencies: - openmm >=7.6 - openff-forcefields >=2023.05.1 - smirnoff99Frosst - - openff-units >=0.2 + - openff-units =0.2.0 - openff-utilities >=0.1.5 - openff-interchange-base >=0.3.3 - openff-nagl >=0.2.2 diff --git a/devtools/conda-envs/rdkit-examples.yaml b/devtools/conda-envs/rdkit-examples.yaml index 108fbab89..cf6462b29 100644 --- a/devtools/conda-envs/rdkit-examples.yaml +++ b/devtools/conda-envs/rdkit-examples.yaml @@ -16,7 +16,7 @@ dependencies: - openff-forcefields >=2023.05.1 - smirnoff99Frosst - openff-amber-ff-ports >=0.0.3 - - openff-units >=0.2 + - openff-units =0.2.0 - openff-utilities >=0.1.5 - openff-interchange-base >=0.3.3 - openff-nagl >=0.2.2 diff --git a/devtools/conda-envs/rdkit.yaml b/devtools/conda-envs/rdkit.yaml index e1bb69332..7cc89c878 100644 --- a/devtools/conda-envs/rdkit.yaml +++ b/devtools/conda-envs/rdkit.yaml @@ -15,7 +15,7 @@ dependencies: - openmm >=7.6 - openff-forcefields >=2023.05.1 - smirnoff99Frosst - - openff-units >=0.2 + - openff-units =0.2.0 - openff-utilities >=0.1.5 - openff-interchange-base >=0.3.3 - openff-nagl >=0.2.2 diff --git a/devtools/conda-envs/test_env.yaml b/devtools/conda-envs/test_env.yaml index 40b39c82c..34761c073 100644 --- a/devtools/conda-envs/test_env.yaml +++ b/devtools/conda-envs/test_env.yaml @@ -16,7 +16,7 @@ dependencies: - openmm >=7.6 - openff-forcefields >=2023.05.1 - smirnoff99Frosst - - openff-units >=0.2 + - openff-units =0.2.0 - openff-utilities >=0.1.5 - openff-interchange-base >=0.3.3 - openff-nagl >=0.2.2 diff --git a/docs/releasehistory.md b/docs/releasehistory.md index 68427e608..1615f82e0 100644 --- a/docs/releasehistory.md +++ b/docs/releasehistory.md @@ -6,21 +6,15 @@ Releases follow the `major.minor.micro` scheme recommended by [PEP440](https://w * `minor` increments add features but do not break API compatibility * `micro` increments represent bugfix releases or improvements in documentation -## Current development - -### Behavior changes +## 0.13.2 ### Bugfixes - [PR #1640](https://github.com/openforcefield/openff-toolkit/pull/1640): Fixes issue [#1633](https://github.com/openforcefield/openff-toolkit/issues/1633) in which some force field attributes were erroneously parsed as `Quantity` objects and issue [#1635](https://github.com/openforcefield/openff-toolkit/issues/1635) in which OpenFF 2.1.0 ("Sage") could not be loaded with Pint 0.22. -### New features ### Improved documentation and warnings -- [PR #1636](https://github.com/openforcefield/openff-toolkit/pull/1636): Make the Molecule Cookbook only pull down QCF records with fully defined stereo. - - -### Examples updates +- [PR #1636](https://github.com/openforcefield/openff-toolkit/pull/1636) and [PR #1643](https://github.com/openforcefield/openff-toolkit/pull/1643): Make the Molecule Cookbook and `Molecule.from_qcschema` docstring only pull down QCF records with fully defined stereo. ## 0.13.1 diff --git a/openff/toolkit/tests/mocking.py b/openff/toolkit/tests/mocking.py index 8f9215b85..f1c3610bd 100644 --- a/openff/toolkit/tests/mocking.py +++ b/openff/toolkit/tests/mocking.py @@ -1,5 +1,5 @@ import numpy -from openff.units import unit +from openff.units import Quantity, unit from openff.toolkit.topology import Molecule from openff.toolkit.typing.engines.smirnoff import VirtualSiteHandler @@ -7,8 +7,8 @@ class VirtualSiteMocking: @staticmethod - def sp1_conformer() -> unit.Quantity: - return unit.Quantity( + def sp1_conformer() -> Quantity: + return Quantity( numpy.array( [ [-2.0, +0.0, +0.0], @@ -21,8 +21,8 @@ def sp1_conformer() -> unit.Quantity: ) @staticmethod - def sp2_conformer() -> unit.Quantity: - return unit.Quantity( + def sp2_conformer() -> Quantity: + return Quantity( numpy.array( [ [+1.0, +0.0, +0.0], @@ -35,12 +35,12 @@ def sp2_conformer() -> unit.Quantity: ) @staticmethod - def sp3_conformer() -> unit.Quantity: + def sp3_conformer() -> Quantity: """Returns the conformer of a dummy tetrahedral molecule with the first atom positioned at (0, 1, 0), the second atom at (0, 0, 0) and the remaining atoms at the corners of the tetrahedron. """ - return unit.Quantity( + return Quantity( numpy.array( [ [+0.0, +1.0, +0.0], @@ -61,7 +61,7 @@ def bond_charge_parameter( type="BondCharge", smirks=smirks, name=name, - charge_increment=unit.Quantity( + charge_increment=Quantity( [0.1 * param_multiple, 0.2 * param_multiple], unit.elementary_charge, ), @@ -93,7 +93,7 @@ def divalent_parameter( smirks: str, match: str, name: str = "EP", - angle: unit.Quantity = 0.0 * unit.degree, + angle: Quantity = 0.0 * unit.degree, ) -> VirtualSiteHandler.VirtualSiteType: return VirtualSiteHandler.VirtualSiteType( type="DivalentLonePair", diff --git a/openff/toolkit/tests/test_toolkit_io.py b/openff/toolkit/tests/test_toolkit_io.py index 23d8005e1..27efb2c04 100644 --- a/openff/toolkit/tests/test_toolkit_io.py +++ b/openff/toolkit/tests/test_toolkit_io.py @@ -12,7 +12,7 @@ import numpy as np import pytest from numpy.testing import assert_allclose -from openff.units import unit +from openff.units import Quantity, unit from openff.toolkit.tests import create_molecules from openff.toolkit.tests.utils import requires_openeye, requires_rdkit @@ -72,7 +72,7 @@ $$$$ """ -CAFFEINE_2D_COORDS = unit.Quantity( +CAFFEINE_2D_COORDS = Quantity( np.array( [ (-1.1875, -9.6542, 0.0000), @@ -277,7 +277,7 @@ $$$$ """ -CAFFEINE_3D_COORDS = unit.Quantity( +CAFFEINE_3D_COORDS = Quantity( np.array( [ (0.4700, 2.5688, 0.0006), diff --git a/openff/toolkit/tests/test_toolkits.py b/openff/toolkit/tests/test_toolkits.py index 0112bb01d..e7f667382 100644 --- a/openff/toolkit/tests/test_toolkits.py +++ b/openff/toolkit/tests/test_toolkits.py @@ -12,7 +12,7 @@ import numpy as np import pytest from numpy.testing import assert_almost_equal -from openff.units import unit +from openff.units import Quantity, unit from openff.toolkit.tests.create_molecules import ( create_acetaldehyde, @@ -261,9 +261,9 @@ def formic_acid_molecule() -> Molecule: @pytest.fixture() -def formic_acid_conformers() -> Dict[str, unit.Quantity]: +def formic_acid_conformers() -> Dict[str, Quantity]: return { - "cis": unit.Quantity( + "cis": Quantity( np.array( [ [-0.95927322, -0.91789997, 0.36333418], @@ -275,7 +275,7 @@ def formic_acid_conformers() -> Dict[str, unit.Quantity]: ), unit.angstrom, ), - "trans": unit.Quantity( + "trans": Quantity( np.array( [ [-0.95927322, -0.91789997, 0.36333418], @@ -382,7 +382,7 @@ def test_to_from_openeye_core_props_filled(self): # Populate core molecule property fields molecule.name = "Alice" - partial_charges = unit.Quantity( + partial_charges = Quantity( np.array( [ -0.9, @@ -408,7 +408,7 @@ def test_to_from_openeye_core_props_filled(self): unit.elementary_charge, ) molecule.partial_charges = partial_charges - coords = unit.Quantity( + coords = Quantity( np.array( [ ["0.0", "1.0", "2.0"], @@ -584,7 +584,7 @@ def test_to_from_openeye_none_partial_charges(self): def test_to_openeye_typed_partial_charges(self): ethanol = create_ethanol() - ethanol.partial_charges = unit.Quantity( + ethanol.partial_charges = Quantity( np.zeros(ethanol.n_atoms, dtype=int), unit.elementary_charge ) oemol = ethanol.to_openeye() @@ -973,7 +973,7 @@ def test_write_pdb_preserving_atom_order(self): water.add_bond(0, 1, 1, False) water.add_bond(1, 2, 1, False) water.add_conformer( - unit.Quantity( + Quantity( np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), unit.angstrom, ) @@ -1150,7 +1150,7 @@ def test_write_multiconformer_mol_as_sdf(self): toolkit_wrapper = OpenEyeToolkitWrapper() filename = get_data_file_path("molecules/ethanol.sdf") ethanol = Molecule.from_file(filename, toolkit_registry=toolkit_wrapper) - ethanol.partial_charges = unit.Quantity( + ethanol.partial_charges = Quantity( np.array([-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0]), unit.elementary_charge, ) @@ -1217,7 +1217,7 @@ def test_get_mol2_charges(self): molecule = Molecule.from_file(filename, toolkit_registry=toolkit_wrapper) assert len(molecule.conformers) == 1 assert molecule.conformers[0].shape == (15, 3) - target_charges = unit.Quantity( + target_charges = Quantity( np.array( [ -0.1342, @@ -1349,7 +1349,7 @@ def test_apply_elf_conformer_selection(self): initial_conformers = [ # Add a conformer with an internal H-bond. - unit.Quantity( + Quantity( np.array( [ [0.5477, 0.3297, -0.0621], @@ -1366,7 +1366,7 @@ def test_apply_elf_conformer_selection(self): unit.angstrom, ), # Add a conformer without an internal H-bond. - unit.Quantity( + Quantity( np.array( [ [0.5477, 0.3297, -0.0621], @@ -2271,7 +2271,7 @@ def test_to_from_rdkit_core_props_filled(self): # Populate core molecule property fields molecule.name = "Alice" - partial_charges = unit.Quantity( + partial_charges = Quantity( np.array( [ -0.9, @@ -2297,7 +2297,7 @@ def test_to_from_rdkit_core_props_filled(self): unit.elementary_charge, ) molecule.partial_charges = partial_charges - coords = unit.Quantity( + coords = Quantity( np.array( [ ["0.0", "1.0", "2.0"], @@ -2749,7 +2749,7 @@ def test_write_multiconformer_mol_as_sdf(self): toolkit_wrapper = RDKitToolkitWrapper() filename = get_data_file_path("molecules/ethanol.sdf") ethanol = Molecule.from_file(filename, toolkit_registry=toolkit_wrapper) - ethanol.partial_charges = unit.Quantity( + ethanol.partial_charges = Quantity( np.array([-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0]), unit.elementary_charge, ) @@ -3042,7 +3042,7 @@ def test_elf_select_diverse_conformers( self, formic_acid_molecule: Molecule, expected_conformer_map: Dict[int, int], - rms_tolerance: unit.Quantity, + rms_tolerance: Quantity, ): """Test the greedy selection of 'diverse' ELF conformers.""" @@ -3077,7 +3077,7 @@ def test_apply_elf_conformer_selection(self): initial_conformers = [ # Add a conformer with an internal H-bond. - unit.Quantity( + Quantity( np.array( [ [0.5477, 0.3297, -0.0621], @@ -3094,7 +3094,7 @@ def test_apply_elf_conformer_selection(self): unit.angstrom, ), # Add a conformer without an internal H-bond. - unit.Quantity( + Quantity( np.array( [ [0.5477, 0.3297, -0.0621], diff --git a/openff/toolkit/topology/molecule.py b/openff/toolkit/topology/molecule.py index c54386441..56697037c 100644 --- a/openff/toolkit/topology/molecule.py +++ b/openff/toolkit/topology/molecule.py @@ -323,8 +323,8 @@ def formal_charge(self, other): Set the atom's formal charge. Accepts either ints or unit-wrapped ints with units of charge. """ if isinstance(other, int): - self._formal_charge = unit.Quantity(other, unit.elementary_charge) - elif isinstance(other, unit.Quantity): + self._formal_charge = Quantity(other, unit.elementary_charge) + elif isinstance(other, Quantity): # Faster to check equality than convert, so short-circuit if other.units is unit.elementary_charge: self.formal_charge = other @@ -379,14 +379,14 @@ def partial_charge(self, charge): "please raise an issue describing your use case." ) - if not isinstance(charge, (unit.Quantity, float)): + if not isinstance(charge, (Quantity, float)): raise ValueError( "Cannot set partial charge with an object that is not a openff.unit.Quantity or float. " f"Found object of type {type(charge)}." ) if isinstance(charge, float): - charge = unit.Quantity(charge, unit.elementary_charge) + charge = Quantity(charge, unit.elementary_charge) if not isinstance(charge.m, float): raise ValueError( @@ -1251,7 +1251,7 @@ def _initialize_from_dict(self, molecule_dict): else: from openff.toolkit.utils.utils import deserialize_numpy - self._partial_charges = unit.Quantity( + self._partial_charges = Quantity( deserialize_numpy(molecule_dict["partial_charges"], (self.n_atoms,)), unit.Unit(molecule_dict["partial_charge_unit"]), ) @@ -1262,7 +1262,7 @@ def _initialize_from_dict(self, molecule_dict): from openff.toolkit.utils.utils import deserialize_numpy self._conformers = [ - unit.Quantity( + Quantity( deserialize_numpy(ser_conf, (self.n_atoms, 3)), unit.Unit(molecule_dict["conformers_unit"]), ) @@ -2410,7 +2410,7 @@ def dihedral(a): conformers[:, cooh_indices, :] = cooh_xyz # Return conformers to original type - self._conformers = [unit.Quantity(conf, unit.angstrom) for conf in conformers] + self._conformers = [Quantity(conf, unit.angstrom) for conf in conformers] def apply_elf_conformer_selection( self, @@ -3007,7 +3007,7 @@ def _add_conformer(self, coordinates): f"Given {coordinates.shape}, expected {(self.n_atoms, 3)}" ) - if isinstance(coordinates, unit.Quantity): + if isinstance(coordinates, Quantity): if not coordinates.units.is_compatible_with(unit.angstrom): raise IncompatibleUnitError( "Coordinates passed to Molecule._add_conformer with incompatible units. " @@ -3039,7 +3039,7 @@ def _add_conformer(self, coordinates): f"openmm.unit.Quantity and openff.units.unit.Quantity, found type {type(coordinates)}." ) - tmp_conf = unit.Quantity( + tmp_conf = Quantity( np.zeros(shape=(self.n_atoms, 3), dtype=float), unit.angstrom ) try: @@ -3094,7 +3094,7 @@ def partial_charges(self, charges): f"Found shape {charges.shape}, expected {(self.n_atoms,)}" ) - if isinstance(charges, unit.Quantity): + if isinstance(charges, Quantity): if charges.units in unit.elementary_charge.compatible_units(): self._partial_charges = charges.astype(float) else: @@ -4000,7 +4000,7 @@ def from_polymer_pdb( substructure_dictionary, ) - coords = unit.Quantity( + coords = Quantity( np.array( [ [*vec3.value_in_unit(openmm_unit.angstrom)] @@ -4055,7 +4055,7 @@ def _to_xyz_file(self, file_path): # If we do not have a conformer make one with all zeros if self.n_conformers == 0: conformers = [ - unit.Quantity(np.zeros((self.n_atoms, 3), dtype=float), unit.angstrom) + Quantity(np.zeros((self.n_atoms, 3), dtype=float), unit.angstrom) ] else: @@ -4731,7 +4731,7 @@ def from_qcschema( else: mol = molecule - geometry = unit.Quantity( + geometry = Quantity( np.array(mol["geometry"], float).reshape(-1, 3), unit.bohr ) try: diff --git a/openff/toolkit/topology/topology.py b/openff/toolkit/topology/topology.py index a3b0a9b28..be2e7f3a4 100644 --- a/openff/toolkit/topology/topology.py +++ b/openff/toolkit/topology/topology.py @@ -670,7 +670,7 @@ def is_periodic(self, is_periodic): ) @property - def constrained_atom_pairs(self) -> Dict[Tuple[int], Union[unit.Quantity, bool]]: + def constrained_atom_pairs(self) -> Dict[Tuple[int], Union[Quantity, bool]]: """Returns the constrained atom pairs of the Topology Returns @@ -1284,7 +1284,7 @@ def _initialize_from_dict(self, topology_dict): (3, 3), ) box_vectors_unit = getattr(unit, topology_dict["box_vectors_unit"]) - self.box_vectors = unit.Quantity(box_vectors_unitless, box_vectors_unit) + self.box_vectors = Quantity(box_vectors_unitless, box_vectors_unit) for molecule_dict in topology_dict["molecules"]: new_mol = Molecule.from_dict(molecule_dict) @@ -1983,7 +1983,7 @@ def to_file( # Get positions in OpenMM format if isinstance(positions, openmm_unit.Quantity): openmm_positions = positions - elif isinstance(positions, unit.Quantity): + elif isinstance(positions, Quantity): openmm_positions = to_openmm_quantity(positions) elif isinstance(positions, np.ndarray): openmm_positions = openmm_unit.Quantity(positions, openmm_unit.angstroms) @@ -2333,7 +2333,7 @@ def add_constraint(self, iatom, jatom, distance=True): # Check that constraint hasn't already been specified. if (iatom, jatom) in self._constrained_atom_pairs: existing_distance = self._constrained_atom_pairs[(iatom, jatom)] - if isinstance(existing_distance, unit.Quantity) and distance is True: + if isinstance(existing_distance, Quantity) and distance is True: raise ConstraintExsistsError( f"Atoms ({iatom},{jatom}) already constrained with distance {existing_distance} " "but attempting to override with unspecified distance" diff --git a/openff/toolkit/typing/engines/smirnoff/forcefield.py b/openff/toolkit/typing/engines/smirnoff/forcefield.py index 901688b9a..c971f899f 100644 --- a/openff/toolkit/typing/engines/smirnoff/forcefield.py +++ b/openff/toolkit/typing/engines/smirnoff/forcefield.py @@ -56,7 +56,7 @@ if TYPE_CHECKING: import openmm - from openff.units import unit + from openff.units import Quantity from openff.toolkit.topology import Molecule, Topology from openff.toolkit.utils.base_wrapper import ToolkitWrapper @@ -1342,7 +1342,7 @@ def _get_parameter_handler_class(self, tagname): raise KeyError(msg) return ph_class - def get_partial_charges(self, molecule: "Molecule", **kwargs) -> "unit.Quantity": + def get_partial_charges(self, molecule: "Molecule", **kwargs) -> "Quantity": """Generate the partial charges for the given molecule in this force field. Parameters @@ -1412,8 +1412,7 @@ def get_partial_charges(self, molecule: "Molecule", **kwargs) -> "unit.Quantity" f"Found {len(top_with_charges.n_molecules)} molecules." ) - for molecule in top_with_charges.molecules: - return molecule.partial_charges + return top_with_charges.molecule(0).partial_charges def __getitem__(self, val): """ diff --git a/openff/toolkit/typing/engines/smirnoff/parameters.py b/openff/toolkit/typing/engines/smirnoff/parameters.py index 062593ed1..b286277ae 100644 --- a/openff/toolkit/typing/engines/smirnoff/parameters.py +++ b/openff/toolkit/typing/engines/smirnoff/parameters.py @@ -71,7 +71,7 @@ ) import numpy as np -from openff.units import unit +from openff.units import Quantity, Unit, unit from packaging.version import Version from openff.toolkit.topology import ImproperDict, TagSortedDict, Topology, ValenceDict @@ -203,11 +203,11 @@ def _value_checker(instance, attr, new_value): return _value_checker -def _validate_units(attr, value: Union[str, unit.Quantity], units: unit.Unit): +def _validate_units(attr, value: Union[str, Quantity], units: Unit): value = object_to_quantity(value) try: - if not units.is_compatible_with(value.units): + if not units.is_compatible_with(value.units): # type: ignore[union-attr] raise IncompatibleUnitError( f"{attr.name}={value} should have units of {units}" ) @@ -338,7 +338,7 @@ class UNDEFINED: def __init__( self, default: Any = UNDEFINED, - unit: Optional[unit.Unit] = None, + unit: Optional[Unit] = None, converter: Optional[Callable] = None, docstring: str = "", ): @@ -3309,7 +3309,7 @@ class GBSAType(ParameterType): solute_dielectric = ParameterAttribute(default=1, converter=float) sa_model = ParameterAttribute(default="ACE", converter=_allow_only(["ACE", None])) surface_area_penalty = ParameterAttribute( - default=unit.Quantity(5.4, _cal_mol_a2), + default=Quantity(5.4, _cal_mol_a2), unit=_cal_mol_a2, ) solvent_radius = ParameterAttribute(default=1.4 * unit.angstrom, unit=unit.angstrom) diff --git a/openff/toolkit/utils/_nagl_wrapper.py b/openff/toolkit/utils/_nagl_wrapper.py index 111b849db..f1014c147 100644 --- a/openff/toolkit/utils/_nagl_wrapper.py +++ b/openff/toolkit/utils/_nagl_wrapper.py @@ -2,14 +2,12 @@ import warnings from typing import TYPE_CHECKING, List, Optional, Type -from openff.units import unit +from openff.units import Quantity, unit from openff.toolkit.utils.base_wrapper import ToolkitWrapper from openff.toolkit.utils.exceptions import ToolkitUnavailableException if TYPE_CHECKING: - from openff.units import Quantity - from openff.toolkit.topology.molecule import FrozenMolecule, Molecule @@ -99,7 +97,7 @@ def assign_partial_charges( model = GNNModel.load(_only_model, eval_mode=True) charges = model.compute_property(molecule, as_numpy=True) - molecule.partial_charges = unit.Quantity( + molecule.partial_charges = Quantity( charges.astype(float), unit.elementary_charge, ) diff --git a/openff/toolkit/utils/ambertools_wrapper.py b/openff/toolkit/utils/ambertools_wrapper.py index ea9334347..e4f12e10e 100644 --- a/openff/toolkit/utils/ambertools_wrapper.py +++ b/openff/toolkit/utils/ambertools_wrapper.py @@ -274,7 +274,7 @@ def assign_partial_charges( for index, token in enumerate(text_charges): charges[index] = float(token) # TODO: Ensure that the atoms in charged.mol2 are in the same order as in molecule.sdf - charges = unit.Quantity(charges, unit.elementary_charge) + charges = Quantity(charges, unit.elementary_charge) molecule.partial_charges = charges if normalize_partial_charges: diff --git a/openff/toolkit/utils/openeye_wrapper.py b/openff/toolkit/utils/openeye_wrapper.py index f171d8819..b672f6aee 100644 --- a/openff/toolkit/utils/openeye_wrapper.py +++ b/openff/toolkit/utils/openeye_wrapper.py @@ -1324,7 +1324,7 @@ def describe_oeatom(oeatom) -> str: all_zeros = not np.any(positions) if all_zeros and n_atoms > 1: continue - molecule._add_conformer(unit.Quantity(positions, unit.angstrom)) + molecule._add_conformer(Quantity(positions, unit.angstrom)) # Store charges with implicit units in this scope unitless_charges = np.zeros(shape=molecule.n_atoms, dtype=np.float64) @@ -1343,7 +1343,7 @@ def describe_oeatom(oeatom) -> str: unitless_charges[off_idx] = unitless_charge if any_partial_charge_is_not_nan: - molecule.partial_charges = unit.Quantity( + molecule.partial_charges = Quantity( unitless_charges, unit.elementary_charge ) else: @@ -2286,7 +2286,7 @@ def apply_elf_conformer_selection( for atom_index, coordinates in oe_conformer.GetCoords().items(): conformer[atom_index, :] = coordinates - conformers.append(unit.Quantity(conformer, unit.angstrom)) + conformers.append(Quantity(conformer, unit.angstrom)) molecule._conformers = conformers @@ -2492,7 +2492,7 @@ def assign_partial_charges( # Extract and return charges # TODO: Make sure atom mapping remains constant # Extract the list of charges, taking into account possible indexing differences - charges = unit.Quantity( + charges = Quantity( np.zeros(shape=oemol.NumAtoms(), dtype=np.float64), unit.elementary_charge ) for oeatom in oemol.GetAtoms(): diff --git a/openff/toolkit/utils/rdkit_wrapper.py b/openff/toolkit/utils/rdkit_wrapper.py index e82c515da..00dc88f00 100644 --- a/openff/toolkit/utils/rdkit_wrapper.py +++ b/openff/toolkit/utils/rdkit_wrapper.py @@ -1227,7 +1227,7 @@ def generate_conformers( from rdkit.Chem import AllChem if rms_cutoff is None: - rms_cutoff = unit.Quantity(1.0, unit.angstrom) + rms_cutoff = Quantity(1.0, unit.angstrom) rdmol = self.to_rdkit(molecule) # TODO: This generates way more conformations than omega, given the same # nConfs and RMS threshold. Is there some way to set an energy cutoff as well? @@ -1347,9 +1347,7 @@ def assign_partial_charges( for rdatom in rdkit_molecule.GetAtoms() ] - molecule.partial_charges = unit.Quantity( - np.asarray(charges), unit.elementary_charge - ) + molecule.partial_charges = Quantity(np.asarray(charges), unit.elementary_charge) if normalize_partial_charges: molecule._normalize_partial_charges() @@ -1358,7 +1356,7 @@ def assign_partial_charges( def _elf_is_problematic_conformer( cls, molecule: "Molecule", - conformer: unit.Quantity, + conformer: Quantity, ) -> Tuple[bool, Optional[str]]: """A function which checks if a particular conformer is known to be problematic when computing ELF partial charges. @@ -1404,9 +1402,7 @@ def _elf_is_problematic_conformer( return False, None @classmethod - def _elf_prune_problematic_conformers( - cls, molecule: "Molecule" - ) -> List[unit.Quantity]: + def _elf_prune_problematic_conformers(cls, molecule: "Molecule") -> List[Quantity]: """A function which attempts to remove conformers which are known to be problematic when computing ELF partial charges. @@ -1442,7 +1438,7 @@ def _elf_prune_problematic_conformers( def _elf_compute_electrostatic_energy( cls, molecule: "Molecule", - conformer: unit.Quantity, + conformer: Quantity, ) -> float: """Computes the 'electrostatic interaction energy' of a particular conformer of a molecule. @@ -1562,10 +1558,10 @@ def _elf_compute_rms_matrix(cls, molecule: "Molecule") -> np.ndarray: def _elf_select_diverse_conformers( cls, molecule: "Molecule", - ranked_conformers: List[unit.Quantity], + ranked_conformers: List[Quantity], limit: int, - rms_tolerance: unit.Quantity, - ) -> List[unit.Quantity]: + rms_tolerance: Quantity, + ) -> List[Quantity]: """Attempt to greedily select a specified number conformers which are maximally diverse. @@ -1637,7 +1633,7 @@ def apply_elf_conformer_selection( molecule: "Molecule", percentage: float = 2.0, limit: int = 10, - rms_tolerance: unit.Quantity = 0.05 * unit.angstrom, + rms_tolerance: Quantity = 0.05 * unit.angstrom, ): """Applies the `ELF method `_ @@ -1978,7 +1974,7 @@ def from_rdkit( for rd_idx, off_idx in map_atoms.items(): atom_coords = conf.GetPositions()[rd_idx, :] positions[off_idx, :] = atom_coords - offmol._add_conformer(unit.Quantity(positions, unit.angstrom)) + offmol._add_conformer(Quantity(positions, unit.angstrom)) partial_charges = np.zeros(shape=offmol.n_atoms, dtype=np.float64) @@ -1996,9 +1992,7 @@ def from_rdkit( "Some atoms in rdmol have partial charges, but others do not." ) if any_atom_has_partial_charge: - offmol.partial_charges = unit.Quantity( - partial_charges, unit.elementary_charge - ) + offmol.partial_charges = Quantity(partial_charges, unit.elementary_charge) else: offmol.partial_charges = None return offmol diff --git a/openff/toolkit/utils/utils.py b/openff/toolkit/utils/utils.py index c3542c8ea..4a5ac5401 100644 --- a/openff/toolkit/utils/utils.py +++ b/openff/toolkit/utils/utils.py @@ -30,7 +30,7 @@ import numpy as np import pint -from openff.units import unit +from openff.units import Quantity, Unit, unit from openff.utilities import requires_package logger = logging.getLogger(__name__) @@ -117,7 +117,7 @@ def format_unit_simple(unit, registry, **options): return " * ".join(f"{u} ** {p}" for u, p in unit.items()) -def unit_to_string(input_unit: unit.Unit) -> str: +def unit_to_string(input_unit: Unit) -> str: return f"{input_unit:simple}" @@ -133,10 +133,10 @@ def quantity_to_dict(input_quantity): def dict_to_quantity(input_dict): - return input_dict["value"] * unit.Unit(input_dict["unit"]) + return input_dict["value"] * Unit(input_dict["unit"]) -def quantity_to_string(input_quantity: unit.Quantity) -> str: +def quantity_to_string(input_quantity: Quantity) -> str: """ Serialize a openff.units.unit.Quantity to a string representation that is backwards-compatible with older versions of the OpenFF Toolkit. This includes a " * " between numerical values and @@ -181,10 +181,10 @@ def string_to_unit(unit_string): output_unit: openff.units.unit.Quantity The deserialized unit from the string """ - return unit.Unit(unit_string) + return Unit(unit_string) -def string_to_quantity(quantity_string) -> Union[str, int, float, unit.Quantity]: +def string_to_quantity(quantity_string) -> Union[str, int, float, Quantity]: """Attempt to parse a string into a unit.Quantity. Note that dimensionless floats and ints are returns as floats or ints, not Quantity objects. @@ -195,7 +195,7 @@ def string_to_quantity(quantity_string) -> Union[str, int, float, unit.Quantity] from pint import UndefinedUnitError try: - quantity = unit.Quantity(quantity_string) + quantity = Quantity(quantity_string) except (TokenError, UndefinedUnitError): return quantity_string @@ -289,7 +289,7 @@ def convert_all_quantities_to_string(smirnoff_data): for index, item in enumerate(smirnoff_data): smirnoff_data[index] = convert_all_quantities_to_string(item) obj_to_return = smirnoff_data - elif isinstance(smirnoff_data, unit.Quantity): + elif isinstance(smirnoff_data, Quantity): obj_to_return = quantity_to_string(smirnoff_data) else: obj_to_return = smirnoff_data @@ -319,7 +319,7 @@ def object_to_quantity(object): return [object_to_quantity(sub_obj) for sub_obj in object] -@object_to_quantity.register(unit.Quantity) +@object_to_quantity.register(Quantity) def _(obj): return obj @@ -337,7 +337,7 @@ def _(obj): @object_to_quantity.register(int) @object_to_quantity.register(float) def _(obj): - return unit.Quantity(obj) + return Quantity(obj) try: