Skip to content

Commit

Permalink
Gauss Trsh Fixes (#713)
Browse files Browse the repository at this point in the history
@Lilachn91 pointed out that `nosymm` should not be part of the opt or
scf combination of parameters but be its own parameter. This has been
implemented. Furthermore, at times we end up creating an input file that
may have `opt=([param1])` and `opt=([param2])` when rather they should
be combined into one `opt=([param1,param2])`
  • Loading branch information
alongd authored Nov 24, 2023
2 parents 26b200b + e407531 commit b47ea8e
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 29 deletions.
11 changes: 11 additions & 0 deletions arc/job/adapters/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,4 +522,15 @@ def combine_parameters(input_dict: dict, terms: list) -> Tuple[dict, List]:
value = re.sub(term, '', value)
input_dict_copy[key] = value

# Parameters may appear as one word, so need to split them via comma
parameters = [param.split(',') for param in parameters]
# Flatten the list of lists
parameters = [item for sublist in parameters for item in sublist]
# Remove empty spaces from the beginning and end of each parameter
parameters = [param.strip() for param in parameters]
# Parameters may appear multiple times in the input_dict, so remove duplicates
parameters = list(set(parameters))
# Sort the list
parameters.sort()

return input_dict_copy, parameters
22 changes: 20 additions & 2 deletions arc/job/adapters/gaussian.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,10 @@ def write_input_file(self) -> None:
input_dict['job_type_2'] = 'freq IOp(7/33=1)'

elif self.job_type == 'sp':
input_dict['job_type_1'] = f'scf=(tight, direct) integral=(grid=ultrafine, {integral_algorithm})'
input_dict['job_type_1'] = f'integral=(grid=ultrafine, {integral_algorithm})'
if input_dict['trsh']:
input_dict['trsh'] += ' '
input_dict['trsh'] += 'scf=(tight, direct)'

elif self.job_type == 'scan':
scans, scans_strings = list(), list()
Expand All @@ -317,8 +320,11 @@ def write_input_file(self) -> None:
self.torsions = torsions_to_scans(scans, direction=-1)

ts = 'ts, ' if self.is_ts else ''
input_dict['job_type_1'] = f'opt=({ts}modredundant, calcfc, noeigentest, maxStep=5) scf=(tight, direct) ' \
input_dict['job_type_1'] = f'opt=({ts}modredundant, calcfc, noeigentest, maxStep=5)' \
f'integral=(grid=ultrafine, {integral_algorithm})'
if input_dict['trsh']:
input_dict['trsh'] += ' '
input_dict['trsh'] += 'scf=(tight, direct)'
input_dict['scan'] = '\n\n' if not input_dict['scan'] else input_dict['scan']
for scan in scans_strings:
input_dict['scan'] += f'D {scan} S {int(360 / self.scan_res)} {self.scan_res:.1f}\n'
Expand Down Expand Up @@ -361,13 +367,25 @@ def write_input_file(self) -> None:
input_dict['job_type_1'] += ' guess=read' if self.checkfile is not None and os.path.isfile(self.checkfile) \
else ' guess=mix'

# Fix OPT
terms_opt = [r'opt=\((.*?)\)', r'opt=(\w+)']
input_dict, parameters_opt = combine_parameters(input_dict, terms_opt)
# If 'opt' parameters are found, concatenate and reinsert them
if parameters_opt:
# Remove duplicate parameters
combined_opt_params = ','.join(parameters_opt)
input_dict['job_type_1'] = f"opt=({combined_opt_params}) {input_dict['job_type_1']}"

#Fix SCF
# This may be redundant due to additional fixes in the above code
terms = ['scf=\((.*?)\)', 'scf=(\w+)']
input_dict, parameters = combine_parameters(input_dict, terms)
if parameters:
input_dict['trsh'] += f" scf=({','.join(parameters)})"

# Remove double spaces
input_dict['job_type_1'] = input_dict['job_type_1'].replace(' ', ' ')

with open(os.path.join(self.local_path, input_filenames[self.job_adapter]), 'w') as f:
f.write(Template(input_template).render(**input_dict))

Expand Down
22 changes: 11 additions & 11 deletions arc/job/adapters/gaussian_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def setUpClass(cls):

# Gaussian: Checkfile error and SCF error
# First SCF error - qc,nosymm
job_status = {'keywords': ['SCF']}
job_status = {'keywords': ['SCF', 'NoSymm']}
output_errors, ess_trsh_methods, remove_checkfile, level_of_theory, software, job_type, fine, trsh_keyword, \
memory, shift, cpu_cores, couldnt_trsh = trsh.trsh_ess_job(label, level_of_theory, server, job_status,
job_type, software, fine, memory_gb,
Expand Down Expand Up @@ -297,7 +297,7 @@ def test_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc) cbs-qb3 IOp(2/9=2000) IOp(1/12=5,3/44=0)
#P opt=(calcfc) cbs-qb3 IOp(2/9=2000) IOp(1/12=5,3/44=0)
spc1
Expand Down Expand Up @@ -333,7 +333,7 @@ def test_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(modredundant, calcfc, noeigentest, maxStep=5) integral=(grid=ultrafine, Acc2E=12) guess=mix wb97xd/def2tzvp IOp(2/9=2000) scf=(tight, direct)
#P opt=(calcfc,maxStep=5,modredundant,noeigentest) integral=(grid=ultrafine, Acc2E=12) guess=mix wb97xd/def2tzvp IOp(2/9=2000) scf=(direct,tight)
ethanol
Expand Down Expand Up @@ -366,7 +366,7 @@ def test_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P uwb97xd/def2tzvp freq IOp(7/33=1) integral=(grid=ultrafine, Acc2E=12) IOp(2/9=2000) scf=(tight, direct)
#P uwb97xd/def2tzvp freq IOp(7/33=1) integral=(grid=ultrafine, Acc2E=12) IOp(2/9=2000) scf=(direct,tight)
birad_singlet
Expand All @@ -384,7 +384,7 @@ def test_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc) uwb97xd/def2tzvp IOp(2/9=2000)
#P opt=(calcfc) uwb97xd/def2tzvp IOp(2/9=2000)
anion
Expand Down Expand Up @@ -478,7 +478,7 @@ def test_trsh_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc, tight, maxstep=5) uwb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) scf=(tight,direct)
#P opt=(calcfc,maxstep=5,tight) uwb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) scf=(direct,tight)
anion
Expand All @@ -496,7 +496,7 @@ def test_trsh_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc, tight, maxstep=5) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) scf=(tight,direct)
#P opt=(calcfc,maxstep=5,tight) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) scf=(direct,tight)
ethanol
Expand All @@ -522,7 +522,7 @@ def test_trsh_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc, tight, maxstep=5) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) scf=(tight,direct,xqc,nosymm)
#P opt=(calcfc,maxstep=5,tight) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) nosymm scf=(direct,tight,xqc)
ethanol
Expand All @@ -548,7 +548,7 @@ def test_trsh_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc, tight, maxstep=5) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) scf=(tight,direct,xqc,nosymm,NDump=30)
#P opt=(calcfc,maxstep=5,tight) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) nosymm scf=(NDump=30,direct,tight,xqc)
ethanol
Expand All @@ -574,7 +574,7 @@ def test_trsh_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc, tight, maxstep=5) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) scf=(tight,direct,xqc,nosymm,NDump=30,NoDIIS)
#P opt=(calcfc,maxstep=5,tight) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) nosymm scf=(NDump=30,NoDIIS,direct,tight,xqc)
ethanol
Expand All @@ -600,7 +600,7 @@ def test_trsh_write_input_file(self):
%mem=14336mb
%NProcShared=8
#P opt=(calcfc, tight, maxstep=5) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) opt=(cartesian,nosymm) scf=(tight,direct,xqc,nosymm,NDump=30,NoDIIS)
#P opt=(calcfc,cartesian,maxstep=5,tight) guess=mix wb97xd integral=(grid=ultrafine, Acc2E=14) IOp(2/9=2000) nosymm scf=(NDump=30,NoDIIS,direct,tight,xqc)
ethanol
Expand Down
55 changes: 41 additions & 14 deletions arc/job/trsh.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def determine_ess_status(output_path: str,
error = 'The blank line after the coordinate section is missing, ' \
'or charge/multiplicity was not specified correctly.'
elif 'l103.exe' in line:
keywords = ['InternalCoordinateError', 'GL103']
keywords = ['InternalCoordinateError', 'GL103','NoSymm']
error = 'Internal coordinate error'
elif 'l108.exe' in line:
keywords = ['InputError', 'GL108']
Expand All @@ -112,7 +112,7 @@ def determine_ess_status(output_path: str,
elif 'l401.exe' in line:
keywords = ['GL401']
elif 'l502.exe' in line:
keywords = ['SCF', 'GL502']
keywords = ['SCF', 'GL502', 'NoSymm']
error = 'Unconverged SCF'
elif 'l508.exe' in line:
keywords = ['no_xqc', 'GL508']
Expand Down Expand Up @@ -867,10 +867,10 @@ def trsh_ess_job(label: str,
if remove_checkfile:
logger_info.append('that failed with "Basis set data is not on the checkpoint file" by removing the checkfile.')

# Check if InternalCoordinateError is in the keyword or opt=(cartesian,nosymm)
# Check if InternalCoordinateError is in the keyword or opt=(cartesian)
ess_trsh_methods, trsh_keyword, couldnt_trsh = trsh_keyword_cartesian(job_status, ess_trsh_methods, job_type, trsh_keyword,couldnt_trsh)
if 'cartesian' in ess_trsh_methods:
logger_info.append('using opt=cartesian with nosyym')
logger_info.append('using opt=cartesian')
ess_trsh_methods, trsh_keyword, couldnt_trsh = trsh_keyword_intaccuracy(ess_trsh_methods, trsh_keyword, couldnt_trsh)
if 'int=(Acc2E=14)' in ess_trsh_methods:
logger_info.append('using int=(Acc2E=14)')
Expand All @@ -879,11 +879,16 @@ def trsh_ess_job(label: str,
ess_trsh_methods, trsh_keyword, couldnt_trsh = trsh_keyword_scf(job_status, ess_trsh_methods, trsh_keyword, couldnt_trsh)
if 'scf=(NDump=30)' in ess_trsh_methods:
logger_info.append('using scf=(NDump=30)')
if 'scf=(qc,nosymm)' in ess_trsh_methods:
logger_info.append('using scf=(qc,nosymm)')
if 'scf=(qc)' in ess_trsh_methods:
logger_info.append('using scf=(qc)')
if 'scf=(NoDIIS)' in ess_trsh_methods:
logger_info.append('using scf=(NoDIIS)')

# Check if NoSymm
ess_trsh_methods, trsh_keyword, couldnt_trsh = trsh_keyword_nosymm(job_status, ess_trsh_methods, trsh_keyword, couldnt_trsh)
if 'NoSymm' in ess_trsh_methods:
logger_info.append('using nosymm')

# Check if unconverged is in the keyword
ess_trsh_methods, trsh_keyword, fine, couldnt_trsh = trsh_keyword_unconverged(job_status, ess_trsh_methods, trsh_keyword, couldnt_trsh, fine)
if fine:
Expand Down Expand Up @@ -1540,18 +1545,25 @@ def trsh_keyword_checkfile(job_status, ess_trsh_methods, couldnt_trsh) -> Tuple[
"""
Check if the job requires removal of checkfile
"""
if 'CheckFile' in job_status.get('keywords', '') or 'checkfile=None' in ess_trsh_methods:
if 'CheckFile' in job_status.get('keywords', '') and 'checkfile=None' not in ess_trsh_methods:
ess_trsh_methods.append('checkfile=None')
couldnt_trsh = False
return True, ess_trsh_methods, couldnt_trsh
elif 'checkfile=None' in ess_trsh_methods:
couldnt_trsh = False
return True, ess_trsh_methods, couldnt_trsh

return False, ess_trsh_methods, couldnt_trsh

def trsh_keyword_intaccuracy(ess_trsh_methods, trsh_keyword, couldnt_trsh) -> Tuple[List, List, bool]:
"""
Check if the job requires change of 2 electron integral accuracy
"""
if 'int=(Acc2E=14)' in ess_trsh_methods:
if 'int=(Acc2E=14)' not in ess_trsh_methods:
ess_trsh_methods.append('int=(Acc2E=14)')
trsh_keyword.append('int=(Acc2E=14)')
couldnt_trsh = False
elif 'int=(Acc2E=14)' not in trsh_keyword and 'int=(Acc2E=14)' in ess_trsh_methods:
trsh_keyword.append('int=(Acc2E=14)')
couldnt_trsh = False

Expand All @@ -1563,11 +1575,12 @@ def trsh_keyword_cartesian(job_status, ess_trsh_methods, job_type, trsh_keyword:
"""
if 'InternalCoordinateError' in job_status['keywords'] \
and 'cartesian' not in ess_trsh_methods and job_type == 'opt':
trsh_keyword.append('opt=(cartesian,nosymm)')
ess_trsh_methods.append('cartesian')
trsh_keyword.append('opt=(cartesian)')
couldnt_trsh = False
elif 'opt=(cartesian,nosymm)' in ess_trsh_methods and \
job_type == 'opt':
trsh_keyword.append('opt=(cartesian,nosymm)')
elif 'cartesian' in ess_trsh_methods and \
job_type == 'opt' and 'cartesian' not in trsh_keyword:
trsh_keyword.append('opt=(cartesian)')
couldnt_trsh = False

return ess_trsh_methods, trsh_keyword, couldnt_trsh
Expand All @@ -1577,9 +1590,9 @@ def trsh_keyword_scf(job_status, ess_trsh_methods, trsh_keyword, couldnt_trsh) -
Check if the job requires change of scf
"""
scf_pattern = r"scf=\((.*?)\)" # e.g., scf=(xqc,MaxCycle=1000), will match xqc,MaxCycle=1000
if 'SCF' in job_status['keywords'] and 'scf=(qc,nosymm)' not in ess_trsh_methods:
if 'SCF' in job_status['keywords'] and 'scf=(qc)' not in ess_trsh_methods:
# try both qc and nosymm
ess_trsh_methods.append('scf=(qc,nosymm)')
ess_trsh_methods.append('scf=(qc)')
couldnt_trsh = False
elif 'SCF' in job_status['keywords'] and 'scf=(NDump=30)' not in ess_trsh_methods:
# Switching off Pulay's Direct Inversion
Expand Down Expand Up @@ -1607,3 +1620,17 @@ def trsh_keyword_unconverged(job_status, ess_trsh_methods, trsh_keyword, couldnt
fine = False

return ess_trsh_methods, trsh_keyword, fine, couldnt_trsh

def trsh_keyword_nosymm(job_status, ess_trsh_methods, trsh_keyword, couldnt_trsh) -> Tuple[List, List, bool]:
"""
Check if the job requires change of nosymm
"""
if 'NoSymm' in job_status['keywords'] and 'nosymm' not in ess_trsh_methods:
ess_trsh_methods.append('NoSymm')
trsh_keyword.append('nosymm')
couldnt_trsh = False
elif 'nosymm' not in trsh_keyword and any('NoSymm' in keyword for keyword in ess_trsh_methods):
trsh_keyword.append('nosymm')
couldnt_trsh = False

return ess_trsh_methods, trsh_keyword, couldnt_trsh
4 changes: 2 additions & 2 deletions arc/job/trsh_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,14 @@ def test_trsh_ess_job(self):
self.assertFalse(couldnt_trsh)

# Gaussian: test 2
job_status = {'keywords': ['InternalCoordinateError']}
job_status = {'keywords': ['InternalCoordinateError', 'NoSymm']}
output_errors, ess_trsh_methods, remove_checkfile, level_of_theory, software, job_type, fine, trsh_keyword, \
memory, shift, cpu_cores, couldnt_trsh = trsh.trsh_ess_job(label, level_of_theory, server, job_status,
job_type, software, fine, memory_gb,
num_heavy_atoms, cpu_cores, ess_trsh_methods)

self.assertTrue(remove_checkfile)
self.assertEqual(trsh_keyword, ['opt=(cartesian,nosymm)', 'int=(Acc2E=14)'] )
self.assertEqual(trsh_keyword, ['opt=(cartesian)', 'int=(Acc2E=14)', 'nosymm'] )

# Test Q-Chem
software = 'qchem'
Expand Down

0 comments on commit b47ea8e

Please sign in to comment.