@@ -732,7 +732,9 @@ def morse_potential(
732732 de = None ,
733733 use_pbc = None ,
734734 name = None ,
735- auto_parametrise = False ,
735+ auto_parametrise = True ,
736+ direct_morse_replacement = True ,
737+ retain_harmonic_bond = False ,
736738 map = None ,
737739):
738740 """
@@ -795,6 +797,16 @@ def morse_potential(
795797 and 'atoms1', the equilibrium distance r0 will be set to the original
796798 bond length, and the force constant k will be set to the force constant
797799 of the bond in the unperturbed state. Note that 'de' must still be provided.
800+ Default is True.
801+
802+ direct_morse_replacement : bool, optional
803+ If True, and if auto_parametrise is True, then the function will attempt to directly
804+ replace an existing bond with a Morse potential. Default is True.
805+
806+ retain_harmonic_bond : bool, optional
807+ If True, and if auto_parametrise is True, then the function will only nullify the force
808+ constant of the existing harmonic bond, rather than removing the bond potential entirely.
809+ If False, then the existing harmonic bond will be removed entirely.
798810 Default is False.
799811
800812 Returns
@@ -803,6 +815,9 @@ def morse_potential(
803815 A container of Morse restraints, where the first restraint is
804816 the MorsePotentialRestraint created. The Morse restraint created can be
805817 extracted with MorsePotentialRestraints[0].
818+
819+ mols : sire.system._system.System
820+ The system containing the atoms, which will have been modified if auto_parametrise is True and direct_morse_replacement is True.
806821 """
807822
808823 from .. import u
@@ -875,10 +890,7 @@ def morse_potential(
875890 atom0_idx = [bond_name .atom0 ().index ().value ()][0 ]
876891 atom1_idx = [bond_name .atom1 ().index ().value ()][0 ]
877892
878- # Divide k0 by 2 to convert from force constant to sire half
879- # force constant k
880893 if k is None :
881- k0 = k0 / 2.0
882894 k0 = u (f"{ k0 } kJ mol-1 nm-2" )
883895 k = [k0 ]
884896
@@ -897,6 +909,47 @@ def morse_potential(
897909 f"molecule property is_perturbable and atomidx { atom1_idx } "
898910 ]
899911 break
912+ if direct_morse_replacement :
913+ from ..legacy import MM as _MM
914+ import re as _re
915+ from ..legacy .CAS import Symbol as _Symbol
916+
917+ search_pattern = r"r - (\d+\.\d+)"
918+ mol = mol [0 ]
919+ info = mol .info ()
920+
921+ # We need to loop through both bond0 and bond1 properties, as we don't know
922+ # which one the bond of interest will be in (bond forming or bond breaking)
923+ for bond_prop in ("bond0" , "bond1" ):
924+ bonds = mol .property (bond_prop )
925+ new_bonds = _MM .TwoAtomFunctions (info )
926+
927+ for p in bonds .potentials ():
928+ idx0 = info .atom_idx (p .atom0 ())
929+ idx1 = info .atom_idx (p .atom1 ())
930+
931+ # Attempt to match the bond of interest using previously identified atom indices
932+ if idx0 .value () == atom0_idx and idx1 .value () == atom1_idx :
933+ bond_potential_string = p .function ().to_string ()
934+ match = _re .search (search_pattern , bond_potential_string )
935+
936+ if not match :
937+ raise ValueError (
938+ f"No match found in the string: { bond_potential_string } "
939+ )
940+
941+ # If we retaining the harmonic bond, then set the harmonic bond force constant
942+ # to zero. Otherwise, the harmonic bond entirely removed from the force list.
943+ if retain_harmonic_bond :
944+ r = float (match .group (1 ))
945+ amber_bond = _MM .AmberBond (0 , r )
946+ expression = amber_bond .to_expression (_Symbol ("r" ))
947+ new_bonds .set (idx0 , idx1 , expression )
948+ else :
949+ new_bonds .set (idx0 , idx1 , p .function ())
950+
951+ mol = mol .edit ().set_property (bond_prop , new_bonds ).molecule ().commit ()
952+ mols .update (mol )
900953
901954 try :
902955 atoms0 = _to_atoms (mols , atoms0 )
@@ -943,16 +996,16 @@ def morse_potential(
943996 except :
944997 raise ValueError (f"Unable to parse 'de' as a Sire GeneralUnit: { de } " )
945998
946- mols = mols .atoms ()
999+ mols_atms = mols .atoms ()
9471000
9481001 if name is None :
9491002 restraints = MorsePotentialRestraints ()
9501003 else :
9511004 restraints = MorsePotentialRestraints (name = name )
9521005
9531006 for i , (atom0 , atom1 ) in enumerate (zip (atoms0 , atoms1 )):
954- idxs0 = mols .find (atom0 )
955- idxs1 = mols .find (atom1 )
1007+ idxs0 = mols_atms .find (atom0 )
1008+ idxs1 = mols_atms .find (atom1 )
9561009
9571010 if type (idxs0 ) is int :
9581011 idxs0 = [idxs0 ]
@@ -989,7 +1042,7 @@ def morse_potential(
9891042 # Set the use_pbc flag.
9901043 restraints .set_uses_pbc (use_pbc )
9911044
992- return restraints
1045+ return restraints , mols
9931046
9941047
9951048def bond (* args , use_pbc = False , ** kwargs ):
0 commit comments