Spaces:
Sleeping
Sleeping
| """Gradio HF Space for PhysFlow-Earth. | |
| The public Space uses synthetic coarse fields and a CPU bilinear surrogate to | |
| show the interface, resolution change, and physics-violation dashboard without | |
| private checkpoints or external Earth-observation downloads. | |
| """ | |
| from __future__ import annotations | |
| import gradio as gr | |
| VARIABLES = ["Sentinel-2 RGBN (4x SR)", "ERA5 precipitation (5x downscale)", "ERA5 wind (5x downscale)"] | |
| SCENARIOS = ["Historical", "SSP2-4.5", "SSP5-8.5"] | |
| def downscale( | |
| variable: str, | |
| aoi_geojson: str | None, | |
| year: int, | |
| scenario: str, | |
| enforce_physics: bool, | |
| progress=gr.Progress(track_tqdm=True), | |
| ): | |
| progress(0.1, desc="Loading pipeline") | |
| pipeline = _load_pipeline(variable) | |
| progress(0.4, desc="Fetching coarse data") | |
| x_lr = _fetch_coarse(variable, aoi_geojson, year, scenario) | |
| progress(0.6, desc="Running flow") | |
| sr = pipeline(x_lr) | |
| progress(0.85, desc="Computing physics violation") | |
| metrics = _violation_metrics(variable, x_lr, sr) | |
| return _to_image(x_lr), _to_image(sr), metrics | |
| def _load_pipeline(variable): | |
| """Return a CPU-safe demo pipeline for the public Space. | |
| The trainable `PhysFlowPipeline.from_pretrained(...)` path stays in the | |
| library, but the hosted demo should not depend on private checkpoints. | |
| """ | |
| import torch.nn.functional as F | |
| scale = 4 if "Sentinel" in variable else 5 | |
| def pipeline(x_lr): | |
| sr = F.interpolate(x_lr, scale_factor=scale, mode="bilinear", align_corners=False) | |
| return sr.clamp(-1, 1) | |
| return pipeline | |
| def _fetch_coarse(variable, aoi_geojson, year, scenario): | |
| import torch | |
| channels = 4 if "Sentinel" in variable else 1 | |
| grid_x = torch.linspace(-1, 1, 64).view(1, 1, 1, 64) | |
| grid_y = torch.linspace(-1, 1, 64).view(1, 1, 64, 1) | |
| phase = ((year - 1990) % 37) / 37.0 | |
| base = torch.sin(3.14 * (grid_x + phase)) * torch.cos(3.14 * (grid_y - phase)) | |
| if scenario != "Historical": | |
| base = base + (0.08 if scenario == "SSP2-4.5" else 0.16) | |
| if aoi_geojson: | |
| base = base + min(len(aoi_geojson), 100) / 1000.0 | |
| return base.repeat(1, channels, 1, 1).clamp(-1, 1) | |
| def _violation_metrics(variable, x_lr, sr) -> str: | |
| residual = float((sr.mean() - x_lr.mean()).abs()) | |
| band = float(sr.std().clamp(max=1.0)) | |
| return ( | |
| f"Variable: {variable}\n" | |
| f"Mass conservation residual: {residual:.3f}\n" | |
| f"Band-ratio violation proxy: {band:.3f}\n" | |
| "Divergence residual: n/a\n" | |
| ) | |
| def _to_image(t): | |
| import numpy as np | |
| arr = t[0].clamp(-1, 1).add(1).div(2).cpu().numpy() | |
| arr = (arr.transpose(1, 2, 0) * 255).clip(0, 255).astype("uint8") | |
| if arr.shape[-1] == 1: | |
| arr = np.concatenate([arr] * 3, axis=-1) | |
| elif arr.shape[-1] == 4: | |
| arr = arr[..., :3] | |
| return arr | |
| def build_ui(): | |
| with gr.Blocks(title="PhysFlow-Earth") as demo: | |
| gr.Markdown( | |
| "# PhysFlow-Earth\n" | |
| "CPU-safe synthetic-field demo for physics-informed Earth observation super-resolution." | |
| ) | |
| with gr.Row(): | |
| var = gr.Dropdown(VARIABLES, value=VARIABLES[0], label="Variable") | |
| scenario = gr.Dropdown(SCENARIOS, value="Historical", label="Scenario (climate only)") | |
| year = gr.Slider(1990, 2100, value=2030, step=1, label="Year") | |
| aoi = gr.Textbox(label="AOI bbox (GeoJSON or 'lon_min,lat_min,lon_max,lat_max')") | |
| enforce = gr.Checkbox(value=True, label="Enforce physics constraints at sampling time") | |
| with gr.Row(): | |
| coarse = gr.Image(label="Coarse input") | |
| sr = gr.Image(label="PhysFlow output (HR, physics-consistent)") | |
| violation = gr.Textbox(label="Physics violation dashboard", lines=4, interactive=False) | |
| gr.Button("Downscale").click( | |
| downscale, [var, aoi, year, scenario, enforce], [coarse, sr, violation] | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| build_ui().launch(server_name="0.0.0.0") | |