Pangu-ICON-DKE / scripts /inference.py
zhangrenchao's picture
Upload folder using huggingface_hub
e66b66f verified
Raw
History Blame Contribute Delete
3.55 kB
"""Compute complete-grid DKE products in latitude chunks and compact T719 spectra."""
import os
import sys
from pathlib import Path
import numpy as np
import torch
import yaml
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from model.pangu_icon_dke import PanguIconDKEDiagnostics
def main():
config = yaml.safe_load((ROOT / "conf/config.yaml").read_text())
checkpoint = torch.load(ROOT / config["paths"]["checkpoint"], map_location="cpu", weights_only=False)
if checkpoint["format_version"] != config["data"]["format_version"]:
raise ValueError("checkpoint protocol mismatch")
model = PanguIconDKEDiagnostics(checkpoint["protocol"], checkpoint["coefficients"])
world = int(os.environ.get("WORLD_SIZE", "1"))
distributed = world > 1
if distributed:
torch.distributed.init_process_group("gloo")
rank = torch.distributed.get_rank() if distributed else 0
experiments, times, _, nlat, nlon = model.fields.field_shape
chunk = int(config["runtime"]["latitude_chunk"])
local = {}
for experiment in range(rank, experiments, world):
global_dke = np.zeros(times, dtype=np.float64)
dke_maps = np.empty((times, nlat, nlon), dtype=np.float32)
spectrum = np.empty((times, int(checkpoint["protocol"]["triangular_truncation"]) + 1), dtype=np.float64)
weights_total = 0.0
weighted_sum = np.zeros(times, dtype=np.float64)
for start in range(0, nlat, chunk):
stop = min(start + chunk, nlat)
dke = model.fields.dke_chunk_all_times(experiment, slice(start, stop))
weights = np.cos(np.deg2rad(model.fields.latitudes[start:stop]))[None, :, None]
weighted_sum += np.sum(dke * weights, axis=(1, 2))
dke_maps[:, start:stop] = dke
weights_total += float(nlon * weights.sum())
global_dke[:] = weighted_sum / weights_total
for time in range(times):
spectrum[time] = model.fields.spectrum(experiment, time)
local[experiment] = (global_dke, dke_maps, spectrum)
if distributed:
gathered = [None] * world if rank == 0 else None
torch.distributed.gather_object(local, gathered, dst=0)
if rank == 0:
local = {key: value for shard in gathered for key, value in shard.items()}
if rank == 0:
ordered = [local[index] for index in range(experiments)]
global_dke = np.stack([item[0] for item in ordered])
maps = np.stack([item[1] for item in ordered])
spectra = np.stack([item[2] for item in ordered])
output = ROOT / config["paths"]["inference"]
output.parent.mkdir(parents=True, exist_ok=True)
np.savez_compressed(output, global_dke=global_dke, dke_maps=maps, spectra=spectra, experiments=np.asarray(checkpoint["protocol"]["experiments"]), times_hours=np.asarray(checkpoint["protocol"]["times_hours"]), latitudes_degrees=np.asarray(checkpoint["protocol"]["latitudes_degrees"]), longitudes_degrees=np.asarray(checkpoint["protocol"]["longitudes_degrees"]), total_wavenumber=np.arange(spectra.shape[-1]), format_version=np.asarray(checkpoint["format_version"]), logical_field_shape=np.asarray(checkpoint["protocol"]["field_shape"]), logical_spectral_shape=np.asarray(checkpoint["protocol"]["spectral_shape"]))
print(f"output={output.relative_to(ROOT)} global={global_dke.shape} maps={maps.shape} spectra={spectra.shape}")
if distributed:
torch.distributed.destroy_process_group()
if __name__ == "__main__":
main()