diff --git a/FOX/classes/armc.py b/FOX/classes/armc.py index 54cc900b..84ceee27 100644 --- a/FOX/classes/armc.py +++ b/FOX/classes/armc.py @@ -32,7 +32,9 @@ from .monte_carlo import MonteCarlo from ..logger import Plams2Logger, get_logger -from ..io.hdf5_utils import create_hdf5, to_hdf5, create_xyz_hdf5, _get_filename_xyz +from ..io.hdf5_utils import ( + create_hdf5, to_hdf5, create_xyz_hdf5, _get_filename_xyz, hdf5_clear_status +) from ..io.file_container import NullContext from ..functions.utils import get_template from ..armc_functions.sanitization import init_armc_sanitization @@ -520,6 +522,16 @@ def restart(self) -> None: if not os.path.isfile(xyz): create_xyz_hdf5(self.hdf5_file, self.molecule, iter_len=self.sub_iter_len) + # Check that both .hdf5 files can be opened; clear their status if not + closed = hdf5_clear_status(xyz) + if not closed: + self.logger.warning(f"Unable to open ...{os.sep}{os.path.basename(xyz)}, " + "file status was forcibly reset") + closed = hdf5_clear_status(self.hdf5_file) + if not closed: + self.logger.warning(f"Unable to open ...{os.sep}{os.path.basename(self.hdf5_file)}, " + "file status was forcibly reset") + # Finish the current set of sub-iterations j += 1 for omega in range(j, self.sub_iter_len): diff --git a/FOX/io/hdf5_utils.py b/FOX/io/hdf5_utils.py index 078655b1..b6621281 100644 --- a/FOX/io/hdf5_utils.py +++ b/FOX/io/hdf5_utils.py @@ -42,6 +42,7 @@ """ +import subprocess from os import remove from time import sleep from typing import Dict, Iterable, Optional, Union, Hashable, List, Tuple @@ -300,6 +301,17 @@ def _get_kwarg_dict(armc: 'FOX.ARMC') -> Settings: """################################### Updating .hdf5 files ####################################""" +@assert_error(H5PY_ERROR) +def hdf5_clear_status(filename: str) -> bool: + """Run the :code:`h5clear filename` command if **filename** refuses to open.""" + try: + with h5py.File(filename, 'r+', libver='latest'): + return True + except OSError: + subprocess.run(['h5clear', '-s', 'repr(filename)']) + return False + + @assert_error(H5PY_ERROR) def hdf5_availability(filename: str, timeout: float = 5.0, max_attempts: Optional[int] = 10) -> None: @@ -329,12 +341,12 @@ def hdf5_availability(filename: str, timeout: float = 5.0, Raised if **max_attempts** is exceded. """ - warning = "OSWarning: '{}' is currently unavailable; repeating attempt in {:.0f} seconds" + warning = "WARNING: '{}' is currently unavailable; repeating attempt in {:.0f} seconds" i = max_attempts or np.inf while i: try: - with h5py.File(filename, 'r+', libver='latest') as _: + with h5py.File(filename, 'r+', libver='latest'): return # the .hdf5 file can safely be opened except OSError as ex: # the .hdf5 file cannot be safely opened yet print((warning).format(filename, timeout)) @@ -405,6 +417,9 @@ def _xyz_to_hdf5(filename: str, omega: int, All to-be exported :class:`MultiMolecule` instance(s) or float (*e.g.* ``np.nan``). """ + # Check if the hdf5 file is already opened. If opened: wait for 5 sec and try again. + hdf5_availability(filename) + with h5py.File(filename, 'r+', libver='latest') as f: if not isinstance(mol_list, abc.Iterable): # Check if mol_list is a scalar (np.nan) i = 0