Source code for bldfm.cache

"""
Disk cache for Green's function results.

When footprint=True, the solver output depends only on the vertical profiles,
domain geometry, and measurement point — not on the surface flux field. Caching
these results avoids redundant solves when re-running with the same PBL/domain
configuration.
"""

import hashlib
import numpy as np
from pathlib import Path

from abltk.logging import get_logger

logger = get_logger("cache")


[docs] class GreensFunctionCache: """Disk-based cache for Green's function solver outputs. Cache key is a SHA-256 hash of the solver inputs that determine the Green's function: vertical grid, profiles, domain, modes, measurement point, halo, and precision. Parameters ---------- cache_dir : str or Path Directory for cache files. Created if it does not exist. """ def __init__(self, cache_dir=".bldfm_cache"): self.cache_dir = Path(cache_dir) self.cache_dir.mkdir(parents=True, exist_ok=True) def _compute_key(self, z, profiles, domain, modes, meas_pt, halo, precision): """Compute SHA-256 hash from solver inputs.""" h = hashlib.sha256() h.update(np.asarray(z).tobytes()) for arr in profiles: h.update(np.asarray(arr).tobytes()) h.update(np.asarray(domain).tobytes()) h.update(np.asarray(modes).tobytes()) h.update(np.asarray(meas_pt).tobytes()) h.update(str(halo).encode()) h.update(precision.encode()) return h.hexdigest()
[docs] def get(self, z, profiles, domain, modes, meas_pt, halo, precision): """Look up cached result. Returns ------- tuple or None (grid, conc, flx) if cached, None on miss. """ key = self._compute_key(z, profiles, domain, modes, meas_pt, halo, precision) path = self.cache_dir / f"{key}.npz" if path.exists(): logger.debug("Cache hit: %s", key[:12]) data = np.load(path) grid = (data["X"], data["Y"], data["Z"]) return grid, data["conc"], data["flx"] logger.debug("Cache miss: %s", key[:12]) return None
[docs] def put( self, z, profiles, domain, modes, meas_pt, halo, precision, grid, conc, flx ): """Store a result in the cache.""" key = self._compute_key(z, profiles, domain, modes, meas_pt, halo, precision) path = self.cache_dir / f"{key}.npz" X, Y, Z = grid np.savez(path, X=X, Y=Y, Z=Z, conc=conc, flx=flx) logger.debug("Cached: %s", key[:12])
[docs] def clear(self): """Remove all cached files.""" count = 0 for f in self.cache_dir.glob("*.npz"): f.unlink() count += 1 logger.info("Cleared %d cache entries", count)