Spaces:
Sleeping
Sleeping
| """ | |
| SQLite cache for simulation results. | |
| Keyed on SHA256 hash of the full parameter vector. | |
| Stores all scalar outputs. Does NOT cache history arrays (too large). | |
| """ | |
| import sqlite3 | |
| import hashlib | |
| import json | |
| import os | |
| import time | |
| _DEFAULT_DB = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'sweep_cache.db') | |
| class SweepCache: | |
| """Persistent cache for simulation scalar outputs.""" | |
| def __init__(self, db_path=_DEFAULT_DB): | |
| self.db_path = db_path | |
| self._conn = sqlite3.connect(db_path, check_same_thread=False) | |
| self._conn.execute('PRAGMA journal_mode=WAL') | |
| self._conn.execute(''' | |
| CREATE TABLE IF NOT EXISTS cache ( | |
| param_hash TEXT PRIMARY KEY, | |
| params_json TEXT NOT NULL, | |
| scalars_json TEXT NOT NULL, | |
| wall_time_s REAL, | |
| created_at REAL | |
| ) | |
| ''') | |
| self._conn.commit() | |
| self._hits = 0 | |
| self._misses = 0 | |
| def _make_key(Pexit_barg, speed_f, Ptank_barg, Psat_barg, | |
| ICVparam, DCVparam, pump_geom, proc_param, | |
| fluid='h2', flash_eff=0.0): | |
| """Hash the full parameter vector to a cache key.""" | |
| def _round(v): | |
| if isinstance(v, (int, float)): | |
| return round(float(v), 8) | |
| if isinstance(v, (list, tuple)): | |
| return [_round(x) for x in v] | |
| return v | |
| vec = { | |
| 'Pexit_barg': _round(Pexit_barg), | |
| 'speed_f': _round(speed_f), | |
| 'Ptank_barg': _round(Ptank_barg), | |
| 'Psat_barg': _round(Psat_barg), | |
| 'ICVparam': _round(list(ICVparam)), | |
| 'DCVparam': _round(list(DCVparam)), | |
| 'pump_geom': _round(list(pump_geom)), | |
| 'proc_param': _round(list(proc_param)), | |
| 'fluid': fluid, | |
| 'flash_eff': _round(flash_eff), | |
| } | |
| raw = json.dumps(vec, sort_keys=True, separators=(',', ':')) | |
| return hashlib.sha256(raw.encode()).hexdigest(), raw | |
| def get(self, **kwargs): | |
| """Look up cached scalars. Returns (scalars_dict, wall_time) or None.""" | |
| key, _ = self._make_key(**kwargs) | |
| row = self._conn.execute( | |
| 'SELECT scalars_json, wall_time_s FROM cache WHERE param_hash = ?', | |
| (key,) | |
| ).fetchone() | |
| if row: | |
| self._hits += 1 | |
| return json.loads(row[0]), row[1] | |
| self._misses += 1 | |
| return None | |
| def put(self, scalars, wall_time_s, **kwargs): | |
| """Store simulation scalars in cache.""" | |
| key, params_json = self._make_key(**kwargs) | |
| clean = {} | |
| for k, v in scalars.items(): | |
| try: | |
| clean[k] = float(v) | |
| except (TypeError, ValueError): | |
| clean[k] = v | |
| self._conn.execute( | |
| 'INSERT OR REPLACE INTO cache (param_hash, params_json, scalars_json, wall_time_s, created_at) ' | |
| 'VALUES (?, ?, ?, ?, ?)', | |
| (key, params_json, json.dumps(clean), wall_time_s, time.time()) | |
| ) | |
| self._conn.commit() | |
| def stats(self): | |
| total = self._conn.execute('SELECT COUNT(*) FROM cache').fetchone()[0] | |
| hit_rate = self._hits / (self._hits + self._misses) if (self._hits + self._misses) > 0 else 0 | |
| return { | |
| 'total_cached': total, | |
| 'session_hits': self._hits, | |
| 'session_misses': self._misses, | |
| 'hit_rate': hit_rate, | |
| } | |
| def close(self): | |
| self._conn.close() | |