Download scripts/fake_data.py from OneScience-Group/GenCast: direct link, hf CLI and curl.
- Browser
- Download file 5.03 kB
-
https://huggingface.co/OneScience-Group/GenCast/resolve/main/scripts/fake_data.py
- Command line
-
hf download hf://OneScience-Group/GenCast/scripts/fake_data.py
-
curl -L -o fake_data.py https://huggingface.co/OneScience-Group/GenCast/resolve/main/scripts/fake_data.py
5.03 kB
| #!/usr/bin/env python3 | |
| """生成确定性的 ERA5、GenCast 统计量和静态场。""" | |
| from __future__ import annotations | |
| import argparse | |
| import sys | |
| from pathlib import Path | |
| import h5py | |
| import numpy as np | |
| import xarray | |
| import yaml | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(PROJECT_ROOT)) | |
| PRESSURE_LEVELS = (50, 100, 150, 200, 250, 300, 400, 500, 600, 700, 850, 925, 1000) | |
| SURFACE = ( | |
| "2m_temperature", "mean_sea_level_pressure", "10m_v_component_of_wind", | |
| "10m_u_component_of_wind", "sea_surface_temperature", "total_precipitation", | |
| ) | |
| ATMOSPHERIC = ( | |
| "temperature", "geopotential", "u_component_of_wind", | |
| "v_component_of_wind", "vertical_velocity", "specific_humidity", | |
| ) | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--config", default=str(PROJECT_ROOT / "conf/config.yaml")) | |
| parser.add_argument("--height", type=int) | |
| parser.add_argument("--width", type=int) | |
| parser.add_argument("--timesteps", type=int) | |
| parser.add_argument("--seed", type=int, default=42) | |
| return parser.parse_args() | |
| def _stat_dataset(value: float, *, minimum: bool = False) -> xarray.Dataset: | |
| data_vars = {} | |
| surface_targets = ( | |
| "2m_temperature", "mean_sea_level_pressure", "10m_v_component_of_wind", | |
| "10m_u_component_of_wind", "sea_surface_temperature", "total_precipitation_12hr", | |
| ) | |
| for name in surface_targets: | |
| scalar = -3.0 if minimum and name == "sea_surface_temperature" else value | |
| data_vars[name] = xarray.DataArray(np.float32(scalar)) | |
| for name in ATMOSPHERIC: | |
| data_vars[name] = xarray.DataArray( | |
| np.full(len(PRESSURE_LEVELS), value, dtype=np.float32), | |
| dims=("level",), | |
| coords={"level": np.asarray(PRESSURE_LEVELS, dtype=np.int32)}, | |
| ) | |
| # Generated forcings already in [-1, 1] — include so normalization is silent | |
| for name in ("year_progress_sin", "year_progress_cos", | |
| "day_progress_sin", "day_progress_cos"): | |
| data_vars[name] = xarray.DataArray(np.float32(value)) | |
| for name in ("geopotential_at_surface", "land_sea_mask"): | |
| data_vars[name] = xarray.DataArray(np.float32(value)) | |
| return xarray.Dataset(data_vars) | |
| def main() -> None: | |
| args = parse_args() | |
| with Path(args.config).open(encoding="utf-8") as source: | |
| config = yaml.safe_load(source) | |
| root = PROJECT_ROOT / config["data"]["data_dir"] | |
| height = int(args.height or config["fake_data"]["height"]) | |
| width = int(args.width or config["fake_data"]["width"]) | |
| timesteps = int(args.timesteps or config["fake_data"]["timesteps"]) | |
| if width != 2 * (height - 1): | |
| raise ValueError("Synthetic GenCast grid must satisfy width=2*(height-1)") | |
| variables = list(SURFACE) + [f"{name}_{level}" for name in ATMOSPHERIC for level in PRESSURE_LEVELS] | |
| years = sorted(set(config["data"]["train_years"] + config["data"]["test_years"])) | |
| rng = np.random.default_rng(args.seed) | |
| (root / "data").mkdir(parents=True, exist_ok=True) | |
| for year in years: | |
| path = root / "data" / f"{year}.h5" | |
| time = np.arange(timesteps, dtype=np.float32)[:, None, None, None] | |
| channel = np.arange(len(variables), dtype=np.float32)[None, :, None, None] | |
| lat = np.linspace(1.0, -1.0, height, dtype=np.float32)[None, None, :, None] | |
| lon = np.linspace(0.0, 2.0 * np.pi, width, endpoint=False, dtype=np.float32)[None, None, None, :] | |
| values = 0.01 * time + 0.001 * channel + 0.1 * lat + 0.05 * np.sin(lon) | |
| values += rng.normal(0.0, 1e-4, values.shape).astype(np.float32) | |
| precip_index = variables.index("total_precipitation") | |
| values[:, precip_index] = np.maximum(values[:, precip_index], 0.0) | |
| sst_index = variables.index("sea_surface_temperature") | |
| values[:, sst_index, : height // 4] = np.nan | |
| with h5py.File(path, "w") as output: | |
| fields = output.create_dataset("fields", data=values, chunks=(1, len(variables), height, width)) | |
| fields.attrs["variables"] = variables | |
| fields.attrs["time_step"] = 6 | |
| print(f"Generated {path} shape={values.shape}") | |
| static_dir = root / "static" | |
| static_dir.mkdir(parents=True, exist_ok=True) | |
| np.save( | |
| static_dir / "geopotential_at_surface.npy", | |
| np.zeros((height, width), dtype=np.float32), | |
| ) | |
| land = np.zeros((height, width), dtype=np.float32) | |
| land[: height // 4] = 1.0 | |
| np.save(static_dir / "land_mask.npy", land) | |
| stats_dir = root / "stats" | |
| stats_dir.mkdir(parents=True, exist_ok=True) | |
| _stat_dataset(0.0).to_netcdf(stats_dir / "mean_by_level.nc") | |
| _stat_dataset(1.0).to_netcdf(stats_dir / "stddev_by_level.nc") | |
| _stat_dataset(1.0).to_netcdf(stats_dir / "diffs_stddev_by_level.nc") | |
| _stat_dataset(0.0, minimum=True).to_netcdf(stats_dir / "min_by_level.nc") | |
| print(f"Generated GenCast statistics and static fields under {root}") | |
| if __name__ == "__main__": | |
| main() | |