diff --git a/arkane/encorr/bac.py b/arkane/encorr/bac.py index d459d9ffd0..d1472860aa 100644 --- a/arkane/encorr/bac.py +++ b/arkane/encorr/bac.py @@ -814,35 +814,51 @@ def write_to_database(self, overwrite: bool = False, alternate_path: str = None) has_entries = bool(data.mbac) if self.bac_type == 'm' else bool(data.pbac) # Add new BACs to file without changing existing formatting + # First: find the BACs dict in the file for i, line in enumerate(lines): if keyword in line: - if has_entries: - if self.level_of_theory in bac_dict: - if overwrite: - # Does not overwrite comments - del_idx_start = del_idx_end = None - for j, line2 in enumerate(lines[i:]): - if repr(self.level_of_theory) in line2: - del_idx_start = i + j - del_idx_end = None - elif line2.rstrip() == ' },': # Can't have comment after final brace - del_idx_end = i + j + 1 - if del_idx_start is not None and del_idx_end is not None: - if (lines[del_idx_start - 1].lstrip().startswith('#') - or lines[del_idx_end + 1].lstrip().startswith('#')): - logging.warning('There may be left over comments from previous BACs') - lines[del_idx_start:del_idx_end] = bacs_formatted - break - else: - raise IOError( - f'{self.level_of_theory} already exists. Set `overwrite` to True.' - ) - else: - lines[(i+1):(i+1)] = ['\n'] + bacs_formatted - else: - lines[i] = f'{keyword} = {{\n' - lines[(i+1):(i+1)] = ['\n'] + bacs_formatted + ['\n}\n'] break + else: + # 'pbac' and 'mbac' should both be found at `data_path` + raise RuntimeError(f'Keyword "{keyword} is not found in the data file. ' + f'Please check the database file at {data_path} and ' + f'make sure an up-to-date RMG-database branch is used.') + + # Second: Write the BACs block into the BACs dict + # Does not overwrite comments + if self.level_of_theory in bac_dict and overwrite: + del_idx_start = del_idx_end = None + lot_repr = repr(self.level_of_theory) + for j, line2 in enumerate(lines[i:]): + if lot_repr in line2 and 'Composite' not in lot_repr and 'Composite' not in line2: + del_idx_start = i + j + elif lot_repr in line2 and 'Composite' in lot_repr: + del_idx_start = i + j + + if del_idx_start is not None and line2.rstrip() == ' },': # Can't have comment after final brace + del_idx_end = i + j + 1 + if (lines[del_idx_start - 1].lstrip().startswith('#') + or lines[del_idx_end + 1].lstrip().startswith('#')): + logging.warning('There may be left over comments from previous BACs') + lines[del_idx_start:del_idx_end] = bacs_formatted + break + + # Check if the entry is successfully inserted to the `lines` + if del_idx_start is None or del_idx_end is None: + raise RuntimeError(f'The script cannot identify the corresponding block for the given BACs. ' + f'It is possible that the database file at {data_path} is not correctly ' + f'formatted. Please check the file.') + + elif self.level_of_theory in bac_dict and not overwrite: + raise IOError( + f'{self.level_of_theory} already exists. Set `overwrite` to True.' + ) + else: + # Either empty BACs dict or adding BACs for a new level of theory + if not has_entries and '}' in lines[i]: # Empty BACs dict + lines[i] = f'{keyword} = {{\n' + lines[(i+1):(i+1)] = ['\n}\n'] + lines[(i+1):(i+1)] = ['\n'] + bacs_formatted with open(data_path if alternate_path is None else alternate_path, 'w') as f: f.writelines(lines) diff --git a/arkane/encorr/bacTest.py b/arkane/encorr/bacTest.py index 02dae4d2cf..34d18a7712 100644 --- a/arkane/encorr/bacTest.py +++ b/arkane/encorr/bacTest.py @@ -48,7 +48,7 @@ from arkane.encorr.data import BACDataset, BOND_SYMBOLS, _pybel_to_rmg from arkane.encorr.reference import ReferenceDatabase from arkane.exceptions import BondAdditivityCorrectionError -from arkane.modelchem import LevelOfTheory +from arkane.modelchem import LevelOfTheory, CompositeLevelOfTheory class TestBAC(unittest.TestCase): @@ -59,6 +59,7 @@ class TestBAC(unittest.TestCase): @classmethod def setUpClass(cls): cls.lot_get = LevelOfTheory(method='CCSD(T)-F12', basis='cc-pVTZ-F12', software='Molpro') + cls.lot_get_composite = CompositeLevelOfTheory(freq=LevelOfTheory(method='wb97xd3',basis='def2tzvp',software='qchem'),energy=LevelOfTheory(method='ccsd(t)f12',basis='ccpvtzf12',software='molpro')) cls.lot_fit = LevelOfTheory(method='wB97M-V', basis='def2-TZVPD', software='Q-Chem') cls.lot_nonexisting = LevelOfTheory('notamethod') @@ -242,6 +243,12 @@ def test_write_to_database(self): spec.loader.exec_module(module) # Load data as module self.assertEqual(self.bac.bacs, module.pbac[repr(self.bac.level_of_theory)]) + # Check that existing Composite Petersson BACs can be overwritten + self.bac.level_of_theory = self.lot_get_composite + self.bac.write_to_database(overwrite=True, alternate_path=tmp_datafile_path) + spec.loader.exec_module(module) # Load data as module + self.assertEqual(self.bac.bacs, module.pbac[repr(self.bac.level_of_theory)]) + # Check that new Petersson BACs can be written self.bac.level_of_theory = self.lot_nonexisting self.bac.bacs = self.tmp_petersson_params diff --git a/documentation/source/users/arkane/input.rst b/documentation/source/users/arkane/input.rst index 9bc627080c..c66348f730 100644 --- a/documentation/source/users/arkane/input.rst +++ b/documentation/source/users/arkane/input.rst @@ -125,7 +125,8 @@ Model Chemistry AEC BC SOC Freq Scale Supp ``'CCSD-F12/cc-pVDZ-F12'`` v v v (0.947) H, C, N, O ``'CCSD(T)-F12/cc-pVDZ-F12_H-TZ'`` v v H, C, N, O ``'CCSD(T)-F12/cc-pVDZ-F12_H-QZ'`` v v H, C, N, O -``'CCSD(T)-F12/cc-pVnZ-F12'``, *n = D,T,Q* v v v v H, C, N, O, S +``'CCSD(T)-F12/cc-pVnZ-F12'``, *n = D,T* v v v v H, C, N, O, F, S, Cl +``'CCSD(T)-F12/cc-pVQZ-F12'`` v v v v H, C, N, O, S ``'CCSD(T)-F12/cc-pVDZ-F12_noscale'`` v v H, C, N, O ``'CCSD(T)-F12/cc-pCVnZ-F12'``, *n = D,T,Q* v v v H, C, N, O ``'CCSD(T)-F12/aug-cc-pVnZ'``, *n = D,T,Q* v v v H, C, N, O, S