Skip to content

Commit 88095e6

Browse files
committed
B2
1 parent e48136a commit 88095e6

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

arc/scheduler.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4139,7 +4139,17 @@ def delete_all_species_jobs(self, label: str):
41394139
logger.info(f'Deleted job {job_name}')
41404140
job.delete()
41414141
self.running_jobs[label] = list()
4142-
self.output[label]['paths'] = {key: '' if key != 'irc' else list() for key in self.output[label]['paths'].keys()}
4142+
# Reset paths for this species. Most keys reset to ''; container-valued
4143+
# keys keep their type so the rest of the pipeline (composite tracking,
4144+
# IRC trajectory list) doesn't crash on a string where it expects a
4145+
# dict / list. Phase 3 added 'sp_composite' as a dict[sub_label → path];
4146+
# without the carve-out below it would collapse to '' here and the next
4147+
# composite sub-job completion would TypeError on item assignment.
4148+
_path_empty = {'irc': list, 'sp_composite': dict}
4149+
self.output[label]['paths'] = {
4150+
key: _path_empty.get(key, str)()
4151+
for key in self.output[label]['paths'].keys()
4152+
}
41434153
for job_type in self.output[label]['job_types']:
41444154
# rotors and bde are initialised to True (see initialize_output_dict) because
41454155
# species with no torsional modes / no BDE targets should not be blocked from

arc/scheduler_test.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,51 @@ def test_corrupt_paths_sp_composite_scalar_auto_heals(self):
16581658
base_path,
16591659
)
16601660

1661+
def test_delete_all_species_jobs_preserves_sp_composite_dict(self):
1662+
"""Regression: ``delete_all_species_jobs`` rebuilds ``paths`` via a
1663+
dict-comprehension that maps every key to ``''`` (with one carve-out
1664+
for ``'irc'`` → list). That clobbers ``paths['sp_composite']`` from
1665+
``dict[sub_label → path]`` to an empty string, and the next composite
1666+
sub-job completion crashes with
1667+
``TypeError: 'str' object does not support item assignment``.
1668+
1669+
``sp_composite`` must be preserved as ``dict()`` (parallel to ``irc``
1670+
being preserved as ``list()``)."""
1671+
tmp = os.path.join(self.project_directory, "fx_delete_all")
1672+
os.makedirs(tmp, exist_ok=True)
1673+
recipe = {
1674+
"base": {"method": "hf", "basis": "cc-pVTZ"},
1675+
"corrections": [
1676+
{"label": "delta_T", "type": "delta",
1677+
"high": {"method": "ccsdt", "basis": "cc-pVDZ"},
1678+
"low": {"method": "ccsd(t)", "basis": "cc-pVDZ"}},
1679+
],
1680+
}
1681+
protocol = CompositeProtocol.from_user_input(recipe)
1682+
spc = ARCSpecies(label='H2', smiles='[H][H]')
1683+
spc.final_xyz = {'symbols': ('H', 'H'),
1684+
'coords': ((0, 0, 0), (0, 0, 0.74)),
1685+
'isotopes': (1, 1)}
1686+
sched = self._make_scheduler([spc], sp_composite=protocol)
1687+
# Drive a base completion through the real path so paths['sp_composite']
1688+
# is a populated dict, not the freshly-init'd empty one.
1689+
base_path = os.path.join(tmp, "base.out")
1690+
self._write_gaussian_fixture(base_path, -1.10)
1691+
sched.post_sp_actions('H2', base_path, protocol.base.level)
1692+
self.assertIsInstance(sched.output['H2']['paths']['sp_composite'], dict)
1693+
self.assertEqual(sched.output['H2']['paths']['sp_composite']['base'], base_path)
1694+
# Now exercise the path that clobbers it. delete_all_species_jobs
1695+
# iterates self.job_dict[label] which the no-op test scheduler may
1696+
# leave empty — that's fine, the dict-comprehension at the end of
1697+
# the method runs unconditionally and is what corrupts paths.
1698+
sched.delete_all_species_jobs('H2')
1699+
# Contract: sp_composite stays a dict (parallel to irc staying a list).
1700+
self.assertIsInstance(sched.output['H2']['paths']['sp_composite'], dict)
1701+
# Next sub-job completion must not crash.
1702+
delta_T_high_path = os.path.join(tmp, "delta_T_high.out")
1703+
self._write_gaussian_fixture(delta_T_high_path, -1.15)
1704+
sched.post_sp_actions('H2', delta_T_high_path, protocol.corrections[0].high)
1705+
16611706
# --- Phase 3.5: preset name + reference preservation ------------------- #
16621707

16631708
def test_preset_name_and_reference_survive_to_notebook_section(self):

0 commit comments

Comments
 (0)