fire2a.meteo

👋🌎 Some functions related to kitral weather scenario creation.

  1#!python3
  2"""👋🌎
  3Some functions related to kitral weather scenario creation.
  4"""
  5__author__ = "Caro"
  6__revision__ = "$Format:%H$"
  7
  8from datetime import datetime, timedelta
  9from pathlib import Path
 10
 11import numpy as np
 12import pandas as pd
 13
 14# debug aqui = Path()
 15aqui = Path(__file__).parent
 16# Ruta a los datos de estaciones
 17ruta_data = aqui / "DB_DMC"
 18
 19
 20def file_name(i, numsims):
 21    if numsims > 1:
 22        return f"Weather{i+1}.csv"
 23    return "Weather.csv"
 24
 25
 26def scenario_name(i, numsims):
 27    if numsims > 1:
 28        return f"DMC_{i+1}"
 29    return "DMC"
 30
 31
 32def distancia(fila, y_i, x_i):
 33    if y_i == fila["lat"] and x_i == fila["lon"]:
 34        return 0
 35    return np.sqrt((fila["lat"] - x_i) ** 2 + (fila["lon"] - y_i) ** 2)
 36
 37
 38def meteo_to_c2f(alfa):
 39    if alfa >= 0 and alfa < 180:
 40        return round(alfa + 180, 2)
 41    elif alfa >= 180 and alfa <= 360:
 42        return round(alfa - 180, 2)
 43    return np.nan
 44
 45
 46def barlo_sota(a):
 47    return round((a + 180) % 360, 2)
 48
 49
 50def generate(x, y, start_datetime, rowres, numrows, numsims, outdir):
 51    """dummy generator function
 52    Args:
 53        x (float): x-coordinate of the ignition point, EPSG 4326
 54        y (float): y-coordinate of the ignition point, EPSG 4326
 55        start_datetime (datetime): starting time of the weather scenario
 56        rowres (int): time resolution in minutes (not implemented yet)
 57        numrows (int): number of hours in the weather scenario
 58        numsims (int): number of weather scenarios
 59        outdir (Path): output directory
 60    Return:
 61        retval (int): 0 if successful, 1 otherwise, 2...
 62        outdict (dict): output dictionary at least 'filelist': list of filenames created
 63    """
 64    filelist = []
 65    try:
 66
 67        if not outdir.is_dir():
 68            outdir.mkdir()
 69
 70        dn = 3
 71        list_stn = pd.read_csv(ruta_data / "Estaciones.csv")
 72        list_stn["Distancia"] = list_stn.apply(distancia, args=(y, x), axis=1)  # calculo distancia
 73        stn = list_stn.sort_values(by=["Distancia"]).head(dn)["nombre"].tolist()
 74
 75        meteos = pd.DataFrame()
 76        for st in stn:
 77            df = pd.read_csv(ruta_data / f"{st}.csv", sep=",")
 78            df["station"] = st
 79            meteos = pd.concat([meteos, df], ignore_index=True)
 80        meteos["datetime"] = pd.to_datetime(meteos["datetime"], errors="coerce")
 81        # available days by stations
 82        days = meteos.groupby(meteos.datetime.dt.date).first()["station"]
 83
 84        for i in range(numsims):
 85            # draw station and day
 86            cd = 0
 87            ch = 0
 88            while True:
 89                station = np.random.choice(stn)
 90                chosen_days = days[days == station]
 91                if chosen_days.empty:
 92                    if cd > 10:
 93                        # print("Not enough data days", cd, ch)
 94                        return 1, {"filelist": [], "exception": "No data in closest stations"}
 95                    cd += 1
 96                    continue
 97                day = np.random.choice(chosen_days.index)
 98                start = datetime.combine(day - timedelta(days=ch), start_datetime.time())
 99                chosen_meteo = meteos[(meteos["datetime"] >= start) & (meteos["station"] == station)]
100                if len(chosen_meteo) < numrows:
101                    if ch > len(meteos):
102                        # print("Not enough data hours", cd, ch)
103                        return 1, {"filelist": [], "exception": "Not enough data"}
104                    ch += 1
105                    continue
106                break
107            # take rows
108            chosen_meteo = chosen_meteo.head(numrows)
109            # drop station
110            chosen_meteo = chosen_meteo.drop(columns=["station"])
111            # wind direction
112            chosen_meteo.loc[:, "WD"] = chosen_meteo["WD"].apply(barlo_sota)
113            # scenario name
114            chosen_meteo.loc[:, "Scenario"] = scenario_name(i, numsims)
115            # datetime format
116            chosen_meteo.loc[:, "datetime"] = chosen_meteo["datetime"].dt.strftime("%Y-%m-%dT%H:%M:%S")
117            # reorder
118            chosen_meteo = chosen_meteo[["Scenario", "datetime", "WS", "WD", "TMP", "RH"]]
119            # write
120            # print("head", chosen_meteo.head())
121            tmpfile = outdir / file_name(i, numsims)
122            filelist += [tmpfile.name]
123            chosen_meteo.to_csv(tmpfile, header=True, index=False)
124        return 0, {"filelist": filelist}
125
126    except Exception as e:
127        return 1, {"filelist": filelist, "exception": e}
aqui = PosixPath('/__w/fire2a-lib/fire2a-lib/src/fire2a')
ruta_data = PosixPath('/__w/fire2a-lib/fire2a-lib/src/fire2a/DB_DMC')
def file_name(i, numsims):
21def file_name(i, numsims):
22    if numsims > 1:
23        return f"Weather{i+1}.csv"
24    return "Weather.csv"
def scenario_name(i, numsims):
27def scenario_name(i, numsims):
28    if numsims > 1:
29        return f"DMC_{i+1}"
30    return "DMC"
def distancia(fila, y_i, x_i):
33def distancia(fila, y_i, x_i):
34    if y_i == fila["lat"] and x_i == fila["lon"]:
35        return 0
36    return np.sqrt((fila["lat"] - x_i) ** 2 + (fila["lon"] - y_i) ** 2)
def meteo_to_c2f(alfa):
39def meteo_to_c2f(alfa):
40    if alfa >= 0 and alfa < 180:
41        return round(alfa + 180, 2)
42    elif alfa >= 180 and alfa <= 360:
43        return round(alfa - 180, 2)
44    return np.nan
def barlo_sota(a):
47def barlo_sota(a):
48    return round((a + 180) % 360, 2)
def generate(x, y, start_datetime, rowres, numrows, numsims, outdir):
 51def generate(x, y, start_datetime, rowres, numrows, numsims, outdir):
 52    """dummy generator function
 53    Args:
 54        x (float): x-coordinate of the ignition point, EPSG 4326
 55        y (float): y-coordinate of the ignition point, EPSG 4326
 56        start_datetime (datetime): starting time of the weather scenario
 57        rowres (int): time resolution in minutes (not implemented yet)
 58        numrows (int): number of hours in the weather scenario
 59        numsims (int): number of weather scenarios
 60        outdir (Path): output directory
 61    Return:
 62        retval (int): 0 if successful, 1 otherwise, 2...
 63        outdict (dict): output dictionary at least 'filelist': list of filenames created
 64    """
 65    filelist = []
 66    try:
 67
 68        if not outdir.is_dir():
 69            outdir.mkdir()
 70
 71        dn = 3
 72        list_stn = pd.read_csv(ruta_data / "Estaciones.csv")
 73        list_stn["Distancia"] = list_stn.apply(distancia, args=(y, x), axis=1)  # calculo distancia
 74        stn = list_stn.sort_values(by=["Distancia"]).head(dn)["nombre"].tolist()
 75
 76        meteos = pd.DataFrame()
 77        for st in stn:
 78            df = pd.read_csv(ruta_data / f"{st}.csv", sep=",")
 79            df["station"] = st
 80            meteos = pd.concat([meteos, df], ignore_index=True)
 81        meteos["datetime"] = pd.to_datetime(meteos["datetime"], errors="coerce")
 82        # available days by stations
 83        days = meteos.groupby(meteos.datetime.dt.date).first()["station"]
 84
 85        for i in range(numsims):
 86            # draw station and day
 87            cd = 0
 88            ch = 0
 89            while True:
 90                station = np.random.choice(stn)
 91                chosen_days = days[days == station]
 92                if chosen_days.empty:
 93                    if cd > 10:
 94                        # print("Not enough data days", cd, ch)
 95                        return 1, {"filelist": [], "exception": "No data in closest stations"}
 96                    cd += 1
 97                    continue
 98                day = np.random.choice(chosen_days.index)
 99                start = datetime.combine(day - timedelta(days=ch), start_datetime.time())
100                chosen_meteo = meteos[(meteos["datetime"] >= start) & (meteos["station"] == station)]
101                if len(chosen_meteo) < numrows:
102                    if ch > len(meteos):
103                        # print("Not enough data hours", cd, ch)
104                        return 1, {"filelist": [], "exception": "Not enough data"}
105                    ch += 1
106                    continue
107                break
108            # take rows
109            chosen_meteo = chosen_meteo.head(numrows)
110            # drop station
111            chosen_meteo = chosen_meteo.drop(columns=["station"])
112            # wind direction
113            chosen_meteo.loc[:, "WD"] = chosen_meteo["WD"].apply(barlo_sota)
114            # scenario name
115            chosen_meteo.loc[:, "Scenario"] = scenario_name(i, numsims)
116            # datetime format
117            chosen_meteo.loc[:, "datetime"] = chosen_meteo["datetime"].dt.strftime("%Y-%m-%dT%H:%M:%S")
118            # reorder
119            chosen_meteo = chosen_meteo[["Scenario", "datetime", "WS", "WD", "TMP", "RH"]]
120            # write
121            # print("head", chosen_meteo.head())
122            tmpfile = outdir / file_name(i, numsims)
123            filelist += [tmpfile.name]
124            chosen_meteo.to_csv(tmpfile, header=True, index=False)
125        return 0, {"filelist": filelist}
126
127    except Exception as e:
128        return 1, {"filelist": filelist, "exception": e}

dummy generator function Args: x (float): x-coordinate of the ignition point, EPSG 4326 y (float): y-coordinate of the ignition point, EPSG 4326 start_datetime (datetime): starting time of the weather scenario rowres (int): time resolution in minutes (not implemented yet) numrows (int): number of hours in the weather scenario numsims (int): number of weather scenarios outdir (Path): output directory Return: retval (int): 0 if successful, 1 otherwise, 2... outdict (dict): output dictionary at least 'filelist': list of filenames created