File size: 8,029 Bytes
430bfd7 a6e0d00 430bfd7 a6e0d00 430bfd7 a6e0d00 51e44c2 430bfd7 51e44c2 430bfd7 51e44c2 430bfd7 51e44c2 430bfd7 a6e0d00 430bfd7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | """Read fixed native refinement levels, loading only requested native planes."""
import json
import re
import shutil
from functools import lru_cache
from pathlib import Path
from threading import Thread
import numpy as np
import zarr
PLANES = {"yz": (1, 2, 0), "xz": (0, 2, 1), "xy": (0, 1, 2)}
class NativeDataset:
def __init__(self, folder=None, repo_id=None, revision=None, prefix=""):
self.cache_status = (
"Local archive" if folder is not None else "Remote native slices"
)
self._local_arrays = None
self.remote_config = None if folder is not None else (repo_id, revision, prefix)
storage_options = None
if folder is not None:
folder = Path(folder)
self.manifest = json.loads((folder / "manifest.json").read_text())
store = str(folder / "fields.zarr")
else:
if not repo_id or not re.fullmatch(r"[0-9a-f]{40}", revision or ""):
raise ValueError("Remote data requires a dataset ID and pinned commit")
if prefix and not re.fullmatch(r"releases/[0-9a-f]{16}", prefix):
raise ValueError("Invalid immutable release prefix")
from huggingface_hub import hf_hub_download
path = hf_hub_download(
repo_id,
f"{prefix}/manifest.json" if prefix else "manifest.json",
repo_type="dataset",
revision=revision,
token=False,
)
self.manifest = json.loads(Path(path).read_text())
store = f"hf://datasets/{repo_id}@{revision}/{prefix + '/' if prefix else ''}fields.zarr"
storage_options = {"token": False}
m = self.manifest
if (
m.get("schema_version") != 1
or m.get("kind") != "native-fixed-level-voxels"
or not m.get("validated")
):
raise ValueError("An audited native dataset is required")
self.times = np.asarray(m["times"], dtype=float)
if (
not len(self.times)
or self.times[0] != 0
or not np.isfinite(self.times).all()
or np.any(np.diff(self.times) <= 0)
):
raise ValueError("Times must start at rest and increase strictly")
self.group = zarr.open_group(store, mode="r", storage_options=storage_options)
self.levels = m["levels"]
self.arrays = [self.group[f"level_{i}"] for i in range(len(self.levels))]
for a, lev in zip(self.arrays, self.levels):
if a.shape != (len(self.times), *lev["shape"]) or a.dtype != np.dtype(
"<f8"
):
raise ValueError("Native array shape or precision changed")
self.native_plane = lru_cache(maxsize=48)(self._native_plane)
def _native_plane(self, frame, level, plane, fixed, quantity):
"""Cache small native slabs, not the entire time series or full box."""
f = PLANES[plane][2]
component = slice(0, 3) if quantity == "velocity" else slice(3, 6)
select = [frame, slice(None), slice(None), slice(None), component]
select[f + 1] = fixed
arrays = self._local_arrays if self._local_arrays is not None else self.arrays
return np.asarray(arrays[level][tuple(select)])
def warm_archive_cache(self):
"""Optional CPU-Space disk cache; stay usable remotely while it fills."""
if self.remote_config is None:
return
from httpx import HTTPError
from huggingface_hub import constants, snapshot_download
repo_id, revision, prefix = self.remote_config
# The current archive fits CPU Basic's ephemeral disk. Larger future
# archives continue to use remote slabs instead of exhausting storage.
raw_bytes = sum(a.nbytes for a in self.arrays)
cache = Path(constants.HF_HUB_CACHE)
cache.mkdir(parents=True, exist_ok=True)
if (
raw_bytes > 18 * 2**30
or shutil.disk_usage(cache).free < raw_bytes + 5 * 2**30
):
self.cache_status = (
"Remote native slices · archive exceeds disk-cache budget"
)
return
self.cache_status = (
"Warming server-side archive cache · cold frames may be slow"
)
def warm():
try:
snapshot = snapshot_download(
repo_id,
repo_type="dataset",
revision=revision,
allow_patterns=[f"{prefix}/fields.zarr/**"],
token=False,
max_workers=4,
)
group = zarr.open_group(
str(Path(snapshot) / prefix / "fields.zarr"), mode="r"
)
arrays = [group[f"level_{i}"] for i in range(len(self.levels))]
if any(
a.shape != b.shape or a.dtype != b.dtype
for a, b in zip(arrays, self.arrays, strict=True)
):
raise ValueError("Cached layout differs from pinned native archive")
# Never read a half-downloaded store: absent chunks mean zeros.
# Publish the local arrays only after the entire snapshot is ready.
self._local_arrays = arrays
self.cache_status = (
"Native archive cached on server · no browser volume download"
)
print("Native archive disk cache ready", flush=True)
except (OSError, ValueError, RuntimeError, KeyError, HTTPError) as error:
self.cache_status = "Remote native slices · disk cache unavailable"
print(f"Archive cache unavailable: {type(error).__name__}", flush=True)
Thread(target=warm, name="native-archive-cache", daemon=True).start()
def sample_plane(self, frame, plane, coordinate, quantity="velocity", n=256):
if (
not isinstance(frame, (int, float, np.integer, np.floating))
or not np.isfinite(frame)
or isinstance(frame, bool)
or int(frame) != frame
or not 0 <= frame < len(self.times)
):
raise ValueError("Invalid saved frame")
if plane not in PLANES or quantity not in {"velocity", "force"}:
raise ValueError("Invalid plane or quantity")
if (
not np.isfinite(coordinate)
or not -1 <= coordinate <= 1
or n not in {64, 128, 256, 512, 1024}
):
raise ValueError("Invalid coordinate or display resolution")
coordinate = min(float(coordinate), np.nextafter(2.0, 0.0) - 1.0)
h, v, f = PLANES[plane]
axis = -1 + 2 * (np.arange(n) + 0.5) / n
output = np.full((n, n, 3), np.nan)
level_map = np.full((n, n), -1, dtype=np.int8)
for index, lev in enumerate(self.levels):
origin, dx = np.array(lev["origin"]), np.array(lev["spacing"])
size = np.array(lev["shape"][:3])
fixed = int(np.floor((coordinate - origin[f]) / dx[f]))
if not 0 <= fixed < size[f]:
continue
ih = np.floor((axis - origin[h]) / dx[h]).astype(int)
iv = np.floor((axis - origin[v]) / dx[v]).astype(int)
ph, pv = (
np.flatnonzero((ih >= 0) & (ih < size[h])),
np.flatnonzero((iv >= 0) & (iv < size[v])),
)
if not len(ph) or not len(pv):
continue
values = self.native_plane(int(frame), index, plane, fixed, quantity)
output[np.ix_(ph, pv)] = values[np.ix_(ih[ph], iv[pv])]
level_map[np.ix_(ph, pv)] = index
if not np.isfinite(output).all() or np.any(level_map < 0):
raise ValueError("Native hierarchy does not cover the requested plane")
return output, level_map
def clear_cache(self):
self.native_plane.cache_clear()
|