Download code/bifurcation/fid/heterogeneous_waves.py from coarse-grained-forecasting-benchmark/forecasting-models: direct link, hf CLI and curl.
- Browser
- Download file 3.35 kB
-
https://huggingface.co/coarse-grained-forecasting-benchmark/forecasting-models/resolve/main/code/bifurcation/fid/heterogeneous_waves.py
- Command line
-
hf download hf://coarse-grained-forecasting-benchmark/forecasting-models/code/bifurcation/fid/heterogeneous_waves.py
-
curl -L -o heterogeneous_waves.py https://huggingface.co/coarse-grained-forecasting-benchmark/forecasting-models/resolve/main/code/bifurcation/fid/heterogeneous_waves.py
3.35 kB
| """Heterogeneous-wave FID adapter: the SAME 196-D coarse spectral observable as Euler and the passive scalar (98 complex modes |k| <= 8, Hermitian half, coefficients / N^2, shared mode order from | |
| ``bifurcation.models.spectral``) -> the exact low-pass DISPLACEMENT field u on a 128x128 grid -> symmetric clip -> | |
| uint8 -> 3 identical channels. | |
| The reconstruction is byte-identical to the Euler adapter's (one inverse FFT, one mode-index map); only the physical | |
| reading differs. The observed field is the wave displacement u of | |
| u_t = v, v_t = div(c^2 grad u) - gamma v, c^2(x, y) = 1 + 0.5 sin(2 pi x) sin(2 pi y), | |
| which is signed and zero-mean (the DC mode is not retained by the observable), so the symmetric clip about zero is | |
| the right quantization (a nonnegative [0, c] range would throw away half of every wave crest-trough pair). | |
| The velocity v and the unresolved band 8 < |k| <= 16 are hidden, which is what makes p(x_T | x_0) non-degenerate; | |
| neither enters the image, which is a function of the observed state alone. | |
| Physical diagnostics, both computed from the coefficient vectors: | |
| * ``displacement_variance_ratio`` — mean sum |u_hat_k|^2, the direct analogue of Euler's enstrophy ratio and the | |
| passive scalar's scalar-variance ratio; | |
| * ``gradient_energy_ratio`` — mean sum |k|^2 |u_hat_k|^2, the resolved part of the potential energy density | |
| c^2 |grad u|^2 up to the medium factor; a wave field can match the first moment while carrying its energy at | |
| the wrong wavenumber, and this separates the two. | |
| """ | |
| from __future__ import annotations | |
| import numpy as np | |
| from ..models.spectral import K_C, mode_int_wavenumbers | |
| from .adapters import register_adapter | |
| from .euler import EulerVorticityAdapter | |
| class HeterogeneousWavesAdapter(EulerVorticityAdapter): | |
| field_kind = "signed" | |
| def __init__(self, quantile: float = 0.9999, n_disp: int = 128, k_c: int = K_C, **kwargs): | |
| super().__init__(quantile, n_disp=n_disp, k_c=k_c, **kwargs) | |
| kx, ky = mode_int_wavenumbers(self.k_c) | |
| self._k2 = kx.astype(np.float64) ** 2 + ky.astype(np.float64) ** 2 | |
| def card(self) -> dict: | |
| c = super().card() | |
| c.update({"state": "196-D coarse spectral wave displacement (98 complex modes |k| <= 8, Hermitian half, u_hat / N^2)", | |
| "clip": "symmetric [-c, c], c = Q_q(|u|) over the training pool", | |
| "physical_diagnostic": "displacement_variance_ratio = mean_gen sum|u_hat_k|^2 / mean_truth sum|u_hat_k|^2; " | |
| "gradient_energy_ratio = mean_gen sum|k|^2|u_hat_k|^2 / mean_truth sum|k|^2|u_hat_k|^2"}) | |
| return c | |
| def _moments(self, v: np.ndarray) -> tuple[float, float]: | |
| v = np.asarray(v, np.float64) | |
| n = self.n_modes | |
| power = v[:, :n] ** 2 + v[:, n:] ** 2 # |u_hat_k|^2 per retained mode | |
| return float(np.mean(np.sum(power, axis=1))), float(np.mean(np.sum(self._k2 * power, axis=1))) | |
| def physical_diagnostics(self, gen_raw: np.ndarray, true_raw: np.ndarray) -> dict: | |
| dg, gg = self._moments(gen_raw) | |
| dt, gt = self._moments(true_raw) | |
| return {"displacement_variance_ratio": dg / dt if dt > 0 else float("nan"), | |
| "gradient_energy_ratio": gg / gt if gt > 0 else float("nan")} | |