Skip to content

Commit a5735a6

Browse files
committed
Added user option to provide verytight which will replace tight
1 parent 5514eed commit a5735a6

2 files changed

Lines changed: 51 additions & 2 deletions

File tree

arc/job/adapters/gaussian.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,32 @@ def __init__(self,
211211
elif self.species[0].checkfile is not None and os.path.isfile(self.species[0].checkfile):
212212
self.checkfile = self.species[0].checkfile
213213

214+
def _user_requested_verytight(self) -> bool:
215+
"""
216+
Return True if the user passed ``verytight`` through ``self.args``.
217+
218+
When True, the fine-mode opt-keyword builder will skip auto-adding
219+
``tight`` so the user's ``verytight`` wins unambiguously in the final
220+
``opt=(...)`` clause assembled by ``combine_parameters``.
221+
222+
Scope: only the ``keyword`` channel is meaningful here — ``block`` is for
223+
Gaussian input blocks and ``trsh`` is for ARC's troubleshooting layer,
224+
neither of which is the right place for a user opt-cutoff override.
225+
226+
Notes for the implementer:
227+
- ``self.args['keyword']`` is a ``dict[str, str]`` (see
228+
``Level._check_args`` at arc/level.py:281). Values may be in any
229+
case and may contain other keywords too (e.g. ``"opt=(verytight)
230+
freq=hpmodes"``).
231+
- Match must be word-bounded: a stray ``verytightscf`` should not
232+
count, and ``tight`` alone must NOT match.
233+
- Be defensive: ``self.args`` or ``self.args['keyword']`` may be
234+
missing or empty depending on how the Level was constructed.
235+
"""
236+
keyword_args = (self.args or {}).get('keyword') or {}
237+
joined = ' '.join(str(v) for v in keyword_args.values())
238+
return re.search(r'\bverytight\b', joined, re.IGNORECASE) is not None
239+
214240
def write_input_file(self) -> None:
215241
"""
216242
Write the input file to execute the job on the server.
@@ -299,10 +325,11 @@ def write_input_file(self) -> None:
299325
if input_dict['trsh']:
300326
input_dict['trsh'] += ' '
301327
input_dict['trsh'] += 'scf=(tight,direct)'
328+
tight_kw = [] if self._user_requested_verytight() else ['tight']
302329
if self.is_ts:
303-
keywords.extend(['tight', 'maxstep=5'])
330+
keywords.extend([*tight_kw, 'maxstep=5'])
304331
else:
305-
keywords.extend(['tight', 'maxstep=5', f'maxcycle={max_c}'])
332+
keywords.extend([*tight_kw, 'maxstep=5', f'maxcycle={max_c}'])
306333
input_dict['job_type_1'] = "opt" if self.level.method_type not in ['dft', 'composite', 'wavefunction']\
307334
else f"opt=({', '.join(key for key in keywords)})"
308335

arc/job/adapters/gaussian_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,28 @@ def test_trsh_write_input_file(self):
11611161

11621162
self.assertEqual(content_24, job_24_expected_input_file)
11631163

1164+
def test_user_requested_verytight(self):
1165+
"""Detection only fires for word-bounded ``verytight`` in the keyword channel."""
1166+
cases = [
1167+
({'keyword': {'opt': 'opt=(verytight)'}, 'block': {}, 'trsh': {}}, True),
1168+
({'keyword': {'opt': 'opt=(VeryTight)'}, 'block': {}, 'trsh': {}}, True),
1169+
({'keyword': {'general': 'opt=(calcfc)'}, 'block': {}, 'trsh': {}}, False),
1170+
({'keyword': {'opt': 'opt=(tight)'}, 'block': {}, 'trsh': {}}, False),
1171+
({'keyword': {'general': 'verytightscf'}, 'block': {}, 'trsh': {}}, False),
1172+
({'keyword': {}, 'block': {}, 'trsh': {}}, False),
1173+
# verytight smuggled in via block/trsh must not count
1174+
({'keyword': {}, 'block': {'1': 'opt=(verytight)'}, 'trsh': {}}, False),
1175+
({'keyword': {}, 'block': {}, 'trsh': {'opt': 'opt=(verytight)'}}, False),
1176+
]
1177+
original_args = self.job_3.args
1178+
try:
1179+
for args, expected in cases:
1180+
with self.subTest(args=args):
1181+
self.job_3.args = args
1182+
self.assertEqual(self.job_3._user_requested_verytight(), expected)
1183+
finally:
1184+
self.job_3.args = original_args
1185+
11641186

11651187
@classmethod
11661188
def tearDownClass(cls):

0 commit comments

Comments
 (0)