Download scripts/fake_data.py from OneScience-Group/UnetDif: direct link, hf CLI and curl.
- Browser
- Download file 3.96 kB
-
https://huggingface.co/OneScience-Group/UnetDif/resolve/main/scripts/fake_data.py
- Command line
-
hf download hf://OneScience-Group/UnetDif/scripts/fake_data.py
-
curl -L -o fake_data.py https://huggingface.co/OneScience-Group/UnetDif/resolve/main/scripts/fake_data.py
3.96 kB
| """Generate grouped synthetic rain days at the real 39x56x56 input shape.""" | |
| from pathlib import Path | |
| import numpy as np | |
| import yaml | |
| ROOT = Path(__file__).resolve().parents[1] | |
| def smooth(field: np.ndarray, rounds: int = 2) -> np.ndarray: | |
| for _ in range(rounds): | |
| field = sum(np.roll(np.roll(field, y, -2), x, -1) for y, x in ((0, 0), (1, 0), (-1, 0), (0, 1), (0, -1))) / 5 | |
| return field | |
| def make_day(rng: np.random.Generator, steps: int, height: int, width: int): | |
| yy, xx = np.mgrid[-1:1:complex(height), -1:1:complex(width)].astype(np.float32) | |
| terrain = np.clip(0.55 + 0.25 * yy + 0.16 * np.sin(2.5 * xx) - 0.12 * np.cos(3 * yy), 0, 1) | |
| center = rng.uniform(-0.45, 0.45, 2) | |
| velocity = rng.uniform(-0.10, 0.10, 2) | |
| width0 = rng.uniform(0.13, 0.27) | |
| amplitude = rng.uniform(12, 28) | |
| inputs = np.empty((steps, 39, height, width), np.float32) | |
| targets = np.empty((steps, height, width), np.float32) | |
| for step in range(steps): | |
| cy, cx = center + velocity * step | |
| rain = amplitude * np.exp(-((xx - cx) ** 2 + (yy - cy) ** 2) / (2 * width0**2)) | |
| rain += 0.35 * amplitude * np.exp(-((xx + cx * 0.5) ** 2 + (yy - cy * 0.6) ** 2) / (3 * width0**2)) | |
| rain = np.clip(rain * (0.8 + 0.3 * terrain) + rng.normal(0, 0.12, rain.shape), 0, None) | |
| forecast = np.clip(np.roll(rain, shift=(1, -1), axis=(0, 1)) * (1.12 + 0.08 * terrain) - 0.25, 0, None) | |
| channels = np.empty((39, height, width), np.float32) | |
| for variable in range(8): | |
| for level in range(4): | |
| index = variable * 4 + level | |
| noise = smooth(rng.normal(0, 0.05, rain.shape).astype(np.float32)) | |
| if variable == 1: # humidity follows rain and terrain | |
| channels[index] = 0.45 + 0.02 * rain + 0.12 * terrain - 0.025 * level + noise | |
| elif variable == 4: # vertical velocity is strongest near moving rain | |
| channels[index] = -0.08 * rain / (level + 1) + 0.04 * (xx * velocity[1] + yy * velocity[0]) + noise | |
| else: | |
| channels[index] = (variable + 1) * 0.12 + level * 0.04 + 0.08 * xx - 0.05 * yy + noise | |
| for index in range(32, 37): | |
| channels[index] = 0.1 * (index - 31) + 0.03 * rain + smooth(rng.normal(0, 0.04, rain.shape).astype(np.float32)) | |
| channels[37] = forecast | |
| channels[38] = terrain | |
| inputs[step], targets[step] = channels, rain | |
| return inputs, targets, terrain | |
| def main(): | |
| config = yaml.safe_load((ROOT / "conf/config.yaml").read_text()) | |
| data = config["data"] | |
| expected = (8, 39, 56, 56) | |
| actual = (int(data["time_steps"]), int(data["channels"]), int(data["height"]), int(data["width"])) | |
| if actual != expected or len(data["lead_hours"]) != expected[0]: | |
| raise ValueError(f"fixed data contract is {expected} with eight lead hours, got {actual}") | |
| counts = data["rain_days"] | |
| output = ROOT / data["root"] | |
| output.mkdir(parents=True, exist_ok=True) | |
| seed = int(config["seed"]) | |
| group_id = 0 | |
| for split_index, split in enumerate(("train", "val", "test")): | |
| arrays, targets, terrains, groups = [], [], [], [] | |
| for day in range(int(counts[split])): | |
| x, y, terrain = make_day(np.random.default_rng(seed + group_id), int(data["time_steps"]), int(data["height"]), int(data["width"])) | |
| arrays.append(x); targets.append(y); terrains.append(terrain); groups.append(group_id) | |
| group_id += 1 | |
| np.savez_compressed( | |
| output / f"{split}.npz", inputs=np.stack(arrays), targets=np.stack(targets), | |
| terrain=np.stack(terrains), group_id=np.asarray(groups), split=np.asarray(split), | |
| format_version=np.asarray(data["format_version"]), lead_hours=np.asarray(data["lead_hours"]), | |
| ) | |
| print(f"split={split} rain_days={counts[split]} inputs={np.stack(arrays).shape}") | |
| if __name__ == "__main__": | |
| main() | |