4040 "rubidium" : ("RB" , 1 ),
4141 "cs" : ("CS" , 1 ),
4242 "cesium" : ("CS" , 1 ),
43- "f" : ("F" , - 1 ),
44- "fluoride" : ("F" , - 1 ),
4543 "cl" : ("CL" , - 1 ),
4644 "chloride" : ("CL" , - 1 ),
47- "br" : ("BR" , - 1 ),
48- "bromide" : ("BR" , - 1 ),
4945 "mg" : ("MG" , 2 ),
5046 "magnesium" : ("MG" , 2 ),
5147 "ca" : ("CA" , 2 ),
@@ -78,6 +74,7 @@ def addIons(
7874 ion_conc = 0 ,
7975 is_neutral = True ,
8076 preserved_waters = None ,
77+ counter_ion = None ,
8178 work_dir = None ,
8279 property_map = {},
8380):
@@ -128,6 +125,15 @@ def addIons(
128125 that genion cannot select them for replacement. Useful for
129126 protecting crystallographic or binding-site water molecules.
130127
128+ counter_ion : str
129+ The name of the ion to use for the opposite charge slot in the
130+ genion call. By default genion uses Na\\ :sup:`+` as the counter
131+ cation and Cl\\ :sup:`-` as the counter anion. Use this parameter
132+ to override the counter-ion species, e.g. ``"br"`` when adding a
133+ cation. The counter-ion must have the opposite charge sign to
134+ ``ion``. Requires ``is_neutral=True`` (otherwise no counter-ions
135+ are added and the parameter has no effect).
136+
131137 work_dir : str
132138 The working directory for the process.
133139
@@ -235,6 +241,35 @@ def addIons(
235241 "'preserved_waters' items must be int indices or Molecule objects."
236242 )
237243
244+ # Validate and resolve counter_ion.
245+ counter_ion_name = None
246+ counter_ion_charge = None
247+ if counter_ion is not None :
248+ if not isinstance (counter_ion , str ):
249+ raise TypeError ("'counter_ion' must be of type 'str'" )
250+ counter_key = counter_ion .strip ().lower ()
251+ if counter_key not in _ion_map :
252+ raise ValueError (
253+ f"Unsupported counter_ion '{ counter_ion } '. Supported ions are: { ions ()} "
254+ )
255+ counter_ion_name , counter_ion_charge = _ion_map [counter_key ]
256+ # The counter-ion must have the opposite charge sign to the requested ion.
257+ if ion_charge > 0 and counter_ion_charge >= 0 :
258+ raise ValueError (
259+ f"'counter_ion' must be negatively charged when 'ion' is positively "
260+ f"charged. '{ counter_ion } ' has charge { counter_ion_charge :+d} ."
261+ )
262+ if ion_charge < 0 and counter_ion_charge <= 0 :
263+ raise ValueError (
264+ f"'counter_ion' must be positively charged when 'ion' is negatively "
265+ f"charged. '{ counter_ion } ' has charge { counter_ion_charge :+d} ."
266+ )
267+ if not is_neutral :
268+ raise ValueError (
269+ "'counter_ion' has no effect when 'is_neutral=False'. Set "
270+ "'is_neutral=True' to enable counter-ion addition."
271+ )
272+
238273 if work_dir is not None and not isinstance (work_dir , str ):
239274 raise TypeError ("'work_dir' must be of type 'str'" )
240275
@@ -280,6 +315,8 @@ def addIons(
280315 num_ions ,
281316 is_neutral ,
282317 preserved_mols ,
318+ counter_ion_name ,
319+ counter_ion_charge ,
283320 work_dir ,
284321 property_map ,
285322 )
@@ -292,6 +329,8 @@ def _add_ions(
292329 num_ions ,
293330 is_neutral ,
294331 preserved_mols = None ,
332+ counter_ion_name = None ,
333+ counter_ion_charge = None ,
295334 work_dir = None ,
296335 property_map = {},
297336):
@@ -322,6 +361,13 @@ def _add_ions(
322361 between the non-water solute and the new water+ions in the result,
323362 mirroring the ordering used by ``_solvate`` for crystal waters.
324363
364+ counter_ion_name : str
365+ The GROMACS residue name of the counter-ion (e.g. ``"BR"``), or
366+ ``None`` to use genion's default (NA/CL).
367+
368+ counter_ion_charge : int
369+ The integer charge of the counter-ion, or ``None``.
370+
325371 work_dir : str
326372 The working directory for the process.
327373
@@ -481,22 +527,29 @@ def _add_ions(
481527 # Build the genion command.
482528 # genion supports one positive ion type (-pname/-pq/-np) and one
483529 # negative ion type (-nname/-nq/-nn). We use the appropriate slot
484- # for the requested ion. When is_neutral=True, genion adds the
485- # default NA/CL as counter-ions to bring the total charge to zero.
530+ # for the requested ion. When is_neutral=True, genion adds counter-ions
531+ # to bring the total charge to zero; counter_ion_name overrides the
532+ # default counter-ion species (NA for cations, CL for anions).
486533 if ion_charge > 0 :
487534 command = (
488535 "%s genion -s ions.tpr -o ions_out.gro -p system.top"
489536 " -pname %s -pq %d" % (_gmx_exe , ion_name , ion_charge )
490537 )
491538 if num_ions > 0 :
492539 command += " -np %d" % num_ions
540+ # Override the default Cl- counter-ion if requested.
541+ if counter_ion_name is not None :
542+ command += " -nname %s -nq %d" % (counter_ion_name , counter_ion_charge )
493543 else :
494544 command = (
495545 "%s genion -s ions.tpr -o ions_out.gro -p system.top"
496546 " -nname %s -nq %d" % (_gmx_exe , ion_name , ion_charge )
497547 )
498548 if num_ions > 0 :
499549 command += " -nn %d" % num_ions
550+ # Override the default Na+ counter-ion if requested.
551+ if counter_ion_name is not None :
552+ command += " -pname %s -pq %d" % (counter_ion_name , counter_ion_charge )
500553
501554 if is_neutral :
502555 command += " -neutral"
0 commit comments