4747def modify (
4848 system ,
4949 k_hard = 100 ,
50- k_hard_ring = 75 ,
5150 k_soft = 5 ,
5251 optimise_angles = True ,
5352 num_optimise = 10 ,
@@ -69,13 +68,6 @@ def modify(
6968 The force constant to use to when setting angle terms involving ghost
7069 atoms to 90 degrees to avoid flapping. (In kcal/mol/rad^2)
7170
72- k_hard_ring : float, optional
73- The force constant to use when setting angle terms involving ghost
74- atoms to 90 degrees for bridge atoms that are in a ring. Ring bridges
75- suffer strain from the 90 degree target fighting the natural ring
76- geometry (~110 degrees). A lower force constant reduces this strain
77- while still preventing flapping. (In kcal/mol/rad^2)
78-
7971 k_soft : float, optional
8072 The force constant to use when setting angle terms involving ghost atoms
8173 for non-planar triple junctions. (In kcal/mol/rad^2)
@@ -322,7 +314,6 @@ def modify(
322314 connectivity0 ,
323315 modifications ,
324316 k_hard = k_hard ,
325- k_hard_ring = k_hard_ring ,
326317 bridge_indices = bridge_indices0 ,
327318 )
328319
@@ -336,7 +327,6 @@ def modify(
336327 connectivity0 ,
337328 modifications ,
338329 k_hard = k_hard ,
339- k_hard_ring = k_hard_ring ,
340330 k_soft = k_soft ,
341331 optimise_angles = optimise_angles ,
342332 num_optimise = num_optimise ,
@@ -417,7 +407,6 @@ def modify(
417407 connectivity1 ,
418408 modifications ,
419409 k_hard = k_hard ,
420- k_hard_ring = k_hard_ring ,
421410 is_lambda1 = True ,
422411 bridge_indices = bridge_indices1 ,
423412 )
@@ -431,7 +420,6 @@ def modify(
431420 connectivity1 ,
432421 modifications ,
433422 k_hard = k_hard ,
434- k_hard_ring = k_hard_ring ,
435423 k_soft = k_soft ,
436424 optimise_angles = optimise_angles ,
437425 num_optimise = num_optimise ,
@@ -741,7 +729,6 @@ def _dual(
741729 connectivity ,
742730 modifications ,
743731 k_hard = 100 ,
744- k_hard_ring = 75 ,
745732 is_lambda1 = False ,
746733 bridge_indices = None ,
747734):
@@ -784,10 +771,6 @@ def _dual(
784771 The force constant to use when setting angle terms involving ghost
785772 atoms to 90 degrees to avoid flapping. (In kcal/mol/rad^2)
786773
787- k_hard_ring : float, optional
788- The force constant to use when the bridge atom is in a ring, where
789- the 90 degree target fights the natural ring geometry. (In kcal/mol/rad^2)
790-
791774 is_lambda1 : bool, optional
792775 Whether the junction is at lambda = 1.
793776
@@ -859,9 +842,6 @@ def _is_heavy(atom_idx):
859842 best_phys_score = 0
860843 heavy_phys = set (physical )
861844
862- # Choose the force constant for angle stiffening.
863- k = k_hard_ring if bridge_in_ring else k_hard
864-
865845 # Single branch.
866846 if len (ghosts ) == 1 :
867847 _logger .debug (" Single branch:" )
@@ -926,6 +906,19 @@ def _is_heavy(atom_idx):
926906 # Identify the physical atom in this angle.
927907 phys_atom = idx2 if idx0 in ghosts else idx0
928908
909+ # Ring bridges: the ring geometry already constrains the ghost
910+ # position and prevents flapping (Boresch et al. note this is
911+ # "acceptable if the physical molecule is a rigid ring system").
912+ # Stiffening to 90° would introduce strain without benefit.
913+ if bridge_in_ring :
914+ new_angles .set (idx0 , idx1 , idx2 , p .function ())
915+ _logger .debug (
916+ f" Skipping stiffening for angle "
917+ f"[{ idx0 .value ()} -{ idx1 .value ()} -{ idx2 .value ()} ]: "
918+ f"bridge atom { bridge .value ()} is in a ring."
919+ )
920+ continue
921+
929922 # Skip stiffening through poorly-scoring atoms if better ones
930923 # exist AND at least one heavy atom would remain as anchor.
931924 # Without a heavy anchor, the ghost is under-constrained.
@@ -950,7 +943,7 @@ def _is_heavy(atom_idx):
950943 theta0 = pi / 2.0
951944
952945 # Create the new angle function.
953- amber_angle = _SireMM .AmberAngle (k , theta0 )
946+ amber_angle = _SireMM .AmberAngle (k_hard , theta0 )
954947
955948 # Generate the new angle expression.
956949 expression = amber_angle .to_expression (Symbol ("theta" ))
@@ -966,7 +959,7 @@ def _is_heavy(atom_idx):
966959 ang_idx = "," .join (
967960 [str (i ) for i in (idx0 .value (), idx1 .value (), idx2 .value ())]
968961 )
969- modifications [mod_key ]["stiffened_angles" ][ang_idx ] = {"k" : k }
962+ modifications [mod_key ]["stiffened_angles" ][ang_idx ] = {"k" : k_hard }
970963
971964 else :
972965 new_angles .set (idx0 , idx1 , idx2 , p .function ())
@@ -1051,7 +1044,6 @@ def _is_heavy(atom_idx):
10511044 connectivity ,
10521045 modifications ,
10531046 k_hard = k_hard ,
1054- k_hard_ring = k_hard_ring ,
10551047 is_lambda1 = is_lambda1 ,
10561048 bridge_indices = bridge_indices ,
10571049 )
@@ -1068,7 +1060,6 @@ def _triple(
10681060 connectivity ,
10691061 modifications ,
10701062 k_hard = 100 ,
1071- k_hard_ring = 75 ,
10721063 k_soft = 5 ,
10731064 optimise_angles = True ,
10741065 num_optimise = 10 ,
@@ -1113,10 +1104,6 @@ def _triple(
11131104 The force constant to use when setting angle terms involving ghost
11141105 atoms to 90 degrees to avoid flapping. (In kcal/mol/rad^2)
11151106
1116- k_hard_ring : float, optional
1117- The force constant to use when the bridge atom is in a ring, where
1118- the 90 degree target fights the natural ring geometry. (In kcal/mol/rad^2)
1119-
11201107 k_soft : float, optional
11211108 The force constant to use when setting angle terms involving ghost
11221109 atoms for non-planar triple junctions. (In kcal/mol/rad^2)
@@ -1535,7 +1522,6 @@ def _is_heavy(atom_idx):
15351522 connectivity ,
15361523 modifications ,
15371524 k_hard = k_hard ,
1538- k_hard_ring = k_hard_ring ,
15391525 is_lambda1 = is_lambda1 ,
15401526 bridge_indices = bridge_indices ,
15411527 )
0 commit comments