|
1 | 1 | import sys |
2 | 2 |
|
3 | 3 | import pytest |
| 4 | +import sire as sr |
4 | 5 | from sire.legacy.MM import InternalFF, IntraCLJFF, IntraFF |
5 | 6 | from sire.legacy.Mol import AtomIdx, Element, PartialMolecule |
6 | 7 |
|
7 | 8 | import BioSimSpace as BSS |
8 | | -from tests.conftest import has_amber, has_openff |
| 9 | +from tests.conftest import has_amber, has_antechamber, has_openff, has_tleap |
9 | 10 |
|
10 | 11 | # Store the tutorial URL. |
11 | 12 | url = BSS.tutorialUrl() |
@@ -844,3 +845,85 @@ def test_ring_opening_and_size_change(ligands, mapping): |
844 | 845 | BSS.Align.merge( |
845 | 846 | m0, m1, mapping, allow_ring_breaking=True, allow_ring_size_change=True |
846 | 847 | ) |
| 848 | + |
| 849 | + |
| 850 | +@pytest.mark.skipif( |
| 851 | + not has_antechamber or not has_tleap, |
| 852 | + reason="Requires antechamber and tLEaP to be installed.", |
| 853 | +) |
| 854 | +@pytest.mark.skipif( |
| 855 | + "openmm" not in sr.convert.supported_formats(), |
| 856 | + reason="Requires OpenMM to be installed.", |
| 857 | +) |
| 858 | +def test_ring_breaking_intrascale(): |
| 859 | + """ |
| 860 | + Regression test for mergeIntrascale with ring-breaking perturbations. |
| 861 | +
|
| 862 | + Before the fix, CLJNBPairs pairs that were excluded/1-4 in one end state |
| 863 | + but fully interacting (1,1) in the other were incorrectly left at the |
| 864 | + non-(1,1) value in the merged intrascale. For cyclopentane->cyclohexane |
| 865 | + this produced only 6 changed OpenMM exceptions instead of the correct 18, |
| 866 | + causing simulation instabilities due to missing non-bonded interactions. |
| 867 | + """ |
| 868 | + # Parameterise both molecules with GAFF2. |
| 869 | + cyclopentane = BSS.Parameters.gaff2("C1CCCC1").getMolecule() |
| 870 | + cyclohexane = BSS.Parameters.gaff2("C1CCCCC1").getMolecule() |
| 871 | + |
| 872 | + # Atom mapping for cyclopentane -> cyclohexane. |
| 873 | + mapping = { |
| 874 | + 0: 0, |
| 875 | + 1: 1, |
| 876 | + 2: 2, |
| 877 | + 3: 3, |
| 878 | + 4: 4, |
| 879 | + 5: 6, |
| 880 | + 6: 7, |
| 881 | + 7: 8, |
| 882 | + 8: 9, |
| 883 | + 9: 10, |
| 884 | + 10: 11, |
| 885 | + 11: 12, |
| 886 | + 12: 13, |
| 887 | + 13: 14, |
| 888 | + 14: 15, |
| 889 | + } |
| 890 | + |
| 891 | + # Load the reference merged system produced by the old BioSimSpace merge |
| 892 | + # code (which used CLJNBPairs(connectivity, sf14) and was known correct). |
| 893 | + reference = sr.load_test_files("cyclopentane_cyclohexane.bss") |
| 894 | + ref_mol = reference.molecules("molecule property is_perturbable")[0] |
| 895 | + ref_omm = ref_mol.perturbation().to_openmm(map={"coordinates": "coordinates0"}) |
| 896 | + ref_bonds = ref_omm.changed_bonds() |
| 897 | + ref_exceptions = ref_omm.changed_exceptions() |
| 898 | + |
| 899 | + # Merge cyclopentane -> cyclohexane and check against the reference. |
| 900 | + cyclopentane_aligned = BSS.Align.rmsdAlign(cyclopentane, cyclohexane, mapping) |
| 901 | + merged_fwd = BSS.Align.merge( |
| 902 | + cyclopentane_aligned, |
| 903 | + cyclohexane, |
| 904 | + mapping, |
| 905 | + allow_ring_size_change=True, |
| 906 | + allow_ring_breaking=True, |
| 907 | + ) |
| 908 | + omm_fwd = merged_fwd._sire_object.perturbation().to_openmm( |
| 909 | + map={"coordinates": "coordinates0"} |
| 910 | + ) |
| 911 | + assert len(omm_fwd.changed_bonds()) == len(ref_bonds) |
| 912 | + assert len(omm_fwd.changed_exceptions()) == len(ref_exceptions) |
| 913 | + |
| 914 | + # Merge in the reverse direction (cyclohexane -> cyclopentane) to verify |
| 915 | + # symmetry: the fix must hold regardless of which molecule is mol0/mol1. |
| 916 | + inv_mapping = {v: k for k, v in mapping.items()} |
| 917 | + cyclohexane_aligned = BSS.Align.rmsdAlign(cyclohexane, cyclopentane, inv_mapping) |
| 918 | + merged_rev = BSS.Align.merge( |
| 919 | + cyclohexane_aligned, |
| 920 | + cyclopentane, |
| 921 | + inv_mapping, |
| 922 | + allow_ring_size_change=True, |
| 923 | + allow_ring_breaking=True, |
| 924 | + ) |
| 925 | + omm_rev = merged_rev._sire_object.perturbation().to_openmm( |
| 926 | + map={"coordinates": "coordinates0"} |
| 927 | + ) |
| 928 | + assert len(omm_rev.changed_bonds()) == len(ref_bonds) |
| 929 | + assert len(omm_rev.changed_exceptions()) == len(ref_exceptions) |
0 commit comments