loone-data-prep 1.2.3__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/PKG-INFO +1 -1
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/GEOGLOWS_LOONE_DATA_PREP.py +47 -16
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/LOONE_DATA_PREP.py +0 -1
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/get_Chla_predicted.py +1 -1
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/get_NO_Loads_predicted.py +1 -1
- loone_data_prep-1.3.0/loone_data_prep/forecast_scripts/new_combined_weather_forecast.py +220 -0
- loone_data_prep-1.3.0/loone_data_prep/herbie_utils.py +29 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/utils.py +19 -2
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep.egg-info/PKG-INFO +1 -1
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep.egg-info/SOURCES.txt +2 -2
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/pyproject.toml +1 -1
- loone_data_prep-1.2.3/loone_data_prep/forecast_scripts/create_forecast_LOWs.py +0 -127
- loone_data_prep-1.2.3/loone_data_prep/forecast_scripts/weather_forecast.py +0 -155
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/LICENSE +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/README.md +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/__init__.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/data_analyses_fns.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/S65E_total.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/__init__.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/forecast_bias_correction.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/get_forecast_flows.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/get_inflows.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/get_outflows.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/hydro.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/Chla_merged.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/forecast_stages.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/loone_q_predict.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/loone_wq_predict.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/predict_PI.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/trib_cond.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_level_data/__init__.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_level_data/get_all.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_level_data/hydro.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_quality_data/__init__.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_quality_data/get_inflows.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_quality_data/get_lake_wq.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_quality_data/wq.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/weather_data/__init__.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/weather_data/get_all.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/weather_data/weather.py +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep.egg-info/dependency_links.txt +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep.egg-info/requires.txt +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep.egg-info/top_level.txt +0 -0
- {loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: loone_data_prep
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Prepare data to run the LOONE model.
|
|
5
5
|
Author-email: Osama Tarabih <osamatarabih@usf.edu>
|
|
6
6
|
Maintainer-email: Michael Souffront <msouffront@aquaveo.com>, James Dolinar <jdolinar@aquaveo.com>
|
|
@@ -15,7 +15,7 @@ from loone_data_prep.utils import stg2sto, stg2ar
|
|
|
15
15
|
import datetime
|
|
16
16
|
|
|
17
17
|
START_DATE = datetime.datetime.now()
|
|
18
|
-
END_DATE = START_DATE + datetime.timedelta(days=
|
|
18
|
+
END_DATE = START_DATE + datetime.timedelta(days=14)
|
|
19
19
|
|
|
20
20
|
M3_Yr = 2008
|
|
21
21
|
M3_M = 1
|
|
@@ -373,8 +373,8 @@ def main(input_dir: str, output_dir: str, ensemble_number: str) -> None: # , hi
|
|
|
373
373
|
C44RO_df['C44RO_cmd'] = C44RO
|
|
374
374
|
C43RO_df['C43RO'] = C43RO_df['C43RO_cmd']/(0.0283168466 * 86400)
|
|
375
375
|
C44RO_df['C44RO'] = C44RO_df['C44RO_cmd']/(0.0283168466 * 86400)
|
|
376
|
-
C43RO_df.to_csv(f'{output_dir}/C43RO_{ensemble_number}.csv'
|
|
377
|
-
C44RO_df.to_csv(f'{output_dir}/C44RO_{ensemble_number}.csv'
|
|
376
|
+
C43RO_df.to_csv(f'{output_dir}/C43RO_{ensemble_number}.csv')
|
|
377
|
+
C44RO_df.to_csv(f'{output_dir}/C44RO_{ensemble_number}.csv')
|
|
378
378
|
C43RO_df.index = pd.to_datetime(C43RO_df["date"])
|
|
379
379
|
C43RO_df = C43RO_df.drop(columns="date")
|
|
380
380
|
|
|
@@ -384,13 +384,13 @@ def main(input_dir: str, output_dir: str, ensemble_number: str) -> None: # , hi
|
|
|
384
384
|
C43Mon = C43RO_df.resample('ME').mean()
|
|
385
385
|
C44Mon = C44RO_df.resample('ME').mean()
|
|
386
386
|
|
|
387
|
-
C43Mon.to_csv(f'{output_dir}/C43RO_Monthly_{ensemble_number}.csv'
|
|
388
|
-
C44Mon.to_csv(f'{output_dir}/C44RO_Monthly_{ensemble_number}.csv'
|
|
387
|
+
C43Mon.to_csv(f'{output_dir}/C43RO_Monthly_{ensemble_number}.csv')
|
|
388
|
+
C44Mon.to_csv(f'{output_dir}/C44RO_Monthly_{ensemble_number}.csv')
|
|
389
389
|
Basin_RO = pd.DataFrame(C44Mon.index, columns=['date'])
|
|
390
390
|
# Basin_RO['SLTRIB'] = SLTRIBMon['SLTRIB_cfs'].values * 1.9835 # cfs to acft
|
|
391
391
|
Basin_RO['C44RO'] = C44Mon['C44RO'].values * 86400
|
|
392
392
|
Basin_RO['C43RO'] = C43Mon['C43RO'].values * 86400
|
|
393
|
-
Basin_RO.to_csv(f'{output_dir}/Basin_RO_inputs_{ensemble_number}.csv'
|
|
393
|
+
Basin_RO.to_csv(f'{output_dir}/Basin_RO_inputs_{ensemble_number}.csv')
|
|
394
394
|
|
|
395
395
|
# # Get monthly C43RO and C44RO from historical run
|
|
396
396
|
# shutil.copyfile(os.path.join(historical_files_src, "C43RO_Monthly.csv"), os.path.join(output_dir, 'C43RO_Monthly.csv'))
|
|
@@ -461,16 +461,47 @@ def main(input_dir: str, output_dir: str, ensemble_number: str) -> None: # , hi
|
|
|
461
461
|
LOWS.to_csv(f"{output_dir}/LOWS_predicted.csv")
|
|
462
462
|
|
|
463
463
|
# # RFVol acft
|
|
464
|
-
|
|
465
|
-
#
|
|
466
|
-
#
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
#
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
#
|
|
473
|
-
#
|
|
464
|
+
RF_data = pd.read_csv(f'{input_dir}/LAKE_RAINFALL_DATA_FORECAST.csv')
|
|
465
|
+
# RF_data_copy = RF_data.copy()
|
|
466
|
+
# LO_Stg_Sto_SA_df_copy = LO_Stg_Sto_SA_df.copy()
|
|
467
|
+
RF_data['date'] = pd.to_datetime(RF_data['date'])
|
|
468
|
+
# LO_Stg_Sto_SA_df_copy['date'] = pd.to_datetime(LO_Stg_Sto_SA_df_copy['date'])
|
|
469
|
+
# LO_Stg_Sto_SA_df_copy.index.name = None
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
# merged_rf_sa = pd.merge(RF_data_copy[['date', 'average_rainfall']],
|
|
473
|
+
# LO_Stg_Sto_SA_df_copy[['date', 'SA_acres']],
|
|
474
|
+
# on='date', how='inner')
|
|
475
|
+
#I am just using the most recent SA_acres value for all forecast dates since we do not have forecasted surface area
|
|
476
|
+
RFVol = pd.DataFrame(RF_data['date'], columns=['date'])
|
|
477
|
+
RFVol['RFVol_acft'] = (RF_data['average_rainfall'].values/12) * LO_Stg_Sto_SA_df["SA_acres"].iloc[-1]
|
|
478
|
+
|
|
479
|
+
date_reference = RFVol['date'].iloc[0]
|
|
480
|
+
date_inserts = [date_reference - datetime.timedelta(days=2), date_reference - datetime.timedelta(days=1)]
|
|
481
|
+
df_insert = pd.DataFrame(data={'date': date_inserts, 'RFVol_acft': [0.0, 0.0]})
|
|
482
|
+
RFVol = pd.concat([df_insert, RFVol])
|
|
483
|
+
RFVol.to_csv(f'{output_dir}/RFVol_Forecast.csv', index=False)
|
|
484
|
+
|
|
485
|
+
# ETVol acft
|
|
486
|
+
# Create File (ETVol)
|
|
487
|
+
# Merge the DataFrames on date to ensure matching rows
|
|
488
|
+
ET_data = pd.read_csv(f'{input_dir}/LOONE_AVERAGE_ETPI_DATA_FORECAST.csv')
|
|
489
|
+
# ET_data_copy = ET_data.copy()
|
|
490
|
+
# LO_Stg_Sto_SA_df_copy = LO_Stg_Sto_SA_df.copy()
|
|
491
|
+
ET_data['date'] = pd.to_datetime(ET_data['date'])
|
|
492
|
+
# LO_Stg_Sto_SA_df_copy['date'] = pd.to_datetime(LO_Stg_Sto_SA_df_copy['date'])
|
|
493
|
+
# merged_et_sa = pd.merge(ET_data_copy[['date', 'average_ETPI']],
|
|
494
|
+
# LO_Stg_Sto_SA_df_copy[['date', 'SA_acres']],
|
|
495
|
+
# on='date', how='inner')
|
|
496
|
+
|
|
497
|
+
ETVol = pd.DataFrame(ET_data['date'], columns=['date'])
|
|
498
|
+
ETVol['ETVol_acft'] = (ET_data['average_ETPI'].values/12) * LO_Stg_Sto_SA_df["SA_acres"].iloc[-1]
|
|
499
|
+
date_reference = ETVol['date'].iloc[0]
|
|
500
|
+
date_inserts = [date_reference - datetime.timedelta(days=2), date_reference - datetime.timedelta(days=1)]
|
|
501
|
+
df_insert = pd.DataFrame(data={'date': date_inserts, 'ETVol_acft': [0.0, 0.0]})
|
|
502
|
+
ETVol = pd.concat([df_insert, ETVol])
|
|
503
|
+
ETVol.to_csv(f'{output_dir}/ETVol_forecast.csv', index=False)
|
|
504
|
+
|
|
474
505
|
|
|
475
506
|
# # WCA Stages
|
|
476
507
|
# # Create File (WCA_Stages_Inputs)
|
|
@@ -351,7 +351,6 @@ def main(input_dir: str, output_dir: str) -> None:
|
|
|
351
351
|
S65E.index = pd.to_datetime(S65E.index, unit='ns')
|
|
352
352
|
S65E_Weekly = S65E.resample('W-FRI').mean()
|
|
353
353
|
# PI
|
|
354
|
-
# TODO
|
|
355
354
|
# This is prepared manually
|
|
356
355
|
# Weekly data is downloaded from https://www.ncei.noaa.gov/access/monitoring/weekly-palmers/time-series/0804
|
|
357
356
|
# State:Florida Division:4.South Central
|
|
@@ -9,7 +9,7 @@ def get_Chla_predicted(input_dir, output_dir):
|
|
|
9
9
|
output_dir: Directory where the output files will be saved.
|
|
10
10
|
"""
|
|
11
11
|
# Read forecast inflow file and get overall date range
|
|
12
|
-
#
|
|
12
|
+
# We are only taking the dates, so it is okay to just use one ensemble because they all have the same dates
|
|
13
13
|
Q_in = pd.read_csv(os.path.join(input_dir, 'LO_Inflows_BK_forecast_01.csv'))
|
|
14
14
|
Q_in['date'] = pd.to_datetime(Q_in['date'])
|
|
15
15
|
date_start = Q_in['date'].min()
|
|
@@ -9,7 +9,7 @@ def get_NO_Loads_predicted(input_dir, output_dir):
|
|
|
9
9
|
output_dir: Directory where the output files will be saved.
|
|
10
10
|
This function reads the forecast inflow file, retrieves nitrate data for specified stations,
|
|
11
11
|
"""
|
|
12
|
-
#
|
|
12
|
+
# It is okay to use just one ensemble because they all have the same dates and we only use the dates
|
|
13
13
|
Q_in = pd.read_csv(os.path.join(input_dir, 'LO_Inflows_BK_forecast_01.csv'))
|
|
14
14
|
|
|
15
15
|
datetime_str = Q_in['date'].iloc[0]
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import warnings
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from retry import retry
|
|
6
|
+
from loone_data_prep.herbie_utils import get_fast_herbie_object
|
|
7
|
+
from herbie import FastHerbie
|
|
8
|
+
import openmeteo_requests
|
|
9
|
+
from retry_requests import retry as retry_requests
|
|
10
|
+
import requests_cache
|
|
11
|
+
|
|
12
|
+
warnings.filterwarnings("ignore", message="Will not remove GRIB file because it previously existed.")
|
|
13
|
+
|
|
14
|
+
POINTS = pd.DataFrame({
|
|
15
|
+
"station": ["L001", "L005", "L006", "LZ40"],
|
|
16
|
+
"longitude": [-80.7934, -80.9724, -80.7828, -80.7890],
|
|
17
|
+
"latitude": [27.1389, 26.9567, 26.8226, 26.9018]
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
WIND_FILE_MAP = {
|
|
21
|
+
"L001": ("L001_WNDS_MPH_predicted.csv", "L001_WNDS_MPH"),
|
|
22
|
+
"L005": ("L005_WNDS_MPH_predicted.csv", "L005_WNDS_MPH"),
|
|
23
|
+
"L006": ("L006_WNDS_MPH_predicted.csv", "L006_WNDS_MPH"),
|
|
24
|
+
"LZ40": ("LZ40_WNDS_MPH_predicted.csv", "LZ40_WNDS_MPH")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
AIRT_FILE_MAP = {
|
|
28
|
+
"L001": "L001_AIRT_Degrees Celsius_forecast.csv",
|
|
29
|
+
"L005": "L005_AIRT_Degrees Celsius_forecast.csv",
|
|
30
|
+
"L006": "L006_AIRT_Degrees Celsius_forecast.csv",
|
|
31
|
+
"LZ40": "LZ40_AIRT_Degrees Celsius_forecast.csv"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
AIRT_COLUMN_MAP = {
|
|
35
|
+
"L001": "L001_AIRT_Degrees Celsius",
|
|
36
|
+
"L005": "L005_AIRT_Degrees Celsius",
|
|
37
|
+
"L006": "L006_AIRT_Degrees Celsius",
|
|
38
|
+
"LZ40": "LZ40_AIRT_Degrees Celsius"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@retry(Exception, tries=5, delay=15, max_delay=60, backoff=2)
|
|
42
|
+
def download_herbie_variable(FH, variable_key, variable_name, point_df):
|
|
43
|
+
"""Download a Herbie variable for a given point and return a DataFrame."""
|
|
44
|
+
FH.download(f":{variable_key}")
|
|
45
|
+
ds = FH.xarray(f":{variable_key}", backend_kwargs={"decode_timedelta": True})
|
|
46
|
+
dsi = ds.herbie.pick_points(point_df, method="nearest")
|
|
47
|
+
|
|
48
|
+
var_name = {
|
|
49
|
+
"10u": "u10",
|
|
50
|
+
"10v": "v10",
|
|
51
|
+
"2t": "t2m"
|
|
52
|
+
}.get(variable_name, variable_name)
|
|
53
|
+
|
|
54
|
+
ts = dsi[var_name].squeeze()
|
|
55
|
+
df = ts.to_dataframe().reset_index()
|
|
56
|
+
if "valid_time" in df.columns:
|
|
57
|
+
df.rename(columns={"valid_time": "datetime"}, inplace=True)
|
|
58
|
+
elif "time" in df.columns:
|
|
59
|
+
df.rename(columns={"time": "datetime"}, inplace=True)
|
|
60
|
+
|
|
61
|
+
df = df[["datetime", var_name]].drop_duplicates()
|
|
62
|
+
ds.close()
|
|
63
|
+
dsi.close()
|
|
64
|
+
del ds, dsi, ts
|
|
65
|
+
return df
|
|
66
|
+
|
|
67
|
+
# Download ET from Open-Meteo
|
|
68
|
+
def download_hourly_et(lat, lon):
|
|
69
|
+
cache_session = requests_cache.CachedSession('.cache', expire_after=3600)
|
|
70
|
+
retry_session = retry_requests(cache_session, retries=5, backoff_factor=0.2)
|
|
71
|
+
client = openmeteo_requests.Client(session=retry_session)
|
|
72
|
+
|
|
73
|
+
url = "https://api.open-meteo.com/v1/forecast"
|
|
74
|
+
params = {
|
|
75
|
+
"latitude": lat,
|
|
76
|
+
"longitude": lon,
|
|
77
|
+
"hourly": "evapotranspiration",
|
|
78
|
+
"forecast_days": 16,
|
|
79
|
+
"models": "gfs_seamless"
|
|
80
|
+
}
|
|
81
|
+
responses = client.weather_api(url, params=params)
|
|
82
|
+
response = responses[0]
|
|
83
|
+
|
|
84
|
+
hourly = response.Hourly()
|
|
85
|
+
hourly_evap = hourly.Variables(0).ValuesAsNumpy()
|
|
86
|
+
hourly_data = {"date": pd.date_range(
|
|
87
|
+
start=pd.to_datetime(hourly.Time(), unit="s"),
|
|
88
|
+
end=pd.to_datetime(hourly.TimeEnd(), unit="s"),
|
|
89
|
+
freq=pd.Timedelta(seconds=hourly.Interval()),
|
|
90
|
+
inclusive="left"
|
|
91
|
+
)}
|
|
92
|
+
hourly_data["evapotranspiration"] = hourly_evap
|
|
93
|
+
return pd.DataFrame(hourly_data)
|
|
94
|
+
|
|
95
|
+
# Main generation function
|
|
96
|
+
def generate_all_outputs(output_dir):
|
|
97
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
98
|
+
today_str = datetime.today().strftime('%Y-%m-%d 00:00')
|
|
99
|
+
FH = get_fast_herbie_object(today_str)
|
|
100
|
+
|
|
101
|
+
# Forecasted weather data (single point)
|
|
102
|
+
point_df = pd.DataFrame({"longitude": [-80.7976], "latitude": [26.9690]})
|
|
103
|
+
forecast_vars = ["10u", "10v", "2t", "tp", "ssrd"]
|
|
104
|
+
data = {var: download_herbie_variable(FH, var, var, point_df) for var in forecast_vars}
|
|
105
|
+
|
|
106
|
+
merged = data["10u"].merge(data["10v"], on="datetime")
|
|
107
|
+
merged = merged.merge(data["2t"], on="datetime")
|
|
108
|
+
merged = merged.merge(data["tp"], on="datetime")
|
|
109
|
+
merged = merged.merge(data["ssrd"], on="datetime")
|
|
110
|
+
|
|
111
|
+
# Derived columns
|
|
112
|
+
merged["wind_speed"] = (merged["u10"]**2 + merged["v10"]**2)**0.5 # wind speed in m/s
|
|
113
|
+
merged["wind_speed_corrected"] = 0.4167 * merged["wind_speed"] + 4.1868
|
|
114
|
+
merged["tp_inc_m"] = merged["tp"].diff().clip(lower=0)
|
|
115
|
+
# Convert incremental meters → mm
|
|
116
|
+
merged["tp_inc_mm"] = merged["tp_inc_m"] * 1000.0
|
|
117
|
+
# Apply bias correction (in mm)
|
|
118
|
+
merged["tp_corrected_mm"] = 0.7247 * merged["tp_inc_mm"] + 0.1853
|
|
119
|
+
# convert to inches
|
|
120
|
+
merged["tp_corrected"] = merged["tp_corrected_mm"] * 0.0393701
|
|
121
|
+
|
|
122
|
+
merged["ssrd_kwm2"] = merged["ssrd"].diff() / merged["datetime"].diff().dt.total_seconds() / 1000
|
|
123
|
+
merged["ssrd_corrected"] = (1.0530 * merged["ssrd_kwm2"] - 0.0347).clip(lower=0)
|
|
124
|
+
merged = merged[[
|
|
125
|
+
"datetime",
|
|
126
|
+
"wind_speed_corrected",
|
|
127
|
+
"tp_corrected",
|
|
128
|
+
"ssrd_corrected"
|
|
129
|
+
]]
|
|
130
|
+
|
|
131
|
+
# ET for main point
|
|
132
|
+
df_et = download_hourly_et(26.9690, -80.7976)
|
|
133
|
+
merged = merged.merge(df_et, left_on="datetime", right_on="date", how="left").drop(columns=["date"])
|
|
134
|
+
merged.to_csv(os.path.join(output_dir, "forecasted_weather_data.csv"), index=False)
|
|
135
|
+
|
|
136
|
+
# 4-point wind and air temp CSVs
|
|
137
|
+
for idx, row in POINTS.iterrows():
|
|
138
|
+
station = row["station"]
|
|
139
|
+
point_df = pd.DataFrame({"longitude": [row.longitude], "latitude": [row.latitude]})
|
|
140
|
+
|
|
141
|
+
# Wind
|
|
142
|
+
df_u = download_herbie_variable(FH, "10u", "10u", point_df)
|
|
143
|
+
df_v = download_herbie_variable(FH, "10v", "10v", point_df)
|
|
144
|
+
merged_ws = df_u.merge(df_v, on="datetime")
|
|
145
|
+
merged_ws["wind_speed"] = (merged_ws["u10"]**2 + merged_ws["v10"]**2)**0.5
|
|
146
|
+
merged_ws["wind_speed_corrected"] = 0.4167 * merged_ws["wind_speed"] + 4.1868
|
|
147
|
+
|
|
148
|
+
filename, new_col = WIND_FILE_MAP[station]
|
|
149
|
+
merged_ws[["datetime", "wind_speed_corrected"]].rename(
|
|
150
|
+
columns={"datetime": "date", "wind_speed_corrected": new_col}
|
|
151
|
+
).to_csv(os.path.join(output_dir, filename), index=False)
|
|
152
|
+
|
|
153
|
+
# Air temp
|
|
154
|
+
df_t = download_herbie_variable(FH, "2t", "2t", point_df)
|
|
155
|
+
df_t["t2m"] = df_t["t2m"] - 273.15
|
|
156
|
+
df_t.rename(columns={"datetime": "date", "t2m": AIRT_COLUMN_MAP[station]}).to_csv(
|
|
157
|
+
os.path.join(output_dir, AIRT_FILE_MAP[station]), index=False
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Rainfall, ET, and SSRD 4-point CSVs
|
|
161
|
+
rainfall_dfs, et_dfs, ssrd_dfs = [], [], []
|
|
162
|
+
|
|
163
|
+
for idx, row in POINTS.iterrows():
|
|
164
|
+
station = row["station"]
|
|
165
|
+
point_df = pd.DataFrame({"longitude": [row.longitude], "latitude": [row.latitude]})
|
|
166
|
+
|
|
167
|
+
# Rainfall
|
|
168
|
+
df_tp = download_herbie_variable(FH, "tp", "tp", point_df)
|
|
169
|
+
# Convert cumulative meters → incremental meters
|
|
170
|
+
df_tp["tp_inc_m"] = df_tp["tp"].diff().clip(lower=0)
|
|
171
|
+
# Convert incremental meters → millimeters
|
|
172
|
+
df_tp["tp_inc_mm"] = df_tp["tp_inc_m"] * 1000.0
|
|
173
|
+
df_tp["date_only"] = df_tp["datetime"].dt.date
|
|
174
|
+
# Sum incremental precipitation per day
|
|
175
|
+
df_daily = df_tp.groupby("date_only")["tp_inc_mm"].sum().reset_index()
|
|
176
|
+
# Apply bias correction on daily totals (in mm)
|
|
177
|
+
df_daily["tp_corrected_mm"] = 0.7247 * df_daily["tp_inc_mm"] + 0.1853
|
|
178
|
+
# Convert corrected mm → inches
|
|
179
|
+
df_daily["tp_corrected_in"] = df_daily["tp_corrected_mm"] * 0.0393701
|
|
180
|
+
df_daily = df_daily.rename(columns={"date_only": "date", "tp_corrected_in": station})
|
|
181
|
+
rainfall_dfs.append(df_daily[["date", station]])
|
|
182
|
+
|
|
183
|
+
# ET
|
|
184
|
+
df_et_point = download_hourly_et(row.latitude, row.longitude)
|
|
185
|
+
df_et_point.rename(columns={"evapotranspiration": station}, inplace=True)
|
|
186
|
+
et_dfs.append(df_et_point)
|
|
187
|
+
|
|
188
|
+
# SSRD
|
|
189
|
+
df_ssrd = download_herbie_variable(FH, "ssrd", "ssrd", point_df)
|
|
190
|
+
df_ssrd["ssrd_kwm2"] = df_ssrd["ssrd"].diff() / df_ssrd["datetime"].diff().dt.total_seconds() / 1000
|
|
191
|
+
df_ssrd["ssrd_corrected"] = (1.0530 * df_ssrd["ssrd_kwm2"] - 0.0347).clip(lower=0)
|
|
192
|
+
df_ssrd = df_ssrd[["datetime", "ssrd_corrected"]].rename(columns={"datetime": "date", "ssrd_corrected": station})
|
|
193
|
+
ssrd_dfs.append(df_ssrd)
|
|
194
|
+
|
|
195
|
+
# Merge rainfall
|
|
196
|
+
rainfall_df = pd.concat(rainfall_dfs, axis=0).groupby("date").first().reset_index()
|
|
197
|
+
rainfall_df["average_rainfall"] = rainfall_df[POINTS["station"]].mean(axis=1)
|
|
198
|
+
rainfall_df.to_csv(os.path.join(output_dir, "LAKE_RAINFALL_DATA_FORECAST.csv"), index=False)
|
|
199
|
+
|
|
200
|
+
# Merge ET
|
|
201
|
+
et_df_all = pd.concat(et_dfs, axis=0).groupby("date").first().reset_index()
|
|
202
|
+
et_df_all["average_ETPI"] = et_df_all[POINTS["station"]].mean(axis=1)
|
|
203
|
+
et_df_all.to_csv(os.path.join(output_dir, "LOONE_AVERAGE_ETPI_DATA_FORECAST.csv"), index=False)
|
|
204
|
+
|
|
205
|
+
# Combine all SSRD DataFrames
|
|
206
|
+
ssrd_df_all = pd.concat(ssrd_dfs, axis=0)
|
|
207
|
+
ssrd_df_all["date"] = pd.to_datetime(ssrd_df_all["date"])
|
|
208
|
+
|
|
209
|
+
# Compute the daily mean for each station
|
|
210
|
+
daily_ssrd = (
|
|
211
|
+
ssrd_df_all.groupby(ssrd_df_all["date"].dt.date)[POINTS["station"]]
|
|
212
|
+
.mean()
|
|
213
|
+
.reset_index()
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
daily_ssrd = daily_ssrd.rename(columns={"date": "date"})
|
|
217
|
+
daily_ssrd["Mean_RADT"] = daily_ssrd[POINTS["station"]].mean(axis=1)
|
|
218
|
+
daily_ssrd.to_csv(os.path.join(output_dir, "LO_RADT_data_forecast.csv"), index=False)
|
|
219
|
+
|
|
220
|
+
print("All outputs generated successfully.")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from retry import retry
|
|
2
|
+
from herbie import FastHerbie
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class NoGribFilesFoundError(Exception):
|
|
6
|
+
"""Raised when no GRIB files are found for the specified date/model run."""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@retry(NoGribFilesFoundError, tries=5, delay=15, max_delay=60, backoff=2)
|
|
11
|
+
def get_fast_herbie_object(date: str) -> FastHerbie:
|
|
12
|
+
"""
|
|
13
|
+
Get a FastHerbie object for the specified date. Raises an exception when no GRIB files are found.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
date: pandas-parsable datetime string
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
A FastHerbie object configured for the specified date.
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
NoGribFilesFoundError: If no GRIB files are found for the specified date.
|
|
23
|
+
"""
|
|
24
|
+
fast_herbie = FastHerbie([date], model="ifs", fxx=range(0, 360, 3))
|
|
25
|
+
|
|
26
|
+
if len(fast_herbie.file_exists) == 0:
|
|
27
|
+
raise NoGribFilesFoundError(f"No GRIB files found for the specified date {date}.")
|
|
28
|
+
|
|
29
|
+
return fast_herbie
|
|
@@ -996,14 +996,31 @@ def get_synthetic_data(date_start: str, df: pd.DataFrame):
|
|
|
996
996
|
end_month_day = date_end.strftime('%m-%d')
|
|
997
997
|
|
|
998
998
|
# Filter the DataFrame to include only rows between date_start and date_end for all previous years
|
|
999
|
-
|
|
999
|
+
# (handle year wrap, e.g., Dec -> Jan)
|
|
1000
|
+
wraps_year = start_month_day > end_month_day
|
|
1001
|
+
|
|
1002
|
+
if wraps_year:
|
|
1003
|
+
mask = (
|
|
1004
|
+
(df['month_day'] >= start_month_day) |
|
|
1005
|
+
(df['month_day'] <= end_month_day)
|
|
1006
|
+
)
|
|
1007
|
+
else:
|
|
1008
|
+
mask = (
|
|
1009
|
+
(df['month_day'] >= start_month_day) &
|
|
1010
|
+
(df['month_day'] <= end_month_day)
|
|
1011
|
+
)
|
|
1012
|
+
|
|
1000
1013
|
filtered_data = df.loc[mask]
|
|
1001
1014
|
|
|
1002
1015
|
# Group by the month and day, then calculate the average for each group
|
|
1003
1016
|
average_values = filtered_data.groupby('month_day')['Data'].mean()
|
|
1004
1017
|
# Interpolate in case there are missing values:
|
|
1005
1018
|
start_date = pd.to_datetime('2001-' + start_month_day)
|
|
1006
|
-
|
|
1019
|
+
|
|
1020
|
+
if wraps_year:
|
|
1021
|
+
end_date = pd.to_datetime('2002-' + end_month_day)
|
|
1022
|
+
else:
|
|
1023
|
+
end_date = pd.to_datetime('2001-' + end_month_day)
|
|
1007
1024
|
|
|
1008
1025
|
full_dates = pd.date_range(start=start_date, end=end_date)
|
|
1009
1026
|
full_index = full_dates.strftime('%m-%d')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: loone_data_prep
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Prepare data to run the LOONE model.
|
|
5
5
|
Author-email: Osama Tarabih <osamatarabih@usf.edu>
|
|
6
6
|
Maintainer-email: Michael Souffront <msouffront@aquaveo.com>, James Dolinar <jdolinar@aquaveo.com>
|
|
@@ -5,6 +5,7 @@ loone_data_prep/GEOGLOWS_LOONE_DATA_PREP.py
|
|
|
5
5
|
loone_data_prep/LOONE_DATA_PREP.py
|
|
6
6
|
loone_data_prep/__init__.py
|
|
7
7
|
loone_data_prep/data_analyses_fns.py
|
|
8
|
+
loone_data_prep/herbie_utils.py
|
|
8
9
|
loone_data_prep/utils.py
|
|
9
10
|
loone_data_prep.egg-info/PKG-INFO
|
|
10
11
|
loone_data_prep.egg-info/SOURCES.txt
|
|
@@ -19,15 +20,14 @@ loone_data_prep/flow_data/get_inflows.py
|
|
|
19
20
|
loone_data_prep/flow_data/get_outflows.py
|
|
20
21
|
loone_data_prep/flow_data/hydro.py
|
|
21
22
|
loone_data_prep/forecast_scripts/Chla_merged.py
|
|
22
|
-
loone_data_prep/forecast_scripts/create_forecast_LOWs.py
|
|
23
23
|
loone_data_prep/forecast_scripts/forecast_stages.py
|
|
24
24
|
loone_data_prep/forecast_scripts/get_Chla_predicted.py
|
|
25
25
|
loone_data_prep/forecast_scripts/get_NO_Loads_predicted.py
|
|
26
26
|
loone_data_prep/forecast_scripts/loone_q_predict.py
|
|
27
27
|
loone_data_prep/forecast_scripts/loone_wq_predict.py
|
|
28
|
+
loone_data_prep/forecast_scripts/new_combined_weather_forecast.py
|
|
28
29
|
loone_data_prep/forecast_scripts/predict_PI.py
|
|
29
30
|
loone_data_prep/forecast_scripts/trib_cond.py
|
|
30
|
-
loone_data_prep/forecast_scripts/weather_forecast.py
|
|
31
31
|
loone_data_prep/water_level_data/__init__.py
|
|
32
32
|
loone_data_prep/water_level_data/get_all.py
|
|
33
33
|
loone_data_prep/water_level_data/hydro.py
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from herbie import FastHerbie
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
import pandas as pd
|
|
5
|
-
from retry_requests import retry
|
|
6
|
-
import warnings
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def generate_wind_forecasts(output_dir):
|
|
10
|
-
# Ensure output directory exists
|
|
11
|
-
warnings.filterwarnings("ignore", message="Will not remove GRIB file because it previously existed.")
|
|
12
|
-
os.makedirs(output_dir, exist_ok=True)
|
|
13
|
-
|
|
14
|
-
# Define points of interest
|
|
15
|
-
points = pd.DataFrame({
|
|
16
|
-
"longitude": [-80.7934, -80.9724, -80.7828, -80.7890],
|
|
17
|
-
"latitude": [27.1389, 26.9567, 26.8226, 26.9018]
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
# Station-specific file and column names
|
|
21
|
-
file_map = {
|
|
22
|
-
"Point_1": ("L001_WNDS_MPH_predicted.csv", "L001_WNDS_MPH"),
|
|
23
|
-
"Point_2": ("L005_WNDS_MPH_predicted.csv", "L005_WNDS_MPH"),
|
|
24
|
-
"Point_3": ("L006_WNDS_MPH_predicted.csv", "L006_WNDS_MPH"),
|
|
25
|
-
"Point_4": ("LZ40_WNDS_MPH_predicted.csv", "LZ40_WNDS_MPH")
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
today_str = datetime.today().strftime('%Y-%m-%d 00:00')
|
|
29
|
-
FH = FastHerbie([today_str], model="ifs", fxx=range(0, 360, 3))
|
|
30
|
-
dfs = []
|
|
31
|
-
|
|
32
|
-
variables = {
|
|
33
|
-
"10u": "10u",
|
|
34
|
-
"10v": "10v",
|
|
35
|
-
"2t": "2t",
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
# Loop through points and extract data
|
|
40
|
-
for index, point in points.iterrows():
|
|
41
|
-
print(f"\nProcessing Point {index + 1}: ({point.latitude}, {point.longitude})")
|
|
42
|
-
|
|
43
|
-
point_df = pd.DataFrame({
|
|
44
|
-
"longitude": [point.longitude],
|
|
45
|
-
"latitude": [point.latitude]
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
for var_key, var_name in variables.items():
|
|
49
|
-
print(f" Variable: {var_key}")
|
|
50
|
-
|
|
51
|
-
# Download and load dataset
|
|
52
|
-
FH.download(f":{var_key}")
|
|
53
|
-
ds = FH.xarray(f":{var_key}", backend_kwargs={"decode_timedelta": True})
|
|
54
|
-
|
|
55
|
-
# Extract point data
|
|
56
|
-
dsi = ds.herbie.pick_points(point_df, method="nearest")
|
|
57
|
-
|
|
58
|
-
# Get actual variable name
|
|
59
|
-
if var_name == "10u":
|
|
60
|
-
var_name_actual = "u10" # Map 10u to u10
|
|
61
|
-
elif var_name == "10v":
|
|
62
|
-
var_name_actual = "v10" # Map 10v to v10
|
|
63
|
-
elif var_name == "2t":
|
|
64
|
-
var_name_actual = "t2m" #TODO: check that this is correct
|
|
65
|
-
|
|
66
|
-
# Convert to DataFrame
|
|
67
|
-
time_series = dsi[var_name_actual].squeeze()
|
|
68
|
-
df = time_series.to_dataframe().reset_index()
|
|
69
|
-
|
|
70
|
-
# Handle datetime columns
|
|
71
|
-
if "valid_time" in df.columns:
|
|
72
|
-
df = df.rename(columns={"valid_time": "datetime"})
|
|
73
|
-
elif "step" in df.columns and "time" in dsi.coords:
|
|
74
|
-
df["datetime"] = dsi.time.values[0] + df["step"]
|
|
75
|
-
|
|
76
|
-
# Retain necessary columns
|
|
77
|
-
df = df[["datetime", var_name_actual]].drop_duplicates()
|
|
78
|
-
dfs.append((index, var_name_actual, df))
|
|
79
|
-
|
|
80
|
-
# Merge and process data per point
|
|
81
|
-
results = {}
|
|
82
|
-
for point_index in range(len(points)):
|
|
83
|
-
u_df = [df for idx, name, df in dfs if idx == point_index and name == "u10"][0]
|
|
84
|
-
v_df = [df for idx, name, df in dfs if idx == point_index and name == "v10"][0]
|
|
85
|
-
merged = u_df.merge(v_df, on="datetime", how="outer")
|
|
86
|
-
|
|
87
|
-
# Compute wind speed and correction
|
|
88
|
-
merged["wind_speed"] = (merged["u10"] ** 2 + merged["v10"] ** 2) ** 0.5
|
|
89
|
-
merged["wind_speed_corrected"] = 0.4167 * merged["wind_speed"] + 4.1868
|
|
90
|
-
merged["wind_speed_corrected"] = merged["wind_speed_corrected"] * 2.23694 # m/s to mph
|
|
91
|
-
|
|
92
|
-
results[f"Point_{point_index + 1}"] = merged
|
|
93
|
-
|
|
94
|
-
# Save outputs with station-specific column names
|
|
95
|
-
for key, (filename, new_col_name) in file_map.items():
|
|
96
|
-
df = results[key].copy()
|
|
97
|
-
df = df[["datetime", "wind_speed_corrected"]].rename(columns={
|
|
98
|
-
"wind_speed_corrected": new_col_name,
|
|
99
|
-
"datetime": "date"
|
|
100
|
-
})
|
|
101
|
-
filepath = os.path.join(output_dir, filename)
|
|
102
|
-
df.to_csv(filepath, index=False)
|
|
103
|
-
# Save 2-meter air temperature data
|
|
104
|
-
airt_file_map = {
|
|
105
|
-
"Point_1": "L001_AIRT_Degrees Celsius_forecast.csv",
|
|
106
|
-
"Point_2": "L005_AIRT_Degrees Celsius_forecast.csv",
|
|
107
|
-
"Point_3": "L006_AIRT_Degrees Celsius_forecast.csv",
|
|
108
|
-
"Point_4": "LZ40_AIRT_Degrees Celsius_forecast.csv"
|
|
109
|
-
}
|
|
110
|
-
airt_column_map = {
|
|
111
|
-
"Point_1": "L001_AIRT_Degrees Celsius",
|
|
112
|
-
"Point_2": "L005_AIRT_Degrees Celsius",
|
|
113
|
-
"Point_3": "L006_AIRT_Degrees Celsius",
|
|
114
|
-
"Point_4": "LZ40_AIRT_Degrees Celsius"
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
for key in airt_file_map:
|
|
118
|
-
point_index = int(key.split("_")[1]) - 1
|
|
119
|
-
df_airt = [df for idx, name, df in dfs if idx == point_index and name == "t2m"][0].copy()
|
|
120
|
-
df_airt["t2m"] = df_airt["t2m"] - 273.15 # Convert from Kelvin to Celsius
|
|
121
|
-
df_airt = df_airt.rename(columns={
|
|
122
|
-
"datetime": "date",
|
|
123
|
-
"t2m": airt_column_map[key]
|
|
124
|
-
})
|
|
125
|
-
filepath = os.path.join(output_dir, airt_file_map[key])
|
|
126
|
-
df_airt.to_csv(filepath, index=False)
|
|
127
|
-
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
from herbie import FastHerbie
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
import pandas as pd
|
|
4
|
-
import openmeteo_requests
|
|
5
|
-
import argparse
|
|
6
|
-
import requests_cache
|
|
7
|
-
from retry_requests import retry
|
|
8
|
-
import warnings
|
|
9
|
-
|
|
10
|
-
warnings.filterwarnings("ignore", message="Will not remove GRIB file because it previously existed.")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def download_weather_forecast (file_path):
|
|
14
|
-
# Get today's date in the required format
|
|
15
|
-
today_str = datetime.today().strftime('%Y-%m-%d 00:00')
|
|
16
|
-
|
|
17
|
-
# Define variables to download and extract
|
|
18
|
-
variables = {
|
|
19
|
-
"10u": "10u",
|
|
20
|
-
"ssrd": "ssrd",
|
|
21
|
-
"tp": "tp",
|
|
22
|
-
"10v": "10v",
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
# Define point of interest
|
|
26
|
-
points = pd.DataFrame({"longitude": [-80.7976], "latitude": [26.9690]})
|
|
27
|
-
|
|
28
|
-
# Initialize FastHerbie
|
|
29
|
-
FH = FastHerbie([today_str], model="ifs", fxx=range(0, 360, 3))
|
|
30
|
-
dfs = []
|
|
31
|
-
|
|
32
|
-
for var_key, var_name in variables.items():
|
|
33
|
-
print(f"Processing {var_key}...")
|
|
34
|
-
|
|
35
|
-
# Download and load the dataset
|
|
36
|
-
FH.download(f":{var_key}")
|
|
37
|
-
ds = FH.xarray(f":{var_key}", backend_kwargs={"decode_timedelta": True})
|
|
38
|
-
|
|
39
|
-
# Extract point data
|
|
40
|
-
dsi = ds.herbie.pick_points(points, method="nearest")
|
|
41
|
-
|
|
42
|
-
# Extract the correct variable name dynamically
|
|
43
|
-
if var_name == "10u":
|
|
44
|
-
var_name_actual = "u10" # Map 10u to u10
|
|
45
|
-
elif var_name == "10v":
|
|
46
|
-
var_name_actual = "v10" # Map 10v to v10
|
|
47
|
-
else:
|
|
48
|
-
var_name_actual = var_name # For ssrd and tp, use the same name
|
|
49
|
-
|
|
50
|
-
# Extract time series
|
|
51
|
-
time_series = dsi[var_name_actual].squeeze()
|
|
52
|
-
|
|
53
|
-
# Convert to DataFrame
|
|
54
|
-
df = time_series.to_dataframe().reset_index()
|
|
55
|
-
|
|
56
|
-
# Convert `valid_time` to datetime
|
|
57
|
-
if "valid_time" in df.columns:
|
|
58
|
-
df = df.rename(columns={"valid_time": "datetime"})
|
|
59
|
-
elif "step" in df.columns and "time" in dsi.coords:
|
|
60
|
-
df["datetime"] = dsi.time.values[0] + df["step"]
|
|
61
|
-
|
|
62
|
-
# Keep only datetime and variable of interest
|
|
63
|
-
df = df[["datetime", var_name_actual]].drop_duplicates()
|
|
64
|
-
|
|
65
|
-
# Append to list
|
|
66
|
-
dfs.append(df)
|
|
67
|
-
|
|
68
|
-
# Print extracted data
|
|
69
|
-
# print(df)
|
|
70
|
-
|
|
71
|
-
# Merge all variables into a single DataFrame
|
|
72
|
-
final_df = dfs[0]
|
|
73
|
-
for df in dfs[1:]:
|
|
74
|
-
final_df = final_df.merge(df, on="datetime", how="outer")
|
|
75
|
-
print(final_df)
|
|
76
|
-
# Calculate wind speed
|
|
77
|
-
final_df["wind_speed"] = (final_df["u10"] ** 2 + final_df["v10"] ** 2) ** 0.5
|
|
78
|
-
|
|
79
|
-
#rainfall corrected: OLS Regression Equation: Corrected Forecast = 0.7247 * Forecast + 0.1853
|
|
80
|
-
final_df["tp_corrected"] = 0.7247 * final_df["tp"] + 0.1853
|
|
81
|
-
|
|
82
|
-
#wind speed correction: Corrected Forecast = 0.4167 * Forecast + 4.1868
|
|
83
|
-
final_df["wind_speed_corrected"] = 0.4167 * final_df["wind_speed"] + 4.1868
|
|
84
|
-
|
|
85
|
-
#radiation correction will need to be fixed because it was done on fdir instead of ssdr
|
|
86
|
-
#radiation corrected: Corrected Forecast = 0.0553 * Forecast - 0.0081
|
|
87
|
-
final_df["ssrd_corrected"] = 0.0553 * final_df["ssrd"] - 0.0081
|
|
88
|
-
|
|
89
|
-
# Setup the Open-Meteo API client with cache and retry on error
|
|
90
|
-
cache_session = requests_cache.CachedSession('.cache', expire_after = 3600)
|
|
91
|
-
retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2)
|
|
92
|
-
openmeteo = openmeteo_requests.Client(session = retry_session)
|
|
93
|
-
|
|
94
|
-
# Make sure all required weather variables are listed here
|
|
95
|
-
# The order of variables in hourly or daily is important to assign them correctly below
|
|
96
|
-
url = "https://api.open-meteo.com/v1/forecast"
|
|
97
|
-
params = {
|
|
98
|
-
"latitude": 26.9690,
|
|
99
|
-
"longitude": -80.7976,
|
|
100
|
-
"hourly": "evapotranspiration",
|
|
101
|
-
"forecast_days": 16,
|
|
102
|
-
"models": "gfs_seamless"
|
|
103
|
-
}
|
|
104
|
-
responses = openmeteo.weather_api(url, params=params)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
# Process first location. Add a for-loop for multiple locations or weather models
|
|
108
|
-
response = responses[0]
|
|
109
|
-
|
|
110
|
-
hourly = response.Hourly()
|
|
111
|
-
hourly_evapotranspiration = hourly.Variables(0).ValuesAsNumpy()
|
|
112
|
-
|
|
113
|
-
hourly_data = {"date": pd.date_range(
|
|
114
|
-
start = pd.to_datetime(hourly.Time(), unit = "s", utc = True),
|
|
115
|
-
end = pd.to_datetime(hourly.TimeEnd(), unit = "s", utc = True),
|
|
116
|
-
freq = pd.Timedelta(seconds = hourly.Interval()),
|
|
117
|
-
inclusive = "left"
|
|
118
|
-
)}
|
|
119
|
-
|
|
120
|
-
hourly_data["evapotranspiration"] = hourly_evapotranspiration
|
|
121
|
-
|
|
122
|
-
hourly_dataframe = pd.DataFrame(data = hourly_data)
|
|
123
|
-
|
|
124
|
-
# Convert datetime to date for merging
|
|
125
|
-
final_df['date'] = final_df['datetime']
|
|
126
|
-
# Ensure final_df['date'] is timezone-aware (convert to UTC)
|
|
127
|
-
final_df['date'] = pd.to_datetime(final_df['date'], utc=True)
|
|
128
|
-
|
|
129
|
-
# Ensure hourly_dataframe['date'] is also timezone-aware (convert to UTC)
|
|
130
|
-
hourly_dataframe['date'] = pd.to_datetime(hourly_dataframe['date'], utc=True)
|
|
131
|
-
|
|
132
|
-
# Merge while keeping only matching dates from final_df
|
|
133
|
-
merged_df = final_df.merge(hourly_dataframe, on='date', how='left')
|
|
134
|
-
|
|
135
|
-
# Print final combined DataFrame
|
|
136
|
-
merged_df.drop(columns=['date'], inplace=True)
|
|
137
|
-
# print(merged_df)
|
|
138
|
-
|
|
139
|
-
merged_df.to_csv(file_path, index=False)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def main():
|
|
143
|
-
# Set up command-line argument parsing
|
|
144
|
-
parser = argparse.ArgumentParser(description="Download and process weather forecast data.")
|
|
145
|
-
parser.add_argument("file_path", help="Path to save the resulting CSV file.")
|
|
146
|
-
|
|
147
|
-
# Parse the arguments
|
|
148
|
-
args = parser.parse_args()
|
|
149
|
-
|
|
150
|
-
# Call the function with the provided file path
|
|
151
|
-
download_weather_forecast(args.file_path)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if __name__ == "__main__":
|
|
155
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/flow_data/get_forecast_flows.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/Chla_merged.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/forecast_stages.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/loone_q_predict.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/loone_wq_predict.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/predict_PI.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/forecast_scripts/trib_cond.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_level_data/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_quality_data/__init__.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_quality_data/get_inflows.py
RENAMED
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep/water_quality_data/get_lake_wq.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{loone_data_prep-1.2.3 → loone_data_prep-1.3.0}/loone_data_prep.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|