diff --git a/news/charge_validation.rst b/news/charge_validation.rst new file mode 100644 index 000000000..ce783ec93 --- /dev/null +++ b/news/charge_validation.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* All protocols will raise a ``ProtocolValidationError`` error if a non-deterministic partial charge generation method is used at run time, please provide molecules with pre-calculated charges to use ``am1bcc`` or use a deterministic method such as library charges or AshGC. + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/openfe/protocols/openmm_afe/base_afe_units.py b/src/openfe/protocols/openmm_afe/base_afe_units.py index 700e48541..7d927a5a3 100644 --- a/src/openfe/protocols/openmm_afe/base_afe_units.py +++ b/src/openfe/protocols/openmm_afe/base_afe_units.py @@ -67,7 +67,6 @@ ) from openfe.protocols.openmm_md.plain_md_methods import PlainMDSimulationUnit from openfe.protocols.openmm_utils import ( - charge_generation, multistate_analysis, omm_compute, settings_validation, @@ -349,33 +348,6 @@ def _pre_equilibrate( return equilibrated_positions, to_openmm(from_openmm(box)) - @staticmethod - def _assign_partial_charges( - partial_charge_settings: OpenFFPartialChargeSettings, - small_mols: dict[SmallMoleculeComponent, OFFMolecule], - ) -> None: - """ - Assign partial charges to the OpenFF Molecules associated with - all the SmallMoleculeComponents in the transformation. - - Parameters - ---------- - charge_settings : OpenFFPartialChargeSettings - Settings for controlling how the partial charges are assigned. - small_mols : dict[SmallMoleculeComponent, openff.toolkit.Molecule] - Dictionary of OpenFF Molecules to add, keyed by their - associated SmallMoleculeComponent. - """ - for mol in small_mols.values(): - charge_generation.assign_offmol_partial_charges( - offmol=mol, - overwrite=False, - method=partial_charge_settings.partial_charge_method, - toolkit_backend=partial_charge_settings.off_toolkit_backend, - generate_n_conformers=partial_charge_settings.number_of_conformers, - nagl_model=partial_charge_settings.nagl_model, - ) - @staticmethod def _get_system_generator( settings: dict[str, SettingsBaseModel], @@ -391,7 +363,7 @@ def _get_system_generator( ---------- settings : dict[str, SettingsBaseModel] A dictionary of settings object for the unit. - solvent_comp : BaseSolventComponent | None + solvent_component : BaseSolventComponent | None The solvent component of this system, if there is one. openff_molecules : list[openff.toolkit.Molecule] | None A list of OpenFF Molecules to generate templates for, if any. @@ -704,9 +676,6 @@ def run( # Get settings settings = self._get_settings() - # Assign partial charges now to avoid any discrepancies later - self._assign_partial_charges(settings["charge_settings"], small_mols) - # Get OpenMM topology, positions, system, and comp_resids omm_topology, omm_system, positions, comp_resids = self._get_omm_objects( settings=settings, diff --git a/src/openfe/protocols/openmm_afe/equil_binding_afe_method.py b/src/openfe/protocols/openmm_afe/equil_binding_afe_method.py index 06dcbaed0..28161b2cb 100644 --- a/src/openfe/protocols/openmm_afe/equil_binding_afe_method.py +++ b/src/openfe/protocols/openmm_afe/equil_binding_afe_method.py @@ -403,6 +403,11 @@ def _validate( system_validation.validate_chemical_system(stateB) self._validate_endstates(stateA, stateB) + # validate small molecule charges + small_ff = self.settings.forcefield_settings.small_molecule_forcefield + system_validation.validate_nondeterministic_charges(stateA, small_ff) + system_validation.validate_nondeterministic_charges(stateB, small_ff) + # Validate the complex lambda schedule self._validate_lambda_schedule( self.settings.complex_lambda_settings, diff --git a/src/openfe/protocols/openmm_afe/equil_solvation_afe_method.py b/src/openfe/protocols/openmm_afe/equil_solvation_afe_method.py index 5b2069c0d..c25765c03 100644 --- a/src/openfe/protocols/openmm_afe/equil_solvation_afe_method.py +++ b/src/openfe/protocols/openmm_afe/equil_solvation_afe_method.py @@ -385,6 +385,11 @@ def _validate( system_validation.validate_chemical_system(stateB) self._validate_endstates(stateA, stateB) + # validate small molecule charges + small_ff = self.settings.solvent_forcefield_settings.small_molecule_forcefield + system_validation.validate_nondeterministic_charges(stateA, small_ff) + system_validation.validate_nondeterministic_charges(stateB, small_ff) + # Validate the lambda schedule for solv_sets in ( self.settings.solvent_simulation_settings, diff --git a/src/openfe/protocols/openmm_md/plain_md_methods.py b/src/openfe/protocols/openmm_md/plain_md_methods.py index c16c3d3cb..c9033949c 100644 --- a/src/openfe/protocols/openmm_md/plain_md_methods.py +++ b/src/openfe/protocols/openmm_md/plain_md_methods.py @@ -50,7 +50,6 @@ PlainMDProtocolSettings, ) from openfe.protocols.openmm_utils import ( - charge_generation, omm_compute, serialization, settings_validation, @@ -197,6 +196,10 @@ def _validate( # Validate the ChemicalSystem system_validation.validate_chemical_system(stateA) + # Validate small molecule charges + small_ff = self.settings.forcefield_settings.small_molecule_forcefield + system_validation.validate_nondeterministic_charges(stateA, small_ff) + # Validate solvent component if present nonbond = self.settings.forcefield_settings.nonbonded_method system_validation.validate_solvent(stateA, nonbond) @@ -333,32 +336,6 @@ class PlainMDSetupUnit(PlainMDUnitMixin, gufe.ProtocolUnit): Protocol setup unit for plain MD simulations which handles charging, system building and solvation. """ - @staticmethod - def _assign_partial_charges( - charge_settings: OpenFFPartialChargeSettings, - smc_components: dict[SmallMoleculeComponent, OFFMolecule], - ) -> None: - """ - Assign partial charges to SMCs. - - Parameters - ---------- - charge_settings : OpenFFPartialChargeSettings - Settings for controlling how the partial charges are assigned. - smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule] - Dictionary of OpenFF Molecules to add, keyed by - SmallMoleculeComponent. - """ - for mol in smc_components.values(): - charge_generation.assign_offmol_partial_charges( - offmol=mol, - overwrite=False, - method=charge_settings.partial_charge_method, - toolkit_backend=charge_settings.off_toolkit_backend, - generate_n_conformers=charge_settings.number_of_conformers, - nagl_model=charge_settings.nagl_model, - ) - def run( self, *, @@ -450,9 +427,6 @@ def run( i: i.to_openff() for i in small_mols } - # a. assign partial charges to smcs - self._assign_partial_charges(charge_settings, smc_components) - # b. get a system generator if output_settings.forcefield_cache is not None: ffcache = self.shared_basepath / output_settings.forcefield_cache diff --git a/src/openfe/protocols/openmm_rfe/hybridtop_protocols.py b/src/openfe/protocols/openmm_rfe/hybridtop_protocols.py index 0d257688b..e346c6c85 100644 --- a/src/openfe/protocols/openmm_rfe/hybridtop_protocols.py +++ b/src/openfe/protocols/openmm_rfe/hybridtop_protocols.py @@ -618,6 +618,11 @@ def _validate( system_validation.validate_chemical_system(stateB) self._validate_endstates(stateA, stateB) + # Validate small molecule charges + small_ff = self.settings.forcefield_settings.small_molecule_forcefield + system_validation.validate_nondeterministic_charges(stateA, small_ff) + system_validation.validate_nondeterministic_charges(stateB, small_ff) + # Validate the mapping alchem_comps = system_validation.get_alchemical_components(stateA, stateB) self._validate_mapping(mapping, alchem_comps) diff --git a/src/openfe/protocols/openmm_rfe/hybridtop_units.py b/src/openfe/protocols/openmm_rfe/hybridtop_units.py index 8de7845f2..63fbc511a 100644 --- a/src/openfe/protocols/openmm_rfe/hybridtop_units.py +++ b/src/openfe/protocols/openmm_rfe/hybridtop_units.py @@ -54,7 +54,6 @@ from ...analysis import plotting from ...utils import log_system_probe, without_oechem_backend from ..openmm_utils import ( - charge_generation, multistate_analysis, omm_compute, settings_validation, @@ -205,33 +204,6 @@ def _get_components( return solvent_comp, protein_comp, small_mols - @staticmethod - def _assign_partial_charges( - charge_settings: OpenFFPartialChargeSettings, - small_mols: dict[SmallMoleculeComponent, OFFMolecule], - ) -> None: - """ - Assign partial charges to the OpenFF Molecules associated with all - the SmallMoleculeComponents in the transformation. - - Parameters - ---------- - charge_settings : OpenFFPartialChargeSettings - Settings for controlling how the partial charges are assigned. - small_mols : dict[SmallMoleculeComponent, openff.toolkit.Molecule] - Dictionary of OpenFF Molecules to add, keyed by - their associated SmallMoleculeComponent. - """ - for smc, mol in small_mols.items(): - charge_generation.assign_offmol_partial_charges( - offmol=mol, - overwrite=False, - method=charge_settings.partial_charge_method, - toolkit_backend=charge_settings.off_toolkit_backend, - generate_n_conformers=charge_settings.number_of_conformers, - nagl_model=charge_settings.nagl_model, - ) - @staticmethod def _get_system_generator( settings: dict[str, SettingsBaseModel], @@ -761,9 +733,6 @@ def run( # in the topology alchem_resnames = [assigned[alchem_comps["stateA"][0]]] - # Assign partial charges now to avoid any discrepancies later - self._assign_partial_charges(settings["charge_settings"], small_mols) - ( stateA_system, stateA_topology, diff --git a/src/openfe/protocols/openmm_septop/base_units.py b/src/openfe/protocols/openmm_septop/base_units.py index b0f71af9e..353dcc78b 100644 --- a/src/openfe/protocols/openmm_septop/base_units.py +++ b/src/openfe/protocols/openmm_septop/base_units.py @@ -69,7 +69,6 @@ from openfe.utils import log_system_probe, without_oechem_backend from ..openmm_utils import ( - charge_generation, multistate_analysis, settings_validation, system_creation, @@ -457,32 +456,6 @@ def _get_system_generator( ) return system_generator - @staticmethod - def _assign_partial_charges( - partial_charge_settings: OpenFFPartialChargeSettings, - smc_components: dict[SmallMoleculeComponent, OFFMolecule], - ) -> None: - """ - Assign partial charges to OFFMolecules inplace. - - Parameters - ---------- - charge_settings : OpenFFPartialChargeSettings - Settings for controlling how the partial charges are assigned. - smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule] - Dictionary of OpenFF Molecules to add, keyed by - SmallMoleculeComponent. - """ - for mol in smc_components.values(): - charge_generation.assign_offmol_partial_charges( - offmol=mol, - overwrite=False, - method=partial_charge_settings.partial_charge_method, - toolkit_backend=partial_charge_settings.off_toolkit_backend, - generate_n_conformers=partial_charge_settings.number_of_conformers, - nagl_model=partial_charge_settings.nagl_model, - ) - def _get_modeller( self, protein_component: Optional[ProteinComponent], diff --git a/src/openfe/protocols/openmm_septop/equil_septop_method.py b/src/openfe/protocols/openmm_septop/equil_septop_method.py index 7baf64273..66c5cde8a 100644 --- a/src/openfe/protocols/openmm_septop/equil_septop_method.py +++ b/src/openfe/protocols/openmm_septop/equil_septop_method.py @@ -485,6 +485,11 @@ def _validate( system_validation.validate_chemical_system(stateB) self._validate_endstates(stateA, stateB) + # Validate small molecule charges + small_ff = self.settings.forcefield_settings.small_molecule_forcefield + system_validation.validate_nondeterministic_charges(stateA, small_ff) + system_validation.validate_nondeterministic_charges(stateB, small_ff) + # Validate the lambda schedule self._validate_lambda_schedule( self.settings.solvent_lambda_settings, diff --git a/src/openfe/protocols/openmm_septop/septop_units.py b/src/openfe/protocols/openmm_septop/septop_units.py index 0c0430e63..ca17ee88f 100644 --- a/src/openfe/protocols/openmm_septop/septop_units.py +++ b/src/openfe/protocols/openmm_septop/septop_units.py @@ -711,9 +711,6 @@ def run( # 3. Get settings settings = self._get_settings() - # 4. Assign partial charges - self._assign_partial_charges(settings["charge_settings"], smc_comps_AB) - # 5. Get the OpenMM systems omm_system_A, omm_topology_A, positions_A, modeller_A, comp_resids_A = ( self.get_system( @@ -1080,9 +1077,6 @@ def run( # 2. Get settings settings = self._get_settings() - # 3. Assign partial charges - self._assign_partial_charges(settings["charge_settings"], smc_comps_AB) - # 4. Update the positions of ligand B: # - solvent: Offset ligand B with respect to ligand A offset = self._get_ligand_offset( diff --git a/src/openfe/protocols/openmm_utils/system_validation.py b/src/openfe/protocols/openmm_utils/system_validation.py index 906999910..0f56bd6d9 100644 --- a/src/openfe/protocols/openmm_utils/system_validation.py +++ b/src/openfe/protocols/openmm_utils/system_validation.py @@ -22,6 +22,8 @@ SolventComponent, ) from gufe.components.errors import ComponentValidationError +from gufe.protocols.errors import ProtocolValidationError +from openff.toolkit import ForceField from openff.toolkit import Molecule as OFFMol logger = logging.getLogger(__name__) @@ -371,3 +373,63 @@ def validate_chemical_system(system: ChemicalSystem): except ComponentValidationError as e: errmsg = f"Component {entry} from ChemicalSystem {system.name} failed validation: {e}" raise ComponentValidationError(errmsg) + + +def validate_nondeterministic_charges(system: ChemicalSystem, small_molecule_forcefield: str): + """ + Validate that the SmallMoleculeComponents of the system will have deterministic partial charges. + + This is determined by checking for charges on the molecules before checking what would be assigned by the force field. + + Parameters + ---------- + system : ChemicalSystem + The ChemicalSystem to validate with SmallMoleculeComponents. + small_molecule_forcefield : str + The force field to be used for the SmallMoleculeComponents. + + Raises + ------ + ProtocolValidationError + If any SmallMoleculeComponents in the system would have am1bcc charges generated at runtime. + """ + smcs: list[SmallMoleculeComponent] = system.get_components_of_type(SmallMoleculeComponent) + if "espaloma" in small_molecule_forcefield or "gaff" in small_molecule_forcefield: + # this will always generate charges at runtime, so raise an error for missing charges + ff = None + else: + try: + ff = ForceField(small_molecule_forcefield) + except OSError: + # try again but adding offxml to the end of the force field name if the user passed one of the installed force fields without the extension + try: + ff = ForceField(small_molecule_forcefield + ".offxml") + except OSError as e: + errmsg = f"Could not load force field {small_molecule_forcefield} or {small_molecule_forcefield}.offxml: {e}" + raise ProtocolValidationError(errmsg) + + errors = [] + for smc in smcs: + offmol = smc.to_openff() + if offmol.partial_charges is not None and np.any(offmol.partial_charges): + continue + + # check the labels assigned for an openff force field + if ff is not None: + labels = ff.label_molecules(offmol.to_topology())[0] + else: + # return a dummy label as the gaff and espaloma should always give am1bcc charges + labels = {"LibraryCharges": {}} + + # We count library and nagl charges as deterministic + # While users could use a deterministic charge method with increments we don't currently support this + if not labels.get("LibraryCharges", {}) and "NAGLCharges" not in labels: + errors.append(smc) + + if errors: + errmsg = ( + f"System: '{system.name}' contains SmallMoleculeComponents which would have am1bcc charges generated at runtime which is non-deterministic. " + f"Please provide a molecule with pre-computed charges or use library charges instead. " + f"The following Components are affected: {', '.join([str(smc) for smc in errors])}" + ) + raise ProtocolValidationError(errmsg) diff --git a/src/openfe/tests/analysis/test_plotting.py b/src/openfe/tests/analysis/test_plotting.py index 926b16b06..f42c78f64 100644 --- a/src/openfe/tests/analysis/test_plotting.py +++ b/src/openfe/tests/analysis/test_plotting.py @@ -159,15 +159,21 @@ def test_mbar_overlap_plot(): assert isinstance(ax, matplotlib.axes.Axes) -@pytest.mark.parametrize("num", [i for i in range(1, 30)]) -def test_plot_2D_rmsd(num): +def test_plot_2D_rmsd(): """ Smoke test: Loop through and test plotting fictitious 2D data """ + num = 29 points = num * (num - 1) // 2 - data = [[0.5 for x in range(points)] for i in range(num)] + data = [[0.5 for _ in range(points)] for _ in range(num)] + fig = plot_2D_rmsd(data) + # check the number of axes and their titles + assert len(fig.axes) == 32 + axis_names = [ax.get_title() for ax in fig.axes if ax.get_title()] + assert axis_names == [f"State {i}" for i in range(num)] + assert fig._suptitle.get_text() == "Protein 2D RMSD" plt.close(fig) diff --git a/src/openfe/tests/conftest.py b/src/openfe/tests/conftest.py index 044ad8864..0d1f2b2e4 100644 --- a/src/openfe/tests/conftest.py +++ b/src/openfe/tests/conftest.py @@ -14,7 +14,7 @@ import pandas as pd import pytest from gufe import AtomMapper, LigandAtomMapping, ProteinComponent, SmallMoleculeComponent -from openff.toolkit import ForceField +from openff.toolkit import ForceField, Molecule from openff.units import unit as offunit from openmm import unit as ommunit from rdkit import Chem @@ -162,7 +162,7 @@ def lomap_basic_test_files_dir(tmp_path_factory): lomap_basic = "openfe.tests.data.lomap_basic" for f in resources.contents(lomap_basic): - if not f.endswith("mol2"): + if not f.endswith("sdf"): continue stuff = resources.read_binary(lomap_basic, f) @@ -188,9 +188,9 @@ def atom_mapping_basic_test_files(): "toluene", ]: with resources.as_file(resources.files("openfe.tests.data.lomap_basic")) as d: - fn = str(d / (f + ".mol2")) - mol = Chem.MolFromMol2File(fn, removeHs=False) - files[f] = SmallMoleculeComponent(mol, name=f) + fn = str(d / (f + ".sdf")) + # go via openff to make sure the partial charges are pulled + files[f] = SmallMoleculeComponent.from_sdf_file(fn) return files @@ -379,17 +379,12 @@ def fepplus_network(): @pytest.fixture() -def CN_molecule() -> list[SmallMoleculeComponent]: +def CN_molecule(): """ A basic CH3NH2 molecule for quick testing. """ with resources.as_file(resources.files("openfe.tests.data")) as d: - fn = str(d / "CN.sdf") - supp = Chem.SDMolSupplier(str(fn), removeHs=False) - - smc = [SmallMoleculeComponent(i) for i in supp][0] - - return smc + yield SmallMoleculeComponent.from_sdf_file(d / "CN.sdf") @pytest.fixture(scope="function") diff --git a/src/openfe/tests/data/lomap_basic/1,3,7-trimethylnaphthalene.mol2 b/src/openfe/tests/data/lomap_basic/1,3,7-trimethylnaphthalene.mol2 deleted file mode 100644 index 4075dbcd6..000000000 --- a/src/openfe/tests/data/lomap_basic/1,3,7-trimethylnaphthalene.mol2 +++ /dev/null @@ -1,63 +0,0 @@ -@MOLECULE -***** - 27 28 0 0 0 -SMALL -GASTEIGER - -@ATOM - 1 C 0.9251 0.1494 -0.0025 C.3 1 LIG1 -0.0397 - 2 C 2.4242 0.1552 0.0465 C.ar 1 LIG1 -0.0498 - 3 C 3.1297 -1.0574 0.0810 C.ar 1 LIG1 -0.0509 - 4 C 4.5422 -1.1042 0.1427 C.ar 1 LIG1 -0.0147 - 5 C 5.2861 -2.3145 0.1727 C.ar 1 LIG1 -0.0425 - 6 C 6.6903 -2.2735 0.2331 C.ar 1 LIG1 -0.0553 - 7 C 7.3760 -1.0578 0.2620 C.ar 1 LIG1 -0.0496 - 8 C 6.6436 0.1328 0.2358 C.ar 1 LIG1 -0.0511 - 9 C 5.2413 0.1261 0.1765 C.ar 1 LIG1 -0.0174 - 10 C 4.5298 1.3362 0.1522 C.ar 1 LIG1 -0.0538 - 11 C 3.1361 1.3519 0.0914 C.ar 1 LIG1 -0.0582 - 12 C 8.8737 -1.0147 0.3281 C.3 1 LIG1 -0.0397 - 13 C 4.6094 -3.6603 0.1443 C.3 1 LIG1 -0.0391 - 14 H 0.5282 1.1476 -0.2149 H 1 LIG1 0.0278 - 15 H 0.5194 -0.1845 0.9575 H 1 LIG1 0.0278 - 16 H 0.5728 -0.5198 -0.7944 H 1 LIG1 0.0278 - 17 H 2.5577 -1.9826 0.0575 H 1 LIG1 0.0626 - 18 H 7.2540 -3.2043 0.2569 H 1 LIG1 0.0623 - 19 H 7.1781 1.0810 0.2619 H 1 LIG1 0.0626 - 20 H 5.0603 2.2854 0.1820 H 1 LIG1 0.0624 - 21 H 2.6157 2.3065 0.0777 H 1 LIG1 0.0620 - 22 H 9.3069 -2.0200 0.3015 H 1 LIG1 0.0278 - 23 H 9.1960 -0.5332 1.2567 H 1 LIG1 0.0278 - 24 H 9.2731 -0.4567 -0.5249 H 1 LIG1 0.0278 - 25 H 5.3371 -4.4789 0.1591 H 1 LIG1 0.0278 - 26 H 4.0157 -3.7691 -0.7690 H 1 LIG1 0.0278 - 27 H 3.9645 -3.7798 1.0209 H 1 LIG1 0.0278 -@BOND - 1 6 7 ar - 2 5 6 ar - 3 7 8 ar - 4 8 9 ar - 5 9 10 ar - 6 4 9 ar - 7 10 11 ar - 8 2 11 ar - 9 2 3 ar - 10 3 4 ar - 11 4 5 ar - 12 1 2 1 - 13 5 13 1 - 14 7 12 1 - 15 1 14 1 - 16 1 15 1 - 17 1 16 1 - 18 3 17 1 - 19 6 18 1 - 20 8 19 1 - 21 10 20 1 - 22 11 21 1 - 23 12 22 1 - 24 12 23 1 - 25 12 24 1 - 26 13 25 1 - 27 13 26 1 - 28 13 27 1 diff --git a/src/openfe/tests/data/lomap_basic/1,3,7-trimethylnaphthalene.sdf b/src/openfe/tests/data/lomap_basic/1,3,7-trimethylnaphthalene.sdf new file mode 100644 index 000000000..5d9849013 --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/1,3,7-trimethylnaphthalene.sdf @@ -0,0 +1,64 @@ +1,3,7-trimethylnaphthalene + -OEChem-08192610263D + + 27 28 0 0 0 0 0 0 0999 V2000 + 0.9251 0.1494 -0.0025 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4242 0.1552 0.0465 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1297 -1.0574 0.0810 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5422 -1.1042 0.1427 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2861 -2.3145 0.1727 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6903 -2.2735 0.2331 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3760 -1.0578 0.2620 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6436 0.1328 0.2358 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2413 0.1261 0.1765 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5298 1.3362 0.1522 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1361 1.3519 0.0914 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8737 -1.0147 0.3281 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6094 -3.6603 0.1443 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5282 1.1476 -0.2149 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5194 -0.1845 0.9575 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5728 -0.5198 -0.7944 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5577 -1.9826 0.0575 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2540 -3.2043 0.2569 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1781 1.0810 0.2619 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0603 2.2854 0.1820 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6157 2.3065 0.0777 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3069 -2.0200 0.3015 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1960 -0.5332 1.2567 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2731 -0.4567 -0.5249 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3371 -4.4789 0.1591 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0157 -3.7691 -0.7690 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9645 -3.7798 1.0209 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6 7 2 0 0 0 0 + 5 6 1 0 0 0 0 + 7 8 1 0 0 0 0 + 8 9 2 0 0 0 0 + 9 10 1 0 0 0 0 + 4 9 1 0 0 0 0 + 10 11 2 0 0 0 0 + 2 11 1 0 0 0 0 + 2 3 2 0 0 0 0 + 3 4 1 0 0 0 0 + 4 5 2 0 0 0 0 + 1 2 1 0 0 0 0 + 5 13 1 0 0 0 0 + 7 12 1 0 0 0 0 + 1 14 1 0 0 0 0 + 1 15 1 0 0 0 0 + 1 16 1 0 0 0 0 + 3 17 1 0 0 0 0 + 6 18 1 0 0 0 0 + 8 19 1 0 0 0 0 + 10 20 1 0 0 0 0 + 11 21 1 0 0 0 0 + 12 22 1 0 0 0 0 + 12 23 1 0 0 0 0 + 12 24 1 0 0 0 0 + 13 25 1 0 0 0 0 + 13 26 1 0 0 0 0 + 13 27 1 0 0 0 0 +M END +> +-0.039700 -0.049800 -0.050900 -0.014700 -0.042500 -0.055300 -0.049600 -0.051100 -0.017400 -0.053800 -0.058200 -0.039700 -0.039100 0.027800 0.027800 0.027800 0.062600 0.062300 0.062600 0.062400 0.062000 0.027800 0.027800 0.027800 0.027800 0.027800 0.027800 + +$$$$ diff --git a/src/openfe/tests/data/lomap_basic/1-butyl-4-methylbenzene.mol2 b/src/openfe/tests/data/lomap_basic/1-butyl-4-methylbenzene.mol2 deleted file mode 100644 index 3c4d3de90..000000000 --- a/src/openfe/tests/data/lomap_basic/1-butyl-4-methylbenzene.mol2 +++ /dev/null @@ -1,62 +0,0 @@ -@MOLECULE -***** - 27 27 0 0 0 -SMALL -GASTEIGER - -@ATOM - 1 C 1.9899 -1.5496 1.4095 C.3 1 LIG1 -0.0653 - 2 C 3.0612 -0.6401 0.8303 C.3 1 LIG1 -0.0556 - 3 C 3.5100 0.4139 1.8419 C.3 1 LIG1 -0.0493 - 4 C 4.5859 1.3256 1.2470 C.3 1 LIG1 -0.0277 - 5 C 5.0777 2.3433 2.2464 C.ar 1 LIG1 -0.0473 - 6 C 4.4793 3.6056 2.3316 C.ar 1 LIG1 -0.0583 - 7 C 4.9350 4.5439 3.2608 C.ar 1 LIG1 -0.0586 - 8 C 5.9858 4.2317 4.1299 C.ar 1 LIG1 -0.0504 - 9 C 6.5860 2.9711 4.0431 C.ar 1 LIG1 -0.0586 - 10 C 6.1309 2.0320 3.1146 C.ar 1 LIG1 -0.0583 - 11 C 6.4975 5.2565 5.0979 C.3 1 LIG1 -0.0397 - 12 H 1.6931 -2.3034 0.6726 H 1 LIG1 0.0230 - 13 H 1.0980 -0.9785 1.6885 H 1 LIG1 0.0230 - 14 H 2.3560 -2.0720 2.3000 H 1 LIG1 0.0230 - 15 H 2.6700 -0.1517 -0.0688 H 1 LIG1 0.0263 - 16 H 3.9190 -1.2484 0.5229 H 1 LIG1 0.0263 - 17 H 3.8957 -0.0824 2.7418 H 1 LIG1 0.0268 - 18 H 2.6473 1.0144 2.1583 H 1 LIG1 0.0268 - 19 H 4.1939 1.8426 0.3620 H 1 LIG1 0.0313 - 20 H 5.4358 0.7279 0.8940 H 1 LIG1 0.0313 - 21 H 3.6566 3.8691 1.6710 H 1 LIG1 0.0620 - 22 H 4.4634 5.5233 3.3010 H 1 LIG1 0.0620 - 23 H 7.4138 2.7097 4.6988 H 1 LIG1 0.0620 - 24 H 6.6080 1.0557 3.0700 H 1 LIG1 0.0620 - 25 H 7.0175 4.7827 5.9374 H 1 LIG1 0.0278 - 26 H 5.6710 5.8412 5.5155 H 1 LIG1 0.0278 - 27 H 7.1937 5.9336 4.5926 H 1 LIG1 0.0278 -@BOND - 1 5 6 ar - 2 6 7 ar - 3 5 10 ar - 4 9 10 ar - 5 8 9 ar - 6 7 8 ar - 7 1 2 1 - 8 2 3 1 - 9 3 4 1 - 10 4 5 1 - 11 8 11 1 - 12 1 12 1 - 13 1 13 1 - 14 1 14 1 - 15 2 15 1 - 16 2 16 1 - 17 3 17 1 - 18 3 18 1 - 19 4 19 1 - 20 4 20 1 - 21 6 21 1 - 22 7 22 1 - 23 9 23 1 - 24 10 24 1 - 25 11 25 1 - 26 11 26 1 - 27 11 27 1 diff --git a/src/openfe/tests/data/lomap_basic/1-butyl-4-methylbenzene.sdf b/src/openfe/tests/data/lomap_basic/1-butyl-4-methylbenzene.sdf new file mode 100644 index 000000000..855a71538 --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/1-butyl-4-methylbenzene.sdf @@ -0,0 +1,63 @@ +1-butyl-4-methylbenzene + -OEChem-08192610283D + + 27 27 0 0 0 0 0 0 0999 V2000 + 1.9899 -1.5496 1.4095 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0612 -0.6401 0.8303 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.5100 0.4139 1.8419 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5859 1.3256 1.2470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0777 2.3433 2.2464 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4793 3.6056 2.3316 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.9350 4.5439 3.2608 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9858 4.2317 4.1299 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5860 2.9711 4.0431 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.1309 2.0320 3.1146 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4975 5.2565 5.0979 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6931 -2.3034 0.6726 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.0980 -0.9785 1.6885 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.3560 -2.0720 2.3000 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6700 -0.1517 -0.0688 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9190 -1.2484 0.5229 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8957 -0.0824 2.7418 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6473 1.0144 2.1583 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1939 1.8426 0.3620 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4358 0.7279 0.8940 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.6566 3.8691 1.6710 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4634 5.5233 3.3010 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4138 2.7097 4.6988 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6080 1.0557 3.0700 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0175 4.7827 5.9374 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6710 5.8412 5.5155 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1937 5.9336 4.5926 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5 6 2 0 0 0 0 + 6 7 1 0 0 0 0 + 5 10 1 0 0 0 0 + 9 10 2 0 0 0 0 + 8 9 1 0 0 0 0 + 7 8 2 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 4 1 0 0 0 0 + 4 5 1 0 0 0 0 + 8 11 1 0 0 0 0 + 1 12 1 0 0 0 0 + 1 13 1 0 0 0 0 + 1 14 1 0 0 0 0 + 2 15 1 0 0 0 0 + 2 16 1 0 0 0 0 + 3 17 1 0 0 0 0 + 3 18 1 0 0 0 0 + 4 19 1 0 0 0 0 + 4 20 1 0 0 0 0 + 6 21 1 0 0 0 0 + 7 22 1 0 0 0 0 + 9 23 1 0 0 0 0 + 10 24 1 0 0 0 0 + 11 25 1 0 0 0 0 + 11 26 1 0 0 0 0 + 11 27 1 0 0 0 0 +M END +> +-0.065300 -0.055600 -0.049300 -0.027700 -0.047300 -0.058300 -0.058600 -0.050400 -0.058600 -0.058300 -0.039700 0.023000 0.023000 0.023000 0.026300 0.026300 0.026800 0.026800 0.031300 0.031300 0.062000 0.062000 0.062000 0.062000 0.027800 0.027800 0.027800 + +$$$$ diff --git a/src/openfe/tests/data/lomap_basic/2,6-dimethylnaphthalene.mol2 b/src/openfe/tests/data/lomap_basic/2,6-dimethylnaphthalene.mol2 deleted file mode 100644 index 1ead00447..000000000 --- a/src/openfe/tests/data/lomap_basic/2,6-dimethylnaphthalene.mol2 +++ /dev/null @@ -1,57 +0,0 @@ -@MOLECULE -***** - 24 25 0 0 0 -SMALL -GASTEIGER - -@ATOM - 1 C 0.8817 -0.0759 0.0737 C.3 1 LIG1 -0.0397 - 2 C 2.3811 -0.0540 0.0354 C.ar 1 LIG1 -0.0499 - 3 C 3.0834 1.1532 0.0347 C.ar 1 LIG1 -0.0582 - 4 C 4.4799 1.1582 -0.0011 C.ar 1 LIG1 -0.0538 - 5 C 5.2032 -0.0442 -0.0356 C.ar 1 LIG1 -0.0176 - 6 C 6.6087 -0.0550 -0.0772 C.ar 1 LIG1 -0.0511 - 7 C 7.3242 -1.2594 -0.1176 C.ar 1 LIG1 -0.0499 - 8 C 8.8235 -1.2393 -0.1486 C.3 1 LIG1 -0.0397 - 9 C 6.6224 -2.4667 -0.0984 C.ar 1 LIG1 -0.0582 - 10 C 5.2258 -2.4717 -0.0573 C.ar 1 LIG1 -0.0538 - 11 C 4.5024 -1.2692 -0.0283 C.ar 1 LIG1 -0.0176 - 12 C 3.0971 -1.2586 0.0081 C.ar 1 LIG1 -0.0511 - 13 H 0.4638 0.9355 0.0362 H 1 LIG1 0.0278 - 14 H 0.5354 -0.5508 0.9973 H 1 LIG1 0.0278 - 15 H 0.4903 -0.6304 -0.7856 H 1 LIG1 0.0278 - 16 H 2.5515 2.1015 0.0601 H 1 LIG1 0.0620 - 17 H 5.0016 2.1125 -0.0033 H 1 LIG1 0.0624 - 18 H 7.1539 0.8869 -0.0807 H 1 LIG1 0.0626 - 19 H 9.2330 -2.2332 -0.3578 H 1 LIG1 0.0278 - 20 H 9.2150 -0.9034 0.8167 H 1 LIG1 0.0278 - 21 H 9.1785 -0.5651 -0.9354 H 1 LIG1 0.0278 - 22 H 7.1546 -3.4149 -0.1177 H 1 LIG1 0.0620 - 23 H 4.7045 -3.4261 -0.0479 H 1 LIG1 0.0624 - 24 H 2.5515 -2.2003 0.0134 H 1 LIG1 0.0626 -@BOND - 1 2 3 ar - 2 3 4 ar - 3 2 12 ar - 4 11 12 ar - 5 10 11 ar - 6 5 11 ar - 7 9 10 ar - 8 7 9 ar - 9 6 7 ar - 10 5 6 ar - 11 4 5 ar - 12 1 2 1 - 13 7 8 1 - 14 1 13 1 - 15 1 14 1 - 16 1 15 1 - 17 3 16 1 - 18 4 17 1 - 19 6 18 1 - 20 8 19 1 - 21 8 20 1 - 22 8 21 1 - 23 9 22 1 - 24 10 23 1 - 25 12 24 1 diff --git a/src/openfe/tests/data/lomap_basic/2,6-dimethylnaphthalene.sdf b/src/openfe/tests/data/lomap_basic/2,6-dimethylnaphthalene.sdf new file mode 100644 index 000000000..839dba911 --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/2,6-dimethylnaphthalene.sdf @@ -0,0 +1,58 @@ +2,6-dimethylnaphthalene + -OEChem-08192610283D + + 24 25 0 0 0 0 0 0 0999 V2000 + 0.8817 -0.0759 0.0737 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.3811 -0.0540 0.0354 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0834 1.1532 0.0347 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4799 1.1582 -0.0011 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2032 -0.0442 -0.0356 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6087 -0.0550 -0.0772 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3242 -1.2594 -0.1176 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.8235 -1.2393 -0.1486 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6224 -2.4667 -0.0984 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2258 -2.4717 -0.0573 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5024 -1.2692 -0.0283 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0971 -1.2586 0.0081 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4638 0.9355 0.0362 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5354 -0.5508 0.9973 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4903 -0.6304 -0.7856 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5515 2.1015 0.0601 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0016 2.1125 -0.0033 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1539 0.8869 -0.0807 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2330 -2.2332 -0.3578 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2150 -0.9034 0.8167 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1785 -0.5651 -0.9354 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1546 -3.4149 -0.1177 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.7045 -3.4261 -0.0479 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5515 -2.2003 0.0134 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2 3 2 0 0 0 0 + 3 4 1 0 0 0 0 + 2 12 1 0 0 0 0 + 11 12 2 0 0 0 0 + 10 11 1 0 0 0 0 + 5 11 1 0 0 0 0 + 9 10 2 0 0 0 0 + 7 9 1 0 0 0 0 + 6 7 2 0 0 0 0 + 5 6 1 0 0 0 0 + 4 5 2 0 0 0 0 + 1 2 1 0 0 0 0 + 7 8 1 0 0 0 0 + 1 13 1 0 0 0 0 + 1 14 1 0 0 0 0 + 1 15 1 0 0 0 0 + 3 16 1 0 0 0 0 + 4 17 1 0 0 0 0 + 6 18 1 0 0 0 0 + 8 19 1 0 0 0 0 + 8 20 1 0 0 0 0 + 8 21 1 0 0 0 0 + 9 22 1 0 0 0 0 + 10 23 1 0 0 0 0 + 12 24 1 0 0 0 0 +M END +> +-0.039700 -0.049900 -0.058200 -0.053800 -0.017600 -0.051100 -0.049900 -0.039700 -0.058200 -0.053800 -0.017600 -0.051100 0.027800 0.027800 0.027800 0.062000 0.062400 0.062600 0.027800 0.027800 0.027800 0.062000 0.062400 0.062600 + +$$$$ diff --git a/src/openfe/tests/data/lomap_basic/2-methyl-6-propylnaphthalene.mol2 b/src/openfe/tests/data/lomap_basic/2-methyl-6-propylnaphthalene.mol2 deleted file mode 100644 index e5595c491..000000000 --- a/src/openfe/tests/data/lomap_basic/2-methyl-6-propylnaphthalene.mol2 +++ /dev/null @@ -1,69 +0,0 @@ -@MOLECULE -***** - 30 31 0 0 0 -SMALL -GASTEIGER - -@ATOM - 1 C 0.7969 1.3147 -1.5722 C.3 1 LIG1 -0.0650 - 2 C 2.3162 1.3551 -1.5843 C.3 1 LIG1 -0.0519 - 3 C 2.8874 1.3784 -0.1657 C.3 1 LIG1 -0.0279 - 4 C 4.3949 1.4239 -0.1763 C.ar 1 LIG1 -0.0468 - 5 C 5.1419 0.2376 -0.2084 C.ar 1 LIG1 -0.0508 - 6 C 6.5466 0.2630 -0.2482 C.ar 1 LIG1 -0.0176 - 7 C 7.2164 1.5056 -0.2598 C.ar 1 LIG1 -0.0176 - 8 C 6.4634 2.6893 -0.2285 C.ar 1 LIG1 -0.0538 - 9 C 5.0678 2.6494 -0.1901 C.ar 1 LIG1 -0.0580 - 10 C 8.6208 1.5306 -0.3057 C.ar 1 LIG1 -0.0511 - 11 C 9.3673 0.3447 -0.3470 C.ar 1 LIG1 -0.0499 - 12 C 8.6960 -0.8804 -0.3232 C.ar 1 LIG1 -0.0582 - 13 C 7.3000 -0.9207 -0.2780 C.ar 1 LIG1 -0.0538 - 14 C 10.8656 0.4019 -0.3796 C.3 1 LIG1 -0.0397 - 15 H 0.4106 1.2994 -2.5961 H 1 LIG1 0.0230 - 16 H 0.3854 2.1942 -1.0670 H 1 LIG1 0.0230 - 17 H 0.4325 0.4199 -1.0579 H 1 LIG1 0.0230 - 18 H 2.6477 2.2415 -2.1391 H 1 LIG1 0.0266 - 19 H 2.6945 0.4813 -2.1292 H 1 LIG1 0.0266 - 20 H 2.5534 0.4943 0.3922 H 1 LIG1 0.0313 - 21 H 2.5001 2.2454 0.3843 H 1 LIG1 0.0313 - 22 H 4.6215 -0.7184 -0.2065 H 1 LIG1 0.0626 - 23 H 6.9606 3.6568 -0.2384 H 1 LIG1 0.0624 - 24 H 4.5102 3.5829 -0.1747 H 1 LIG1 0.0620 - 25 H 9.1424 2.4858 -0.3125 H 1 LIG1 0.0626 - 26 H 9.2523 -1.8147 -0.3422 H 1 LIG1 0.0620 - 27 H 6.8033 -1.8881 -0.2657 H 1 LIG1 0.0624 - 28 H 11.2977 -0.5759 -0.6162 H 1 LIG1 0.0278 - 29 H 11.2498 0.7216 0.5938 H 1 LIG1 0.0278 - 30 H 11.2028 1.1048 -1.1483 H 1 LIG1 0.0278 -@BOND - 1 4 9 ar - 2 8 9 ar - 3 4 5 ar - 4 5 6 ar - 5 6 13 ar - 6 6 7 ar - 7 12 13 ar - 8 11 12 ar - 9 10 11 ar - 10 7 10 ar - 11 7 8 ar - 12 1 2 1 - 13 2 3 1 - 14 3 4 1 - 15 11 14 1 - 16 1 15 1 - 17 1 16 1 - 18 1 17 1 - 19 2 18 1 - 20 2 19 1 - 21 3 20 1 - 22 3 21 1 - 23 5 22 1 - 24 8 23 1 - 25 9 24 1 - 26 10 25 1 - 27 12 26 1 - 28 13 27 1 - 29 14 28 1 - 30 14 29 1 - 31 14 30 1 diff --git a/src/openfe/tests/data/lomap_basic/2-methyl-6-propylnaphthalene.sdf b/src/openfe/tests/data/lomap_basic/2-methyl-6-propylnaphthalene.sdf new file mode 100644 index 000000000..175aa303b --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/2-methyl-6-propylnaphthalene.sdf @@ -0,0 +1,70 @@ +2-methyl-6-propylnaphthalene + -OEChem-08192610293D + + 30 31 0 0 0 0 0 0 0999 V2000 + 0.7969 1.3147 -1.5722 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.3162 1.3551 -1.5843 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8874 1.3784 -0.1657 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3949 1.4239 -0.1763 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1419 0.2376 -0.2084 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5466 0.2630 -0.2482 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2164 1.5056 -0.2598 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4634 2.6893 -0.2285 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0678 2.6494 -0.1901 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6208 1.5306 -0.3057 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3673 0.3447 -0.3470 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6960 -0.8804 -0.3232 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3000 -0.9207 -0.2780 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.8656 0.4019 -0.3796 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4106 1.2994 -2.5961 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.3854 2.1942 -1.0670 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4325 0.4199 -1.0579 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6477 2.2415 -2.1391 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6945 0.4813 -2.1292 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5534 0.4943 0.3922 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5001 2.2454 0.3843 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6215 -0.7184 -0.2065 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9606 3.6568 -0.2384 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5102 3.5829 -0.1747 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1424 2.4858 -0.3125 H 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2523 -1.8147 -0.3422 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8033 -1.8881 -0.2657 H 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2977 -0.5759 -0.6162 H 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2498 0.7216 0.5938 H 0 0 0 0 0 0 0 0 0 0 0 0 + 11.2028 1.1048 -1.1483 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4 9 2 0 0 0 0 + 8 9 1 0 0 0 0 + 4 5 1 0 0 0 0 + 5 6 2 0 0 0 0 + 6 13 1 0 0 0 0 + 6 7 1 0 0 0 0 + 12 13 2 0 0 0 0 + 11 12 1 0 0 0 0 + 10 11 2 0 0 0 0 + 7 10 1 0 0 0 0 + 7 8 2 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 1 0 0 0 0 + 3 4 1 0 0 0 0 + 11 14 1 0 0 0 0 + 1 15 1 0 0 0 0 + 1 16 1 0 0 0 0 + 1 17 1 0 0 0 0 + 2 18 1 0 0 0 0 + 2 19 1 0 0 0 0 + 3 20 1 0 0 0 0 + 3 21 1 0 0 0 0 + 5 22 1 0 0 0 0 + 8 23 1 0 0 0 0 + 9 24 1 0 0 0 0 + 10 25 1 0 0 0 0 + 12 26 1 0 0 0 0 + 13 27 1 0 0 0 0 + 14 28 1 0 0 0 0 + 14 29 1 0 0 0 0 + 14 30 1 0 0 0 0 +M END +> +-0.065000 -0.051900 -0.027900 -0.046800 -0.050800 -0.017600 -0.017600 -0.053800 -0.058000 -0.051100 -0.049900 -0.058200 -0.053800 -0.039700 0.023000 0.023000 0.023000 0.026600 0.026600 0.031300 0.031300 0.062600 0.062400 0.062000 0.062600 0.062000 0.062400 0.027800 0.027800 0.027800 + +$$$$ diff --git a/src/openfe/tests/data/lomap_basic/2-methylnaphthalene.mol2 b/src/openfe/tests/data/lomap_basic/2-methylnaphthalene.mol2 deleted file mode 100644 index 4f4a6ea55..000000000 --- a/src/openfe/tests/data/lomap_basic/2-methylnaphthalene.mol2 +++ /dev/null @@ -1,51 +0,0 @@ -@MOLECULE -***** - 21 22 0 0 0 -SMALL -GASTEIGER - -@ATOM - 1 C 0.9750 -0.0348 0.0833 C.3 1 LIG1 -0.0397 - 2 C 2.4749 -0.0532 0.0754 C.ar 1 LIG1 -0.0499 - 3 C 3.2098 1.1400 0.0597 C.ar 1 LIG1 -0.0511 - 4 C 4.6141 1.1264 -0.0127 C.ar 1 LIG1 -0.0176 - 5 C 5.3554 2.3190 -0.0614 C.ar 1 LIG1 -0.0540 - 6 C 6.7465 2.2894 -0.1768 C.ar 1 LIG1 -0.0612 - 7 C 7.4142 1.0702 -0.2321 C.ar 1 LIG1 -0.0612 - 8 C 6.6939 -0.1236 -0.1628 C.ar 1 LIG1 -0.0540 - 9 C 5.2934 -0.1107 -0.0560 C.ar 1 LIG1 -0.0179 - 10 C 4.5528 -1.3018 -0.0057 C.ar 1 LIG1 -0.0538 - 11 C 3.1574 -1.2723 0.0551 C.ar 1 LIG1 -0.0582 - 12 H 0.5850 0.9882 0.1017 H 1 LIG1 0.0278 - 13 H 0.5915 -0.5586 0.9643 H 1 LIG1 0.0278 - 14 H 0.5924 -0.5209 -0.8204 H 1 LIG1 0.0278 - 15 H 2.6835 2.0917 0.0844 H 1 LIG1 0.0626 - 16 H 4.8512 3.2813 -0.0218 H 1 LIG1 0.0624 - 17 H 7.3059 3.2198 -0.2301 H 1 LIG1 0.0618 - 18 H 8.4962 1.0459 -0.3322 H 1 LIG1 0.0618 - 19 H 7.2331 -1.0669 -0.2063 H 1 LIG1 0.0624 - 20 H 5.0575 -2.2644 -0.0289 H 1 LIG1 0.0624 - 21 H 2.6062 -2.2099 0.0730 H 1 LIG1 0.0620 -@BOND - 1 1 2 1 - 2 2 3 ar - 3 3 4 ar - 4 4 5 ar - 5 5 6 ar - 6 6 7 ar - 7 7 8 ar - 8 8 9 ar - 9 4 9 ar - 10 9 10 ar - 11 10 11 ar - 12 2 11 ar - 13 1 12 1 - 14 1 13 1 - 15 1 14 1 - 16 3 15 1 - 17 5 16 1 - 18 6 17 1 - 19 7 18 1 - 20 8 19 1 - 21 10 20 1 - 22 11 21 1 diff --git a/src/openfe/tests/data/lomap_basic/2-methylnaphthalene.sdf b/src/openfe/tests/data/lomap_basic/2-methylnaphthalene.sdf new file mode 100644 index 000000000..8d754318e --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/2-methylnaphthalene.sdf @@ -0,0 +1,52 @@ +2-methylnaphthalene + -OEChem-08192610323D + + 21 22 0 0 0 0 0 0 0999 V2000 + 0.9750 -0.0348 0.0833 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4749 -0.0532 0.0754 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.2098 1.1400 0.0597 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6141 1.1264 -0.0127 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3554 2.3190 -0.0614 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7465 2.2894 -0.1768 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4142 1.0702 -0.2321 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6939 -0.1236 -0.1628 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2934 -0.1107 -0.0560 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5528 -1.3018 -0.0057 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1574 -1.2723 0.0551 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5850 0.9882 0.1017 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5915 -0.5586 0.9643 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5924 -0.5209 -0.8204 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6835 2.0917 0.0844 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8512 3.2813 -0.0218 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3059 3.2198 -0.2301 H 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4962 1.0459 -0.3322 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2331 -1.0669 -0.2063 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0575 -2.2644 -0.0289 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6062 -2.2099 0.0730 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 2 3 2 0 0 0 0 + 3 4 1 0 0 0 0 + 4 5 2 0 0 0 0 + 5 6 1 0 0 0 0 + 6 7 2 0 0 0 0 + 7 8 1 0 0 0 0 + 8 9 2 0 0 0 0 + 4 9 1 0 0 0 0 + 9 10 1 0 0 0 0 + 10 11 2 0 0 0 0 + 2 11 1 0 0 0 0 + 1 12 1 0 0 0 0 + 1 13 1 0 0 0 0 + 1 14 1 0 0 0 0 + 3 15 1 0 0 0 0 + 5 16 1 0 0 0 0 + 6 17 1 0 0 0 0 + 7 18 1 0 0 0 0 + 8 19 1 0 0 0 0 + 10 20 1 0 0 0 0 + 11 21 1 0 0 0 0 +M END +> +-0.039700 -0.049900 -0.051100 -0.017600 -0.054000 -0.061200 -0.061200 -0.054000 -0.017900 -0.053800 -0.058200 0.027800 0.027800 0.027800 0.062600 0.062400 0.061800 0.061800 0.062400 0.062400 0.062000 + +$$$$ diff --git a/src/openfe/tests/data/lomap_basic/2-naftanol.mol2 b/src/openfe/tests/data/lomap_basic/2-naftanol.mol2 deleted file mode 100644 index 79bfc04e2..000000000 --- a/src/openfe/tests/data/lomap_basic/2-naftanol.mol2 +++ /dev/null @@ -1,47 +0,0 @@ -@MOLECULE -***** - 19 20 0 0 0 -SMALL -GASTEIGER - -@ATOM - 1 O 9.9477 -4.1875 1.4569 O.3 1 LIG1 -0.5067 - 2 C 9.0676 -3.1850 1.1716 C.ar 1 LIG1 0.1175 - 3 C 7.7820 -3.1808 1.6974 C.ar 1 LIG1 -0.0196 - 4 C 6.9153 -2.1329 1.3798 C.ar 1 LIG1 -0.0506 - 5 C 7.3294 -1.0867 0.5375 C.ar 1 LIG1 -0.0177 - 6 C 6.4703 -0.0252 0.2106 C.ar 1 LIG1 -0.0540 - 7 C 6.8977 1.0066 -0.6271 C.ar 1 LIG1 -0.0612 - 8 C 8.1878 0.9906 -1.1489 C.ar 1 LIG1 -0.0612 - 9 C 9.0548 -0.0574 -0.8344 C.ar 1 LIG1 -0.0539 - 10 C 8.6411 -1.1023 0.0071 C.ar 1 LIG1 -0.0144 - 11 C 9.5008 -2.1625 0.3346 C.ar 1 LIG1 -0.0125 - 12 H 9.5144 -4.8197 2.0534 H 1 LIG1 0.2921 - 13 H 7.4363 -3.9757 2.3505 H 1 LIG1 0.0654 - 14 H 5.9102 -2.1360 1.7951 H 1 LIG1 0.0625 - 15 H 5.4583 0.0059 0.6080 H 1 LIG1 0.0624 - 16 H 6.2223 1.8225 -0.8713 H 1 LIG1 0.0618 - 17 H 8.5216 1.7931 -1.8011 H 1 LIG1 0.0618 - 18 H 10.0593 -0.0532 -1.2512 H 1 LIG1 0.0624 - 19 H 10.5134 -2.1967 -0.0603 H 1 LIG1 0.0660 -@BOND - 1 2 3 ar - 2 2 11 ar - 3 3 4 ar - 4 4 5 ar - 5 5 6 ar - 6 5 10 ar - 7 6 7 ar - 8 7 8 ar - 9 8 9 ar - 10 9 10 ar - 11 10 11 ar - 12 1 2 1 - 13 1 12 1 - 14 3 13 1 - 15 4 14 1 - 16 6 15 1 - 17 7 16 1 - 18 8 17 1 - 19 9 18 1 - 20 11 19 1 diff --git a/src/openfe/tests/data/lomap_basic/2-naftanol.sdf b/src/openfe/tests/data/lomap_basic/2-naftanol.sdf new file mode 100644 index 000000000..e51db2e63 --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/2-naftanol.sdf @@ -0,0 +1,48 @@ +2-naftanol + -OEChem-08192610333D + + 19 20 0 0 0 0 0 0 0999 V2000 + 9.9477 -4.1875 1.4569 O 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0676 -3.1850 1.1716 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.7820 -3.1808 1.6974 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.9153 -2.1329 1.3798 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3294 -1.0867 0.5375 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4703 -0.0252 0.2106 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8977 1.0066 -0.6271 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1878 0.9906 -1.1489 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0548 -0.0574 -0.8344 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6411 -1.1023 0.0071 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5008 -2.1625 0.3346 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5144 -4.8197 2.0534 H 0 0 0 0 0 0 0 0 0 0 0 0 + 7.4363 -3.9757 2.3505 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9102 -2.1360 1.7951 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4583 0.0059 0.6080 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.2223 1.8225 -0.8713 H 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5216 1.7931 -1.8011 H 0 0 0 0 0 0 0 0 0 0 0 0 + 10.0593 -0.0532 -1.2512 H 0 0 0 0 0 0 0 0 0 0 0 0 + 10.5134 -2.1967 -0.0603 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2 3 2 0 0 0 0 + 2 11 1 0 0 0 0 + 3 4 1 0 0 0 0 + 4 5 2 0 0 0 0 + 5 6 1 0 0 0 0 + 5 10 1 0 0 0 0 + 6 7 2 0 0 0 0 + 7 8 1 0 0 0 0 + 8 9 2 0 0 0 0 + 9 10 1 0 0 0 0 + 10 11 2 0 0 0 0 + 1 2 1 0 0 0 0 + 1 12 1 0 0 0 0 + 3 13 1 0 0 0 0 + 4 14 1 0 0 0 0 + 6 15 1 0 0 0 0 + 7 16 1 0 0 0 0 + 8 17 1 0 0 0 0 + 9 18 1 0 0 0 0 + 11 19 1 0 0 0 0 +M END +> +-0.506700 0.117500 -0.019600 -0.050600 -0.017700 -0.054000 -0.061200 -0.061200 -0.053900 -0.014400 -0.012500 0.292100 0.065400 0.062500 0.062400 0.061800 0.061800 0.062400 0.066000 + +$$$$ diff --git a/src/openfe/tests/data/lomap_basic/methylcyclohexane.mol2 b/src/openfe/tests/data/lomap_basic/methylcyclohexane.mol2 deleted file mode 100644 index 926963c28..000000000 --- a/src/openfe/tests/data/lomap_basic/methylcyclohexane.mol2 +++ /dev/null @@ -1,50 +0,0 @@ -@MOLECULE -***** - 21 21 0 0 0 -SMALL -GASTEIGER - -@ATOM - 1 C 0.9730 0.1554 0.1412 C.3 1 LIG1 -0.0624 - 2 C 2.4934 0.1043 -0.0303 C.3 1 LIG1 -0.0439 - 3 C 2.9737 -1.3048 -0.4072 C.3 1 LIG1 -0.0505 - 4 C 2.6388 -1.6853 -1.8487 C.3 1 LIG1 -0.0528 - 5 C 3.1458 -0.6424 -2.8397 C.3 1 LIG1 -0.0530 - 6 C 2.6503 0.7581 -2.4959 C.3 1 LIG1 -0.0528 - 7 C 2.9839 1.1382 -1.0536 C.3 1 LIG1 -0.0505 - 8 H 0.6557 1.1542 0.4607 H 1 LIG1 0.0232 - 9 H 0.6478 -0.5562 0.9081 H 1 LIG1 0.0232 - 10 H 0.4392 -0.0840 -0.7835 H 1 LIG1 0.0232 - 11 H 2.9316 0.3596 0.9431 H 1 LIG1 0.0298 - 12 H 2.5484 -2.0480 0.2778 H 1 LIG1 0.0268 - 13 H 4.0632 -1.3509 -0.2778 H 1 LIG1 0.0268 - 14 H 3.0861 -2.6588 -2.0822 H 1 LIG1 0.0265 - 15 H 1.5550 -1.8040 -1.9616 H 1 LIG1 0.0265 - 16 H 4.2430 -0.6482 -2.8423 H 1 LIG1 0.0265 - 17 H 2.8244 -0.9091 -3.8522 H 1 LIG1 0.0265 - 18 H 3.1052 1.4851 -3.1790 H 1 LIG1 0.0265 - 19 H 1.5667 0.8148 -2.6555 H 1 LIG1 0.0265 - 20 H 4.0736 1.2348 -0.9613 H 1 LIG1 0.0268 - 21 H 2.5648 2.1260 -0.8271 H 1 LIG1 0.0268 -@BOND - 1 2 7 1 - 2 2 3 1 - 3 6 7 1 - 4 5 6 1 - 5 4 5 1 - 6 3 4 1 - 7 1 2 1 - 8 1 8 1 - 9 1 9 1 - 10 1 10 1 - 11 2 11 1 - 12 3 12 1 - 13 3 13 1 - 14 4 14 1 - 15 4 15 1 - 16 5 16 1 - 17 5 17 1 - 18 6 18 1 - 19 6 19 1 - 20 7 20 1 - 21 7 21 1 diff --git a/src/openfe/tests/data/lomap_basic/methylcyclohexane.sdf b/src/openfe/tests/data/lomap_basic/methylcyclohexane.sdf new file mode 100644 index 000000000..b7eb9621c --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/methylcyclohexane.sdf @@ -0,0 +1,51 @@ +methylcyclohexane + -OEChem-08192610333D + + 21 21 0 0 0 0 0 0 0999 V2000 + 0.9730 0.1554 0.1412 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4934 0.1043 -0.0303 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9737 -1.3048 -0.4072 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6388 -1.6853 -1.8487 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1458 -0.6424 -2.8397 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6503 0.7581 -2.4959 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9839 1.1382 -1.0536 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6557 1.1542 0.4607 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6478 -0.5562 0.9081 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4392 -0.0840 -0.7835 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9316 0.3596 0.9431 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5484 -2.0480 0.2778 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0632 -1.3509 -0.2778 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0861 -2.6588 -2.0822 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5550 -1.8040 -1.9616 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.2430 -0.6482 -2.8423 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.8244 -0.9091 -3.8522 H 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1052 1.4851 -3.1790 H 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5667 0.8148 -2.6555 H 0 0 0 0 0 0 0 0 0 0 0 0 + 4.0736 1.2348 -0.9613 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.5648 2.1260 -0.8271 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2 7 1 0 0 0 0 + 2 3 1 0 0 0 0 + 6 7 1 0 0 0 0 + 5 6 1 0 0 0 0 + 4 5 1 0 0 0 0 + 3 4 1 0 0 0 0 + 1 2 1 0 0 0 0 + 1 8 1 0 0 0 0 + 1 9 1 0 0 0 0 + 1 10 1 0 0 0 0 + 2 11 1 0 0 0 0 + 3 12 1 0 0 0 0 + 3 13 1 0 0 0 0 + 4 14 1 0 0 0 0 + 4 15 1 0 0 0 0 + 5 16 1 0 0 0 0 + 5 17 1 0 0 0 0 + 6 18 1 0 0 0 0 + 6 19 1 0 0 0 0 + 7 20 1 0 0 0 0 + 7 21 1 0 0 0 0 +M END +> +-0.062400 -0.043900 -0.050500 -0.052800 -0.053000 -0.052800 -0.050500 0.023200 0.023200 0.023200 0.029800 0.026800 0.026800 0.026500 0.026500 0.026500 0.026500 0.026500 0.026500 0.026800 0.026800 + +$$$$ diff --git a/src/openfe/tests/data/lomap_basic/toluene.sdf b/src/openfe/tests/data/lomap_basic/toluene.sdf new file mode 100644 index 000000000..c10f889bb --- /dev/null +++ b/src/openfe/tests/data/lomap_basic/toluene.sdf @@ -0,0 +1,39 @@ +toluene + -OEChem-08192610343D + + 15 15 0 0 0 0 0 0 0999 V2000 + 0.9562 0.0874 0.1225 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4532 0.1169 0.0327 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1480 1.3313 -0.0192 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5410 1.3447 -0.1106 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2502 0.1457 -0.1538 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.5672 -1.0681 -0.1065 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1745 -1.0830 -0.0148 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5405 1.0944 0.2295 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6412 -0.4972 0.9928 H 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5343 -0.3590 -0.7834 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6097 2.2757 0.0116 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0726 2.2915 -0.1488 H 0 0 0 0 0 0 0 0 0 0 0 0 + 6.3343 0.1573 -0.2252 H 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1186 -2.0039 -0.1418 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6530 -2.0368 0.0195 H 0 0 0 0 0 0 0 0 0 0 0 0 + 2 3 2 0 0 0 0 + 3 4 1 0 0 0 0 + 2 7 1 0 0 0 0 + 6 7 2 0 0 0 0 + 5 6 1 0 0 0 0 + 4 5 2 0 0 0 0 + 1 2 1 0 0 0 0 + 1 8 1 0 0 0 0 + 1 9 1 0 0 0 0 + 1 10 1 0 0 0 0 + 3 11 1 0 0 0 0 + 4 12 1 0 0 0 0 + 5 13 1 0 0 0 0 + 6 14 1 0 0 0 0 + 7 15 1 0 0 0 0 +M END +> +-0.039700 -0.050400 -0.058800 -0.061500 -0.061700 -0.061500 -0.058800 0.027800 0.027800 0.027800 0.062000 0.061800 0.061800 0.061800 0.062000 + +$$$$ diff --git a/src/openfe/tests/data/openmm_rfe/charged_benzenes.sdf b/src/openfe/tests/data/openmm_rfe/charged_benzenes.sdf index ea2735835..80853c45a 100644 --- a/src/openfe/tests/data/openmm_rfe/charged_benzenes.sdf +++ b/src/openfe/tests/data/openmm_rfe/charged_benzenes.sdf @@ -1,5 +1,5 @@ benzene - PyMOL2.5 3D 0 + RDKit 3D 12 12 0 0 0 0 0 0 0 0999 V2000 1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 @@ -14,22 +14,27 @@ benzene -2.5079 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -1.2540 -2.1719 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 1.2540 -2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 2 0 0 0 0 - 1 6 1 0 0 0 0 - 1 7 1 0 0 0 0 - 2 3 1 0 0 0 0 - 2 8 1 0 0 0 0 - 3 4 2 0 0 0 0 - 3 9 1 0 0 0 0 - 4 5 1 0 0 0 0 - 4 10 1 0 0 0 0 - 5 6 2 0 0 0 0 - 5 11 1 0 0 0 0 - 6 12 1 0 0 0 0 + 1 2 2 0 + 1 6 1 0 + 1 7 1 0 + 2 3 1 0 + 2 8 1 0 + 3 4 2 0 + 3 9 1 0 + 4 5 1 0 + 4 10 1 0 + 5 6 2 0 + 5 11 1 0 + 6 12 1 0 M END + +> +-0.13019000614682832 -0.1301299991707007 -0.1301299991707007 -0.1301299991707007 -0.1301299991707007 -0.1301299991707007 0.13014000033338866 0.13014000033338866 0.13014000033338866 +0.13014000033338866 0.13014000033338866 0.13014000033338866 + $$$$ aniline - PyMOL2.5 3D 0 + RDKit 3D 15 15 0 0 0 0 0 0 0 0999 V2000 1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 @@ -41,36 +46,42 @@ aniline 3.2106 0.8251 0.4756 H 0 0 0 0 0 0 0 0 0 0 0 0 3.2117 -0.8238 0.4772 H 0 0 0 0 0 0 0 0 0 0 0 0 3.2117 -0.0000 -0.9520 H 0 0 0 0 0 0 0 0 0 0 0 0 - 2.8745 -0.0000 0.0000 N 0 3 0 0 0 0 0 0 0 0 0 0 + 2.8745 -0.0000 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 1.2540 2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -1.2540 2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -2.5079 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -1.2540 -2.1719 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 1.2540 -2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 2 0 0 0 0 - 1 6 1 0 0 0 0 - 1 10 1 0 0 0 0 - 2 3 1 0 0 0 0 - 2 11 1 0 0 0 0 - 3 4 2 0 0 0 0 - 3 12 1 0 0 0 0 - 4 5 1 0 0 0 0 - 4 13 1 0 0 0 0 - 5 6 2 0 0 0 0 - 5 14 1 0 0 0 0 - 6 15 1 0 0 0 0 - 7 10 1 0 0 0 0 - 8 10 1 0 0 0 0 - 9 10 1 0 0 0 0 + 1 2 2 0 + 1 6 1 0 + 1 10 1 0 + 2 3 1 0 + 2 11 1 0 + 3 4 2 0 + 3 12 1 0 + 4 5 1 0 + 4 13 1 0 + 5 6 2 0 + 5 14 1 0 + 6 15 1 0 + 7 10 1 0 + 8 10 1 0 + 9 10 1 0 +M CHG 1 10 1 M END + +> +-0.082359999914964038 -0.09780000199874242 -0.098719999690850574 -0.061870001753171283 -0.098719999690850574 -0.09780000199874242 0.46404001067082085 0.46404001067082085 +0.46404001067082085 -0.69748002340396242 0.15680000136295955 0.17632999966541926 0.17636999438206355 0.17632999966541926 0.15680000136295955 + $$$$ benzoic_acid - PyMOL2.5 3D 0 + RDKit 3D 14 14 0 0 0 0 0 0 0 0999 V2000 1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 2.7445 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 3.2607 -1.0833 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0 + 3.2607 -1.0833 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 0.7022 1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.7023 1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 3.4265 1.0159 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 @@ -82,19 +93,25 @@ benzoic_acid -2.5079 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -1.2540 -2.1719 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 1.2540 -2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 1 0 0 0 0 - 1 4 2 0 0 0 0 - 1 9 1 0 0 0 0 - 2 3 1 0 0 0 0 - 2 6 2 0 0 0 0 - 4 5 1 0 0 0 0 - 4 10 1 0 0 0 0 - 5 7 2 0 0 0 0 - 5 11 1 0 0 0 0 - 7 8 1 0 0 0 0 - 7 12 1 0 0 0 0 - 8 9 2 0 0 0 0 - 8 13 1 0 0 0 0 - 9 14 1 0 0 0 0 + 1 2 1 0 + 1 4 2 0 + 1 9 1 0 + 2 3 1 0 + 2 6 2 0 + 4 5 1 0 + 4 10 1 0 + 5 7 2 0 + 5 11 1 0 + 7 8 1 0 + 7 12 1 0 + 8 9 2 0 + 8 13 1 0 + 9 14 1 0 +M CHG 1 3 -1 M END + +> +-0.12568999826908112 0.90591001510620117 -0.83410000801086426 -0.10845000296831131 -0.16561999917030334 -0.83410000801086426 -0.16110999882221222 -0.16561999917030334 -0.10845000296831131 +0.14900000393390656 0.10098999738693237 0.097249999642372131 0.10098999738693237 0.14900000393390656 + $$$$ diff --git a/src/openfe/tests/data/openmm_rfe/ligand_23.sdf b/src/openfe/tests/data/openmm_rfe/ligand_23.sdf index 3a503794e..ee1052b3e 100644 --- a/src/openfe/tests/data/openmm_rfe/ligand_23.sdf +++ b/src/openfe/tests/data/openmm_rfe/ligand_23.sdf @@ -77,4 +77,10 @@ ligand_23 6 29 1 0 1 27 1 0 M END +> (1) +-0.096620000795357763 -0.12906000007771784 0.052329998566872545 -0.1420399992623263 0.052329998566872545 -0.12906000007771784 -0.058970000491374068 0.68882000456667614 -0.54965001334332753 +-0.46614998568677241 0.11851000051117605 -0.28589999665402704 0.43860000382281011 -0.72825998057507801 0.54181998978472423 -0.29723998893880182 -0.55049002160214711 0.70070999871111583 +-0.57516002644681263 -0.24832999695920283 -0.12739999581956202 0.15659999857760137 -0.18966999639653498 -0.058970000491374068 0.097960002823836267 0.093230001731879175 0.14708000431872076 +0.15737000118113226 0.15737000118113226 0.331019997700221 0.17687000344610876 0.026149999453789659 0.17281000326491064 0.32982999096728033 0.096780002220637262 0.096780002220637262 + $$$$ diff --git a/src/openfe/tests/data/openmm_rfe/ligand_55.sdf b/src/openfe/tests/data/openmm_rfe/ligand_55.sdf index 073d61e2b..0c183511d 100644 --- a/src/openfe/tests/data/openmm_rfe/ligand_55.sdf +++ b/src/openfe/tests/data/openmm_rfe/ligand_55.sdf @@ -70,4 +70,10 @@ ligand_55 6 23 1 0 1 21 1 0 M END +> (1) +-0.096989995263742676 -0.12775999160878587 0.05143000332243515 -0.14379000517003465 0.05143000332243515 -0.12775999160878587 -0.060149999730514755 0.68993997720606404 -0.54237001987569256 +-0.47453999372594285 0.12862999884016585 -0.28791001292340684 0.44437000302202773 -0.68067002149693889 0.56722998765833454 -0.34415998908154893 -0.53615999075047893 0.75111001876719075 +-0.52239000650517864 -0.060149999730514755 0.14786000696547102 0.15815000382788252 0.15815000382788252 0.3266800060642488 0.17450000492460799 0.033190002269817123 0.14128999558813643 +0.34145999101526808 0.13978999999888014 0.053180003143621216 0.053180003143621216 -0.45994999858014513 0.053180003143621216 + $$$$ diff --git a/src/openfe/tests/protocols/openmm_ahfe/test_ahfe_protocol.py b/src/openfe/tests/protocols/openmm_ahfe/test_ahfe_protocol.py index 38d83d393..7320261d1 100644 --- a/src/openfe/tests/protocols/openmm_ahfe/test_ahfe_protocol.py +++ b/src/openfe/tests/protocols/openmm_ahfe/test_ahfe_protocol.py @@ -1,5 +1,6 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +import re import sys from math import sqrt from unittest import mock @@ -8,6 +9,7 @@ import mdtraj as mdt import numpy as np import pytest +from gufe.protocols import ProtocolValidationError from numpy.testing import assert_allclose from openff.units import unit as offunit from openff.units.openmm import ensure_quantity, from_openmm @@ -619,76 +621,30 @@ def assign_fictitious_charges(offmol): assert pytest.approx(c) == prop_chgs[i] -@pytest.mark.parametrize( - "method, backend, ref_key", - [ - ("am1bcc", "ambertools", "ambertools"), - pytest.param( - "am1bcc", - "openeye", - "openeye", - marks=pytest.mark.skipif(not HAS_OPENEYE, reason="needs oechem"), - ), - pytest.param( - "nagl", - "rdkit", - "nagl", - marks=pytest.mark.skipif( - not HAS_NAGL or HAS_OPENEYE or sys.platform.startswith("darwin"), - reason="needs NAGL (without oechem) and/or on macos", - ), - ), - pytest.param( - "espaloma", - "rdkit", - "espaloma", - marks=pytest.mark.skipif(not HAS_ESPALOMA_CHARGE, reason="needs espaloma charge"), - ), - ], -) -def test_dry_run_charge_backends( - CN_molecule, tmp_path, method, backend, ref_key, protocol_dry_settings, am1bcc_ref_charges -): +def test_dry_run_missing_charges(CN_molecule, protocol_dry_settings): """ - Check that partial charge generation with different backends - works as expected. + Make sure an error is raised if a nondeterministic charge method would be used at run time """ - protocol_dry_settings.partial_charge_settings.partial_charge_method = method - protocol_dry_settings.partial_charge_settings.off_toolkit_backend = backend + protocol_dry_settings.partial_charge_settings.partial_charge_method = "am1bcc" + protocol_dry_settings.partial_charge_settings.off_toolkit_backend = "ambertools" protocol_dry_settings.partial_charge_settings.nagl_model = "openff-gnn-am1bcc-0.1.0-rc.1.pt" protocol = openmm_afe.AbsoluteSolvationProtocol(settings=protocol_dry_settings) # Create ChemicalSystems - stateA = ChemicalSystem({"benzene": CN_molecule, "solvent": SolventComponent()}) + stateA = ChemicalSystem( + {"benzene": CN_molecule, "solvent": SolventComponent()}, name="CN no charges" + ) stateB = ChemicalSystem({"solvent": SolventComponent()}) - # Create DAG from protocol, get the vacuum and solvent units - # and eventually dry run the first solvent unit - dag = protocol.create(stateA=stateA, stateB=stateB, mapping=None) - prot_units = list(dag.protocol_units) - - vac_setup_units = _get_units(prot_units, UNIT_TYPES["vacuum"]["setup"]) - - # check vac_unit charges - results = vac_setup_units[0].run(dry=True, scratch_basepath=tmp_path, shared_basepath=tmp_path) - system = results["alchem_system"] - nonbond = [f for f in system.getForces() if isinstance(f, CustomNonbondedForce)] - assert len(nonbond) == 4 - - custom_elec = [n for n in nonbond if n.getGlobalParameterName(0) == "lambda_electrostatics"][0] - - charges = [] - for i in range(system.getNumParticles()): - c, s = custom_elec.getParticleParameters(i) - charges.append(c) - - assert_allclose( - am1bcc_ref_charges[ref_key], - charges * offunit.elementary_charge, - rtol=1e-4, - ) + with pytest.raises( + ProtocolValidationError, + match=re.escape( + "SmallMoleculeComponent(name=) from system CN no charges would have am1bcc charges generated at runtime which is non-deterministic." + ), + ): + _ = protocol.create(stateA=stateA, stateB=stateB, mapping=None) @pytest.fixture diff --git a/src/openfe/tests/protocols/openmm_md/test_plain_md_protocol.py b/src/openfe/tests/protocols/openmm_md/test_plain_md_protocol.py index 279797536..3a33fe222 100644 --- a/src/openfe/tests/protocols/openmm_md/test_plain_md_protocol.py +++ b/src/openfe/tests/protocols/openmm_md/test_plain_md_protocol.py @@ -3,7 +3,7 @@ import json import logging import pathlib -import sys +import re from unittest import mock import gufe @@ -11,13 +11,13 @@ import openmm import pytest from gufe import ChemicalSystem, LigandAtomMapping, SmallMoleculeComponent +from gufe.protocols.errors import ProtocolValidationError from numpy.testing import assert_allclose from openff.units import unit -from openff.units.openmm import from_openmm, to_openmm +from openff.units.openmm import to_openmm from openmm import MonteCarloBarostat, NonbondedForce from openmm import unit as omm_unit from openmmtools.states import ThermodynamicState -from pydantic import ValidationError import openfe from openfe.protocols import openmm_md @@ -28,11 +28,6 @@ PlainMDSimulationUnit, ) from openfe.protocols.openmm_utils import serialization -from openfe.protocols.openmm_utils.charge_generation import ( - HAS_ESPALOMA_CHARGE, - HAS_NAGL, - HAS_OPENEYE, -) from openfe.tests.conftest import HAS_ESPALOMA @@ -275,60 +270,26 @@ def test_dry_run_espaloma_vacuum_user_charges( assert_allclose(charges, expected_charges, rtol=1e-6) -@pytest.mark.parametrize( - "method, backend, ref_key", - [ - ("am1bcc", "ambertools", "ambertools"), - pytest.param( - "am1bcc", - "openeye", - "openeye", - marks=pytest.mark.skipif(not HAS_OPENEYE, reason="needs oechem"), - ), - pytest.param( - "nagl", - "rdkit", - "nagl", - marks=pytest.mark.skipif( - not HAS_NAGL or HAS_OPENEYE or sys.platform.startswith("darwin"), - reason="needs NAGL (without oechem) and/or on macos", - ), - ), - pytest.param( - "espaloma", - "rdkit", - "espaloma", - marks=pytest.mark.skipif(not HAS_ESPALOMA_CHARGE, reason="needs espaloma charge"), - ), - ], -) -def test_dry_run_charge_backends( - CN_molecule, tmp_path, method, backend, ref_key, vac_settings, am1bcc_ref_charges +def test_dry_run_missing_charges( + CN_molecule, + vac_settings, ): - vac_settings.partial_charge_settings.partial_charge_method = method - vac_settings.partial_charge_settings.off_toolkit_backend = backend + # an error should be raised if a nondeterministic charge method would be used at run time + vac_settings.partial_charge_settings.partial_charge_method = "am1bcc" + vac_settings.partial_charge_settings.off_toolkit_backend = "ambertools" vac_settings.partial_charge_settings.nagl_model = "openff-gnn-am1bcc-0.1.0-rc.1.pt" protocol = PlainMDProtocol(settings=vac_settings) - csystem = openfe.ChemicalSystem({"ligand": CN_molecule}) - - dag = protocol.create(stateA=csystem, stateB=csystem, mapping=None) - md_unit = list(dag.protocol_units)[0] + csystem = openfe.ChemicalSystem({"ligand": CN_molecule}, name="CN no charges") - result = md_unit.run(dry=True, scratch_basepath=tmp_path, shared_basepath=tmp_path) - system = result["debug"]["system"] - - nonbond = [f for f in system.getForces() if isinstance(f, NonbondedForce)][0] - - charges = [] - for i in range(system.getNumParticles()): - c, s, e = nonbond.getParticleParameters(i) - charges.append(from_openmm(c)) - - charges = unit.Quantity.from_list(charges) - - assert_allclose(am1bcc_ref_charges[ref_key], charges, rtol=1e-4) + with pytest.raises( + ProtocolValidationError, + match=re.escape( + "SmallMoleculeComponent(name=) from system CN no charges would have am1bcc charges generated at runtime which is non-deterministic." + ), + ): + _ = protocol.create(stateA=csystem, stateB=csystem, mapping=None) def test_dry_many_molecules_solvent(benzene_many_solv_system, tmp_path): @@ -351,72 +312,6 @@ def test_dry_many_molecules_solvent(benzene_many_solv_system, tmp_path): dag_unit.run(dry=True, scratch_basepath=tmp_path, shared_basepath=tmp_path)["debug"]["system"] -BENZ = """\ -benzene - PyMOL2.5 3D 0 - - 12 12 0 0 0 0 0 0 0 0999 V2000 - 1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.7022 1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - -0.7023 1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - -1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - -0.7023 -1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.7023 -1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 2.5079 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1.2540 2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - -1.2540 2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - -2.5079 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - -1.2540 -2.1719 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1.2540 -2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 2 0 0 0 0 - 1 6 1 0 0 0 0 - 1 7 1 0 0 0 0 - 2 3 1 0 0 0 0 - 2 8 1 0 0 0 0 - 3 4 2 0 0 0 0 - 3 9 1 0 0 0 0 - 4 5 1 0 0 0 0 - 4 10 1 0 0 0 0 - 5 6 2 0 0 0 0 - 5 11 1 0 0 0 0 - 6 12 1 0 0 0 0 -M END -$$$$ -""" - - -PYRIDINE = """\ -pyridine - PyMOL2.5 3D 0 - - 11 11 0 0 0 0 0 0 0 0999 V2000 - 1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - -0.7023 1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - -1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - -0.7023 -1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 0.7023 -1.2164 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 2.4940 -0.0325 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1.2473 -2.1604 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - -1.2473 -2.1604 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - -2.4945 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - -1.2753 2.1437 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 0.7525 1.3034 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 1 5 1 0 0 0 0 - 1 6 1 0 0 0 0 - 1 11 2 0 0 0 0 - 2 3 2 0 0 0 0 - 2 10 1 0 0 0 0 - 3 4 1 0 0 0 0 - 3 9 1 0 0 0 0 - 4 5 2 0 0 0 0 - 4 8 1 0 0 0 0 - 5 7 1 0 0 0 0 - 2 11 1 0 0 0 0 -M END -$$$$ -""" - - def test_dry_run_ligand_tip4p(benzene_system, tmp_path): """ Test that we can create a system with virtual sites in the diff --git a/src/openfe/tests/protocols/openmm_rfe/test_hybrid_top_protocol.py b/src/openfe/tests/protocols/openmm_rfe/test_hybrid_top_protocol.py index 611e6d0f9..1c0524ec6 100644 --- a/src/openfe/tests/protocols/openmm_rfe/test_hybrid_top_protocol.py +++ b/src/openfe/tests/protocols/openmm_rfe/test_hybrid_top_protocol.py @@ -3,6 +3,7 @@ import copy import json import logging +import re import sys import xml.etree.ElementTree as ET from importlib import resources @@ -16,6 +17,8 @@ import numpy as np import openmm import pytest +from gufe import LigandAtomMapping +from gufe.protocols import ProtocolValidationError from kartograf import KartografAtomMapper from kartograf.atom_aligner import align_mol_shape from numpy.testing import assert_allclose @@ -410,7 +413,7 @@ def test_dry_many_molecules_solvent( BENZ = """\ benzene - PyMOL2.5 3D 0 + RDKit 3D 12 12 0 0 0 0 0 0 0 0999 V2000 1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 @@ -425,26 +428,32 @@ def test_dry_many_molecules_solvent( -2.5079 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -1.2540 -2.1719 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 1.2540 -2.1720 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 - 1 2 2 0 0 0 0 - 1 6 1 0 0 0 0 - 1 7 1 0 0 0 0 - 2 3 1 0 0 0 0 - 2 8 1 0 0 0 0 - 3 4 2 0 0 0 0 - 3 9 1 0 0 0 0 - 4 5 1 0 0 0 0 - 4 10 1 0 0 0 0 - 5 6 2 0 0 0 0 - 5 11 1 0 0 0 0 - 6 12 1 0 0 0 0 + 1 2 2 0 + 1 6 1 0 + 1 7 1 0 + 2 3 1 0 + 2 8 1 0 + 3 4 2 0 + 3 9 1 0 + 4 5 1 0 + 4 10 1 0 + 5 6 2 0 + 5 11 1 0 + 6 12 1 0 M END + +> +benzene + +> +-0.13016000265876451 -0.13009999568263689 -0.13009999568263689 -0.13009999568263689 -0.13009999568263689 -0.13009999568263689 0.13010999684532484 0.13010999684532484 0.13010999684532484 0.13010999684532484 0.13010999684532484 0.13010999684532484 + $$$$ """ - PYRIDINE = """\ pyridine - PyMOL2.5 3D 0 + RDKit 3D 11 11 0 0 0 0 0 0 0 0999 V2000 1.4045 -0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 @@ -458,25 +467,30 @@ def test_dry_many_molecules_solvent( -2.4945 -0.0000 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 -1.2753 2.1437 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0 0.7525 1.3034 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 1 5 1 0 0 0 0 - 1 6 1 0 0 0 0 - 1 11 2 0 0 0 0 - 2 3 2 0 0 0 0 - 2 10 1 0 0 0 0 - 3 4 1 0 0 0 0 - 3 9 1 0 0 0 0 - 4 5 2 0 0 0 0 - 4 8 1 0 0 0 0 - 5 7 1 0 0 0 0 - 2 11 1 0 0 0 0 + 1 5 2 0 + 1 6 1 0 + 1 11 1 0 + 2 3 1 0 + 2 10 1 0 + 3 4 2 0 + 3 9 1 0 + 4 5 1 0 + 4 8 1 0 + 5 7 1 0 + 2 11 2 0 M END + +> +0.39228000661188905 0.39228000661188905 -0.24653000215237791 -0.093170007860118698 -0.24653000215237791 0.021279994229024105 0.14280999621207063 0.1373999955301935 0.14280999621207063 +0.021279994229024105 -0.66390997747128655 + $$$$ """ def test_setup_core_element_change(vac_settings, tmp_path): - benz = openfe.SmallMoleculeComponent(Chem.MolFromMolBlock(BENZ, removeHs=False)) - pyr = openfe.SmallMoleculeComponent(Chem.MolFromMolBlock(PYRIDINE, removeHs=False)) + benz = openfe.SmallMoleculeComponent.from_sdf_string(BENZ) + pyr = openfe.SmallMoleculeComponent.from_sdf_string(PYRIDINE) mapping = openfe.LigandAtomMapping( benz, pyr, {0: 0, 1: 10, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 8: 9, 9: 8, 10: 7, 11: 6} @@ -731,39 +745,13 @@ def test_setup_ligand_system_cutoff( assert f_cutoff == cutoff -@pytest.mark.parametrize( - "method, backend, ref_key", - [ - ("am1bcc", "ambertools", "ambertools"), - pytest.param( - "am1bcc", - "openeye", - "openeye", - marks=pytest.mark.skipif(not HAS_OPENEYE, reason="needs oechem"), - ), - pytest.param( - "nagl", - "rdkit", - "nagl", - marks=pytest.mark.skipif( - not HAS_NAGL or HAS_OPENEYE or sys.platform.startswith("darwin"), - reason="needs NAGL (without oechem) and/or on macos", - ), - ), - pytest.param( - "espaloma", - "rdkit", - "espaloma", - marks=pytest.mark.skipif(not HAS_ESPALOMA_CHARGE, reason="needs espaloma charge"), - ), - ], -) def test_setup_charge_backends( - CN_molecule, tmp_path, method, backend, ref_key, vac_settings, am1bcc_ref_charges + CN_molecule, + vac_settings, ): - vac_settings.partial_charge_settings.partial_charge_method = method - vac_settings.partial_charge_settings.off_toolkit_backend = backend - vac_settings.partial_charge_settings.nagl_model = "openff-gnn-am1bcc-0.1.0-rc.1.pt" + # make sure an error is raised if a nondeterministic charge method would be used at run time + vac_settings.partial_charge_settings.partial_charge_method = "am1bcc" + vac_settings.partial_charge_settings.off_toolkit_backend = "ambertools" protocol = openmm_rfe.RelativeHybridTopologyProtocol( settings=vac_settings, @@ -772,52 +760,21 @@ def test_setup_charge_backends( # make stateB molecule offmolB = Molecule.from_smiles("CCN") offmolB.generate_conformers() - molB = openfe.SmallMoleculeComponent.from_openff(offmolB) - a_molB = align_mol_shape(molB, ref_mol=CN_molecule) - mapper = KartografAtomMapper(atom_map_hydrogens=True) - mapping = next(mapper.suggest_mappings(CN_molecule, a_molB)) - - systemA = openfe.ChemicalSystem({"l": CN_molecule}) - systemB = openfe.ChemicalSystem({"l": a_molB}) - - dag = protocol.create(stateA=systemA, stateB=systemB, mapping=mapping) - - dag_setup_unit = [pu for pu in dag.protocol_units if isinstance(pu, HybridTopologySetupUnit)][0] - - results = dag_setup_unit.run(dry=True, scratch_basepath=tmp_path, shared_basepath=tmp_path) - htf = results["hybrid_factory"] - hybrid_system = results["hybrid_system"] - - # get the standard nonbonded force - nonbond = [f for f in hybrid_system.getForces() if isinstance(f, NonbondedForce)] - assert len(nonbond) == 1 - - # get the particle parameter offsets - c_offsets = {} - for i in range(nonbond[0].getNumParticleParameterOffsets()): - offset = nonbond[0].getParticleParameterOffset(i) - c_offsets[offset[1]] = ensure_quantity(offset[2], "openff") + molB = openfe.SmallMoleculeComponent.from_openff(offmolB, name="CCN") + mapping = LigandAtomMapping( + componentA=CN_molecule, componentB=molB, componentA_to_componentB={0: 1} + ) + systemA = openfe.ChemicalSystem({"l": CN_molecule}, name="CN no charges") + systemB = openfe.ChemicalSystem({"l": molB}) - # See the user charges test below for an idea of what we're doing here - # In this particular case we are solely checking that the old atoms - # match the reference charges in am1bcc_ref_charges - for i in range(hybrid_system.getNumParticles()): - c, s, e = nonbond[0].getParticleParameters(i) - # get the particle charge (c) - c = ensure_quantity(c, "openff") - # particle charge (c) is equal to molA particle charge - # offset (c_offsets) is equal to -(molA particle charge) - if i in htf._atom_classes["unique_old_atoms"]: - idx = htf._hybrid_to_old_map[i] - ref = am1bcc_ref_charges[ref_key][idx] - np.testing.assert_allclose(c, ref, rtol=1e-4) - np.testing.assert_allclose(c_offsets[i], -ref, rtol=1e-4) - # particle charge (c) is equal to molA particle charge - # offset (c_offsets) is equal to difference between molB and molA - elif i in htf._atom_classes["core_atoms"]: - old_i = htf._hybrid_to_old_map[i] - ref = am1bcc_ref_charges[ref_key][i] - np.testing.assert_allclose(c, ref, rtol=1e-4) + with pytest.raises( + ProtocolValidationError, + match=re.escape( + # this is the CN failing as it has no name + "The following Components are affected: SmallMoleculeComponent(name=)" + ), + ): + _ = protocol.create(stateA=systemA, stateB=systemB, mapping=mapping) def test_setup_same_mol_different_charges(benzene_modifications_uncharged, vac_settings, tmp_path): @@ -1714,7 +1671,6 @@ def tyk2_reference_xml(): return ET.fromstring(xmldata) -@pytest.mark.slow class TestTyk2XmlRegression: """Generates Hybrid system XML and performs regression test""" @@ -2647,6 +2603,9 @@ def test_high_heavy_atom_mapping_ratio_warning(atom_mapping_basic_test_files, va componentA_to_componentB={0: 0, 1: 1, 2: 10, 3: 9, 8: 8}, ) + # make sure the mapping ratio is over 2 which should trigger the warning + assert mapping.get_heavy_atom_mapping_ratio() >= 2.0 + with pytest.warns( UserWarning, match="The ratio of alchemical to mapped heavy atoms: 2.8 is large, please review the mapping if the simulation is unstable.", diff --git a/src/openfe/tests/protocols/test_openmmutils.py b/src/openfe/tests/protocols/test_openmmutils.py index f1672b6ba..2e5e3c2c5 100644 --- a/src/openfe/tests/protocols/test_openmmutils.py +++ b/src/openfe/tests/protocols/test_openmmutils.py @@ -4,6 +4,7 @@ import gzip import logging import os +import re import sys from importlib import resources from pathlib import Path @@ -11,9 +12,12 @@ import numpy as np import pytest +from gufe import ChemicalSystem from gufe.components.errors import ComponentValidationError +from gufe.protocols.errors import ProtocolValidationError from gufe.settings import OpenMMSystemGeneratorFFSettings, ThermoSettings from numpy.testing import assert_allclose, assert_equal +from openff.toolkit import ForceField from openff.toolkit import Molecule as OFFMol from openff.toolkit.utils.toolkit_registry import ToolkitRegistry from openff.toolkit.utils.toolkits import RDKitToolkitWrapper @@ -1429,3 +1433,136 @@ def test_assign_offmol_residue_metadata(self, benzene_modifications, specs, expe assert _get_offmol_resname(off) == resname assert _get_offmol_metadata(off, "residue_number") == residue_number assert assigned[smc] == resname + + +class TestChargeValidation: + """Test validation of nondeterministic partial charge assignment.""" + + @pytest.fixture + def benzene_charged_system(self, benzene_modifications): + return ChemicalSystem({"ligand": benzene_modifications["benzene"]}, name="charged") + + @pytest.fixture + def benzene_no_charge_system(self, benzene_modifications_uncharged): + return ChemicalSystem( + {"ligand": benzene_modifications_uncharged["benzene"]}, name="no charges" + ) + + @pytest.fixture + def mixed_charge_system(self, benzene_modifications, benzene_modifications_uncharged): + return ChemicalSystem( + { + "benzene": benzene_modifications["benzene"], + "toluene": benzene_modifications_uncharged["toluene"], + }, + name="mixed charges", + ) + + @pytest.fixture + def many_no_charge_system(self, benzene_modifications_uncharged): + return ChemicalSystem( + { + "benzene": benzene_modifications_uncharged["benzene"], + "toluene": benzene_modifications_uncharged["toluene"], + "phenol": benzene_modifications_uncharged["phenol"], + }, + name="many no charges", + ) + + def test_gaff_with_molecule_charges(self, benzene_charged_system): + system_validation.validate_nondeterministic_charges( + benzene_charged_system, small_molecule_forcefield="gaff-2.11" + ) + + def test_gaff_no_charges(self, benzene_no_charge_system): + with pytest.raises( + ProtocolValidationError, + match=re.escape( + "The following Components are affected: SmallMoleculeComponent(name=benzene)" + ), + ): + system_validation.validate_nondeterministic_charges( + benzene_no_charge_system, small_molecule_forcefield="gaff-2.11" + ) + + def test_espaloma_with_molecule_charges(self, benzene_charged_system): + system_validation.validate_nondeterministic_charges( + benzene_charged_system, small_molecule_forcefield="espaloma-0.3.2" + ) + + def test_espaloma_no_charges(self, benzene_no_charge_system): + with pytest.raises( + ProtocolValidationError, + match=re.escape( + "The following Components are affected: SmallMoleculeComponent(name=benzene)" + ), + ): + system_validation.validate_nondeterministic_charges( + benzene_no_charge_system, small_molecule_forcefield="espaloma-0.3.2" + ) + + def test_openff_with_molecule_charges(self, benzene_charged_system): + system_validation.validate_nondeterministic_charges( + benzene_charged_system, small_molecule_forcefield="openff-2.2.0.offxml" + ) + + @pytest.mark.parametrize("forcefield", ["openff-1.0.0.offxml", "openff-2.2.0.offxml", "openff-2.2.0"]) + def test_openff_no_charges(self, benzene_no_charge_system, forcefield): + # Test ffs with/out LibraryCharges handler, and with/out .offxml extension + with pytest.raises( + ProtocolValidationError, + match=re.escape( + "The following Components are affected: SmallMoleculeComponent(name=benzene)" + ), + ): + system_validation.validate_nondeterministic_charges( + benzene_no_charge_system, small_molecule_forcefield=forcefield + ) + + def test_openff_nagl_no_charges(self, benzene_no_charge_system): + system_validation.validate_nondeterministic_charges( + benzene_no_charge_system, small_molecule_forcefield="openff-2.3.0.offxml" + ) + + def test_openff_lib_charges_no_charges(self, benzene_no_charge_system, benzene_modifications): + # add some library charges to the force field and test using a string + benzene = benzene_modifications["benzene"].to_openff() + # use a force field with an am1bcc handler + ff = ForceField("openff-2.2.0.offxml") + lib_charge_handler = ff.get_parameter_handler("LibraryCharges") + # make a new parameter + lib_charge = lib_charge_handler._INFOTYPE.from_molecule(benzene) + # add it to the handler + lib_charge_handler.add_parameter(parameter=lib_charge) + # run the validation + system_validation.validate_nondeterministic_charges( + benzene_no_charge_system, small_molecule_forcefield=ff.to_string() + ) + + def test_openff_mixed_charges(self, mixed_charge_system): + # make sure an error is raised if not all smcs would have deterministic charges + with pytest.raises( + ProtocolValidationError, + match=re.escape( + "The following Components are affected: SmallMoleculeComponent(name=toluene)" + ), + ): + system_validation.validate_nondeterministic_charges( + # pick a force field with an am1bcc handler + mixed_charge_system, + small_molecule_forcefield="openff-2.2.0.offxml", + ) + + def test_openff_many_missing_charges(self, many_no_charge_system): + # make sure an error is raised if not all smcs would have deterministic charges and all smcs are listed in the error message + with pytest.raises( + ProtocolValidationError, + match=re.escape( + "The following Components are affected: SmallMoleculeComponent(name=benzene), SmallMoleculeComponent(name=toluene), SmallMoleculeComponent(name=phenol)" + ), + ): + system_validation.validate_nondeterministic_charges( + # pick a force field with an am1bcc handler + many_no_charge_system, + small_molecule_forcefield="openff-2.2.0.offxml", + ) diff --git a/src/openfe/tests/setup/atom_mapping/test_lomap_scorers.py b/src/openfe/tests/setup/atom_mapping/test_lomap_scorers.py index faad4ba47..f05792be2 100644 --- a/src/openfe/tests/setup/atom_mapping/test_lomap_scorers.py +++ b/src/openfe/tests/setup/atom_mapping/test_lomap_scorers.py @@ -287,7 +287,7 @@ def test_lomap_regression( smallmols = [] for i in range(matrix.shape[0]): nm = dbmols[i].getName() - smallmols.append(atom_mapping_basic_test_files[nm[:-5]]) # - ".mol2" + smallmols.append(atom_mapping_basic_test_files[nm[:-4]]) # - ".sdf" mapper = openfe.setup.atom_mapping.LomapAtomMapper( time=20, diff --git a/src/openfe/tests/data/lomap_basic/toluene.mol2 b/src/openfecli/tests/data/toluene.mol2 similarity index 100% rename from src/openfe/tests/data/lomap_basic/toluene.mol2 rename to src/openfecli/tests/data/toluene.mol2 diff --git a/src/openfecli/tests/parameters/test_mol.py b/src/openfecli/tests/parameters/test_mol.py index 680ea0673..8f0e6b55a 100644 --- a/src/openfecli/tests/parameters/test_mol.py +++ b/src/openfecli/tests/parameters/test_mol.py @@ -27,7 +27,7 @@ def test_get_molecule_sdf(): def test_get_molecule_mol2(): - with resources.as_file(resources.files("openfe.tests.data.lomap_basic")) as d: + with resources.as_file(resources.files("openfecli.tests.data")) as d: f = d / "toluene.mol2" mol = get_molecule(str(f)) diff --git a/src/openfecli/tests/parameters/test_molecules.py b/src/openfecli/tests/parameters/test_molecules.py index dd2fa0309..b2d25142b 100644 --- a/src/openfecli/tests/parameters/test_molecules.py +++ b/src/openfecli/tests/parameters/test_molecules.py @@ -9,18 +9,6 @@ from openfecli.parameters.molecules import load_molecules -def test_get_dir_molecules_sdf(): - with resources.as_file(resources.files("openfe.tests.data.serialization")) as dir_path: - # Note: the template doesn't include a valid version, but it loads - # anyway. In the future, we may need to create a temporary file with - # template substitutions done, but that seemed like overkill now. - mols = load_molecules(dir_path) - - assert len(mols) == 1 - assert mols[0].smiles == "CC" - assert mols[0].name == "ethane" - - def test_load_molecules_sdf_file(): files = resources.files("openfe.tests.data") ref = files / "benzene_modifications.sdf" @@ -30,7 +18,7 @@ def test_load_molecules_sdf_file(): assert len(mols) == 7 -def test_get_dir_molecules_mol2(): +def test_get_dir_molecules_sdf(): with resources.as_file(resources.files("openfe.tests.data.lomap_basic")) as dir_path: # Note: the template doesn't include a valid version, but it loads # anyway. In the future, we may need to create a temporary file with @@ -41,7 +29,6 @@ def test_get_dir_molecules_mol2(): all_smiles = {mol.smiles for mol in mols} all_names = {mol.name for mol in mols} assert "Cc1cc(C)c2cc(C)ccc2c1" in all_smiles - assert "*****" in all_names def test_get_molecule_error():