@@ -172,7 +172,8 @@ def __init__(self, system, config):
172172
173173 # Make sure the system contains perturbable molecules.
174174 try :
175- self ._system .molecules ("property is_perturbable" )
175+ atoms = self ._system ["property is_perturbable" ].atoms ()
176+ pert_idxs = self ._system .atoms ().find (atoms )
176177 except KeyError :
177178 msg = "No perturbable molecules in the system"
178179 _logger .error (msg )
@@ -265,7 +266,18 @@ def __init__(self, system, config):
265266 from ghostly import modify
266267
267268 _logger .info ("Applying modifications to ghost atom bonded terms" )
268- self ._system , self ._modifications = modify (self ._system )
269+ try :
270+ self ._system , self ._modifications = modify (self ._system )
271+ # Angle optimisation can sometimes fail.
272+ except Exception as e1 :
273+ try :
274+ self ._system , self ._modifications = modify (
275+ self_system , optimise_angles = False
276+ )
277+ except Exception as e2 :
278+ msg = f"Unable to apply modifications to ghost atom bonded terms: { e1 } ; { e2 } "
279+ _logger .error (msg )
280+ raise RuntimeError (msg )
269281
270282 # Check for a periodic space.
271283 self ._has_space = self ._check_space ()
@@ -363,6 +375,7 @@ def __init__(self, system, config):
363375 from math import isclose
364376
365377 # Set the REST2 scale factors.
378+ is_rest2 = False
366379 if self ._config .rest2_scale is not None :
367380 # Single value. Interpolate between 1.0 at the end states and rest2_scale
368381 # at lambda = 0.5.
@@ -396,6 +409,45 @@ def __init__(self, system, config):
396409 raise ValueError (msg )
397410 self ._rest2_scale_factors = self ._config .rest2_scale
398411
412+ # If there are any non-zero REST2 scale factors, then log it.
413+ if any (
414+ not isclose (factor , 1.0 , abs_tol = 1e-4 )
415+ for factor in self ._rest2_scale_factors
416+ ):
417+ is_rest2 = True
418+ _logger .info (f"REST2 scaling factors: { self ._rest2_scale_factors } " )
419+
420+ # Make sure the REST2 selection is valid.
421+ if self ._config .rest2_selection is not None :
422+
423+ try :
424+ atoms = _sr .mol .selection_to_atoms (
425+ self ._system , self ._config .rest2_selection
426+ )
427+ except :
428+ msg = "Invalid 'rest2_selection' value."
429+ _logger .error (msg )
430+ raise ValueError (msg )
431+
432+ # Make sure the user hasn't selected all atoms.
433+ if len (atoms ) == self ._system .num_atoms ():
434+ msg = "REST2 selection cannot contain all atoms in the system."
435+ _logger .error (msg )
436+ raise ValueError (msg )
437+
438+ # Get the atom indices.
439+ idxs = self ._system .atoms ().find (atoms )
440+
441+ # If no indices are in the perturbable region, then add them.
442+ if not any (i in pert_idxs for i in idxs ):
443+ idxs = sorted (pert_idxs + idxs )
444+ else :
445+ idxs = pert_idxs
446+
447+ # Log the atom indices in the REST2 selection.
448+ if is_rest2 :
449+ _logger .info (f"REST2 selection contains { len (atoms )} atoms: { idxs } " )
450+
399451 # Apply hydrogen mass repartitioning.
400452 if self ._config .hmr :
401453 # Work out the current hydrogen mass factor.
@@ -444,23 +496,6 @@ def __init__(self, system, config):
444496 self ._system , self ._config .h_mass_factor
445497 )
446498
447- # Make sure the REST2 selection is valid.
448- if self ._config .rest2_selection is not None :
449- from sire .mol import selection_to_atoms
450-
451- try :
452- atoms = selection_to_atoms (self ._system , self ._config .rest2_selection )
453- except :
454- msg = "Invalid 'rest2_selection' value."
455- _logger .error (msg )
456- raise ValueError (msg )
457-
458- # Make sure the user hasn't selected all atoms.
459- if len (atoms ) == self ._system .num_atoms ():
460- msg = "REST2 selection cannot contain all atoms in the system."
461- _logger .error (msg )
462- raise ValueError (msg )
463-
464499 # Flag whether this is a GPU simulation.
465500 self ._is_gpu = self ._config .platform in ["cuda" , "opencl" , "hip" ]
466501
0 commit comments