Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for clearing and disabling the file cache #266

Merged
merged 1 commit into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions python/BioSimSpace/IO/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
.. autosummary::
:toctree: generated/

clearCache
disableCache
enableCache
fileFormats
formatInfo
readMolecules
Expand All @@ -38,3 +41,4 @@
"""

from ._io import *
from ._file_cache import *
45 changes: 42 additions & 3 deletions python/BioSimSpace/IO/_file_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
__author__ = "Lester Hedges"
__email__ = "[email protected]"

__all__ = ["check_cache", "update_cache"]
__all__ = ["clearCache", "disableCache", "enableCache"]

import collections as _collections
import hashlib as _hashlib
Expand Down Expand Up @@ -80,8 +80,43 @@ def __delitem__(self, key):
# to the same format, allowing us to re-use the existing file.
_cache = _FixedSizeOrderedDict()

# Whether to use the cache.
_use_cache = True

def check_cache(

def clearCache():
"""
Clear the file cache.
"""
global _cache
_cache = _FixedSizeOrderedDict()


def disableCache():
"""
Disable the file cache.
"""
global _use_cache
_use_cache = False


def enableCache():
"""
Enable the file cache.
"""
global _use_cache
_use_cache = True


def _cache_active():
"""
Internal helper function to check whether the cache is active.
"""
global _use_cache
return _use_cache


def _check_cache(
system,
format,
filebase,
Expand Down Expand Up @@ -157,6 +192,8 @@ def check_cache(
if not isinstance(skip_water, bool):
raise TypeError("'skip_water' must be of type 'bool'.")

global _cache

# Create the key.
key = (
system._sire_object.uid().toString(),
Expand Down Expand Up @@ -221,7 +258,7 @@ def check_cache(
return ext


def update_cache(
def _update_cache(
system,
format,
path,
Expand Down Expand Up @@ -284,6 +321,8 @@ def update_cache(
if not isinstance(skip_water, bool):
raise TypeError("'skip_water' must be of type 'bool'.")

global _cache

# Convert to an absolute path.
path = _os.path.abspath(path)

Expand Down
29 changes: 18 additions & 11 deletions python/BioSimSpace/IO/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@
from .._SireWrappers import System as _System
from .. import _Utils

from ._file_cache import check_cache as _check_cache
from ._file_cache import update_cache as _update_cache
from ._file_cache import _check_cache
from ._file_cache import _update_cache
from ._file_cache import _cache_active


# Context manager for capturing stdout.
Expand Down Expand Up @@ -741,14 +742,17 @@ def saveMolecules(
# Save the system using each file format.
for format in formats:
# Copy an existing file if it exists in the cache.
ext = _check_cache(
system,
format,
filebase,
match_water=match_water,
property_map=property_map,
**kwargs,
)
if _cache_active():
ext = _check_cache(
system,
format,
filebase,
match_water=match_water,
property_map=property_map,
**kwargs,
)
else:
ext = None
if ext:
files.append(_os.path.abspath(filebase + ext))
continue
Expand Down Expand Up @@ -835,7 +839,10 @@ def saveMolecules(
files += file

# If this is a new file, then add it to the cache.
_update_cache(system, format, file[0], match_water=match_water, **kwargs)
if _cache_active():
_update_cache(
system, format, file[0], match_water=match_water, **kwargs
)

except Exception as e:
msg = "Failed to save system to format: '%s'" % format
Expand Down
6 changes: 4 additions & 2 deletions python/BioSimSpace/Sandpit/Exscientia/IO/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
.. autosummary::
:toctree: generated/

clearCache
disableCache
enableCache
fileFormats
formatInfo
readMolecules
Expand All @@ -37,6 +40,5 @@
savePerturbableSystem
"""

from glob import glob

from ._io import *
from ._file_cache import *
45 changes: 42 additions & 3 deletions python/BioSimSpace/Sandpit/Exscientia/IO/_file_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
__author__ = "Lester Hedges"
__email__ = "[email protected]"

__all__ = ["check_cache", "update_cache"]
__all__ = ["clearCache", "disableCache", "enableCache"]

import collections as _collections
import hashlib as _hashlib
Expand Down Expand Up @@ -80,8 +80,43 @@ def __delitem__(self, key):
# to the same format, allowing us to re-use the existing file.
_cache = _FixedSizeOrderedDict()

# Whether to use the cache.
_use_cache = True

def check_cache(

def clearCache():
"""
Clear the file cache.
"""
global _cache
_cache = _FixedSizeOrderedDict()


def disableCache():
"""
Disable the file cache.
"""
global _use_cache
_use_cache = False


def enableCache():
"""
Enable the file cache.
"""
global _use_cache
_use_cache = True


def _cache_active():
"""
Internal helper function to check whether the cache is active.
"""
global _use_cache
return _use_cache


def _check_cache(
system,
format,
filebase,
Expand Down Expand Up @@ -157,6 +192,8 @@ def check_cache(
if not isinstance(skip_water, bool):
raise TypeError("'skip_water' must be of type 'bool'.")

global _cache

# Create the key.
key = (
system._sire_object.uid().toString(),
Expand Down Expand Up @@ -221,7 +258,7 @@ def check_cache(
return ext


def update_cache(
def _update_cache(
system,
format,
path,
Expand Down Expand Up @@ -284,6 +321,8 @@ def update_cache(
if not isinstance(skip_water, bool):
raise TypeError("'skip_water' must be of type 'bool'.")

global _cache

# Convert to an absolute path.
path = _os.path.abspath(path)

Expand Down
31 changes: 19 additions & 12 deletions python/BioSimSpace/Sandpit/Exscientia/IO/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@
from .._SireWrappers import System as _System
from .. import _Utils

from ._file_cache import check_cache as _check_cache
from ._file_cache import update_cache as _update_cache
from ._file_cache import _check_cache
from ._file_cache import _update_cache
from ._file_cache import _cache_active


# Context manager for capturing stdout.
Expand Down Expand Up @@ -741,14 +742,17 @@ def saveMolecules(
# Save the system using each file format.
for format in formats:
# Copy an existing file if it exists in the cache.
ext = _check_cache(
system,
format,
filebase,
match_water=match_water,
property_map=property_map,
**kwargs,
)
if _cache_active():
ext = _check_cache(
system,
format,
filebase,
match_water=match_water,
property_map=property_map,
**kwargs,
)
else:
ext = None
if ext:
files.append(_os.path.abspath(filebase + ext))
continue
Expand Down Expand Up @@ -835,7 +839,10 @@ def saveMolecules(
files += file

# If this is a new file, then add it to the cache.
_update_cache(system, format, file[0], match_water=match_water, **kwargs)
if _cache_active():
_update_cache(
system, format, file[0], match_water=match_water, **kwargs
)

except Exception as e:
msg = "Failed to save system to format: '%s'" % format
Expand Down Expand Up @@ -1162,7 +1169,7 @@ def readPerturbableSystem(top0, coords0, top1, coords1, property_map={}):
prop = property_map.get("time", "time")
time = system0._sire_object.property(prop)
system0._sire_object.removeSharedProperty(prop)
system0._sire_object.setPropery(prop, time)
system0._sire_object.setProperty(prop, time)
except:
pass

Expand Down
22 changes: 20 additions & 2 deletions tests/IO/test_file_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def test_file_cache():
"""

# Clear the file cache.
BSS.IO._file_cache._cache = BSS.IO._file_cache._FixedSizeOrderedDict()
BSS.IO.clearCache()

# Load the molecular system.
s = BSS.IO.readMolecules(["tests/input/ala.crd", "tests/input/ala.top"])
Expand Down Expand Up @@ -82,6 +82,21 @@ def test_file_cache():
# Make sure the number of atoms in the cache was decremented.
assert BSS.IO._file_cache._cache._num_atoms == total_atoms - num_atoms

# Clear the file cache.
BSS.IO.clearCache()

# The cache should now be empty.
assert len(BSS.IO._file_cache._cache) == 0

# Disable the cache.
BSS.IO.disableCache()

# Write to PDB and GroTop format. The PDB from the cache should not be reused.
BSS.IO.saveMolecules(f"{tmp_path}/tmp5", s, ["pdb", "grotop"])

# The cache should still be empty.
assert len(BSS.IO._file_cache._cache) == 0


@pytest.mark.skipif(
has_amber is False or has_openff is False,
Expand All @@ -93,8 +108,11 @@ def test_file_cache_mol_nums():
contain different MolNUms.
"""

# Enable the cache.
BSS.IO.enableCache()

# Clear the file cache.
BSS.IO._file_cache._cache = BSS.IO._file_cache._FixedSizeOrderedDict()
BSS.IO.clearCache()

# Create an initial system.
system = BSS.Parameters.openff_unconstrained_2_0_0("CO").getMolecule().toSystem()
Expand Down
22 changes: 20 additions & 2 deletions tests/Sandpit/Exscientia/IO/test_file_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_file_cache():
"""

# Clear the file cache.
BSS.IO._file_cache._cache = BSS.IO._file_cache._FixedSizeOrderedDict()
BSS.IO.clearCache()

# Load the molecular system.
s = BSS.IO.readMolecules([f"{root_fp}/input/ala.crd", f"{root_fp}/input/ala.top"])
Expand Down Expand Up @@ -83,6 +83,21 @@ def test_file_cache():
# Make sure the number of atoms in the cache was decremented.
assert BSS.IO._file_cache._cache._num_atoms == total_atoms - num_atoms

# Clear the file cache.
BSS.IO.clearCache()

# The cache should now be empty.
assert len(BSS.IO._file_cache._cache) == 0

# Disable the cache.
BSS.IO.disableCache()

# Write to PDB and GroTop format. The PDB from the cache should not be reused.
BSS.IO.saveMolecules(f"{tmp_path}/tmp5", s, ["pdb", "grotop"])

# The cache should still be empty.
assert len(BSS.IO._file_cache._cache) == 0


@pytest.mark.skipif(
has_amber is False or has_openff is False,
Expand All @@ -94,8 +109,11 @@ def test_file_cache_mol_nums():
contain different MolNUms.
"""

# Enable the cache.
BSS.IO.enableCache()

# Clear the file cache.
BSS.IO._file_cache._cache = BSS.IO._file_cache._FixedSizeOrderedDict()
BSS.IO.clearCache()

# Create an initial system.
system = BSS.Parameters.openff_unconstrained_2_0_0("CO").getMolecule().toSystem()
Expand Down
Loading