File size: 3,301 Bytes
b11ef36 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | """Generate compact hourly data retaining all 12 stations and six pollutants."""
import sys
from pathlib import Path
import numpy as np
import yaml
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from model.meteonorm_rf import BASE_FEATURES, FORMAT_VERSION, POLLUTANTS, STATIONS
def main():
config = yaml.safe_load((ROOT / "conf/config.yaml").read_text())
rng = np.random.default_rng(int(config["seed"]))
days = int(config["data"]["synthetic_days"])
hours = np.tile(np.arange(days * 24), len(STATIONS))
station = np.repeat(np.arange(len(STATIONS)), days * 24)
day = hours // 24
hour = hours % 24
doy = day + int(config["data"]["start_day_of_year"])
weekend = ((day + 1) % 7 >= 5).astype(np.float32)
seasonal = np.sin(2 * np.pi * (doy - 172) / 365.25)
diurnal = np.sin(2 * np.pi * (hour - 14) / 24)
synoptic = np.sin(2 * np.pi * day / 6.5 + station * 0.17)
wind_speed = np.maximum(0.2, 2.7 + 1.1 * synoptic + rng.normal(0, .55, len(hours)))
wind_direction = np.mod(185 + 75 * synoptic + station * 9 + rng.normal(0, 28, len(hours)), 360)
temperature = 13 + 12 * seasonal + 5.5 * diurnal + rng.normal(0, 1.4, len(hours))
rh = np.clip(52 - 18 * seasonal - 10 * diurnal - 3 * wind_speed + rng.normal(0, 7, len(hours)), 15, 98)
pressure = 1013 - .32 * temperature + 4 * np.cos(2 * np.pi * day / 8) + rng.normal(0, 1.8, len(hours))
ttrend = 2013.0 + hours / (24 * 365.25)
emission = 1.0 - .22 * day / max(days - 1, 1)
stagnation = np.exp(-wind_speed / 3.2) * (0.65 + rh / 150)
rush = ((hour >= 7) & (hour <= 10)) | ((hour >= 17) & (hour <= 21))
station_factor = 0.82 + station * .025
pm25 = (22 + 78 * stagnation + 16 * rush) * emission * station_factor
pm10 = 28 + 1.22 * pm25 + 7 * wind_speed
no2 = (15 + 37 * stagnation + 19 * rush) * emission * station_factor
so2 = (4 + 25 * stagnation) * emission ** 1.8 * (1.1 - .15 * seasonal)
o3 = np.maximum(3, 30 + 29 * np.maximum(diurnal, -.4) + 1.2 * temperature - .28 * no2)
co = (0.25 + .012 * pm25 + .008 * no2) * emission
pollution = np.column_stack([pm25, pm10, no2, so2, o3, co])
pollution *= rng.lognormal(0, .09, pollution.shape)
output = ROOT / config["data"]["path"]
output.parent.mkdir(parents=True, exist_ok=True)
np.savez_compressed(output, format_version=np.array(FORMAT_VERSION),
station_names=np.asarray(STATIONS), pollutant_names=np.asarray(POLLUTANTS),
station_id=station.astype(np.int16), timestamp_hour=hours.astype(np.int32),
ttrend=ttrend.astype(np.float32), day_of_year=doy.astype(np.float32),
weekend=weekend, hour=hour.astype(np.float32),
wind_speed=wind_speed.astype(np.float32), wind_direction=wind_direction.astype(np.float32),
pressure=pressure.astype(np.float32), temperature=temperature.astype(np.float32),
relative_humidity=rh.astype(np.float32), pollution=pollution.astype(np.float32),
feature_names=np.asarray(BASE_FEATURES))
print(f"data={output.relative_to(ROOT)} rows={len(hours)} stations=12 pollutants=6 hourly_days={days}")
if __name__ == "__main__":
main()
|