From bce1b507c47b58ddfb91dc0cd399a0efc4af8c64 Mon Sep 17 00:00:00 2001
From: akarich73 <61820266+akarich73@users.noreply.github.com>
Date: Sat, 19 Oct 2024 13:15:00 +1100
Subject: [PATCH] Initial commit
---
.idea/barra2-dl.iml | 3 +-
.idea/misc.xml | 2 +-
barra2_dl/__init__.py | 2 +-
barra2_dl/{downloaders.py => downloader.py} | 12 +-
barra2_dl/globals.py | 9 +-
barra2_dl/helpers.py | 273 +++-----------------
barra2_dl/helpers_geo.py | 108 ++++++++
barra2_dl/helpers_wind.py | 84 ++++++
barra2_dl/merger.py | 135 ++++++++++
poetry.lock | 202 ++++-----------
pyproject.toml | 3 +-
scripts/barra2_downloader_example.py | 4 +-
tests/test_downloader.py | 2 +-
tests/test_example/test_some_function.py | 1 -
tests/test_helpers_wind.py | 16 ++
15 files changed, 466 insertions(+), 390 deletions(-)
rename barra2_dl/{downloaders.py => downloader.py} (90%)
create mode 100644 barra2_dl/helpers_geo.py
create mode 100644 barra2_dl/helpers_wind.py
create mode 100644 barra2_dl/merger.py
create mode 100644 tests/test_helpers_wind.py
diff --git a/.idea/barra2-dl.iml b/.idea/barra2-dl.iml
index be9e8b5..462e8c5 100644
--- a/.idea/barra2-dl.iml
+++ b/.idea/barra2-dl.iml
@@ -9,8 +9,9 @@
+
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 3fc1e0f..434a144 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/barra2_dl/__init__.py b/barra2_dl/__init__.py
index f1c931d..01f66fa 100644
--- a/barra2_dl/__init__.py
+++ b/barra2_dl/__init__.py
@@ -1 +1 @@
-from . import globals, helpers, downloaders
+from . import globals, downloader, merger, helpers
diff --git a/barra2_dl/downloaders.py b/barra2_dl/downloader.py
similarity index 90%
rename from barra2_dl/downloaders.py
rename to barra2_dl/downloader.py
index 6e348c7..491ddbd 100644
--- a/barra2_dl/downloaders.py
+++ b/barra2_dl/downloader.py
@@ -6,6 +6,7 @@
from pathlib import Path
import calendar
from .helpers import list_months
+from .helpers_geo import format_lat_lon
from .globals import LatLonPoint, LatLonBBox, barra2_aus11_index
@@ -52,7 +53,7 @@ def barra2_point_downloader(base_url: str,
lat_lon_point: LatLonPoint,
start_datetime: str | datetime,
end_datetime: str | datetime,
- fileout_prefix: str,
+ fileout_prefix: str = None,
fileout_folder: str = 'cache',
fileout_type: str = 'csv_file') -> None:
"""Download barra2 data based on the url and variables list
@@ -76,10 +77,11 @@ def barra2_point_downloader(base_url: str,
Change from using os to pathlib
"""
+ # set default fileout_prefix if not set by user
# loop through each variable requested for download as each variable is saved in a separate url
for var in barra2_var:
- # loop through each month as each BARRA2 file is saved by month
+ # loop through each month as each BARRA2 file is saved by month todo check index enumerate addition works
for date in list_months(start_datetime, end_datetime, freq="MS"):
year = date.year
month = date.month
@@ -97,8 +99,12 @@ def barra2_point_downloader(base_url: str,
folder_path = fileout_folder
download_file(url, folder_path, fileout_name, create_folder=True)
- return
+ # todo add option to name file_prefix using BARRA2 node; might need index 0 check
+ # if fileout_prefix is None:
+ # fileout_prefix = BARRA2_aus11_index[lat_lon_point['lat']][lat_lon_point['lon']]
+
+ return
diff --git a/barra2_dl/globals.py b/barra2_dl/globals.py
index bdb7f69..fdad84e 100644
--- a/barra2_dl/globals.py
+++ b/barra2_dl/globals.py
@@ -40,8 +40,11 @@ class LatLonBBox(TypedDict):
# VARIABLES
# -----------------------------------------------------------------------------
-# barra2_aus11_extents
-barra2_aus11_lat_lon_bbox = LatLonBBox(north=-23.0, west=133.0, east=134.0, south=-24)
+# barra2_aus11_extents http://www.bom.gov.au/research/publications/researchreports/BRR-067.pdf
+# todo consider updating Barra2 to Barra-r2 to match published data convention
+barra_r2_aus11_lat_lon_bbox = LatLonBBox(north=12.95, south=-57.97, east=207.39, west=88.48)
+
+barra_r2_grid_spacing = 0.11
# base thredds url for BARRA2 11km 1hour reanalysis data
barra2_aus11_csv_url = ("https://thredds.nci.org.au/thredds/ncss/grid/ob53/output/reanalysis/AUS-11/BOM/ERA5"
@@ -49,7 +52,7 @@ class LatLonBBox(TypedDict):
"{var}_AUS-11_ERA5_historical_hres_BOM_BARRA-R2_v1_1hr_{year}{month:02d}-{year}{month:02d}.nc")
# index for barra2 used to join separate files
-barra2_aus11_index = ['time', 'station', 'latitude[unit="degrees_north"]', 'longitude[unit="degrees_east"]']
+barra2_aus11_index = ['time','station', 'latitude[unit="degrees_north"]', 'longitude[unit="degrees_east"]']
# BARRA2 wind speed variable pairs
barra2_aus11_wind_all = [('ua10m', 'va10m', '10m[unit="m s-1"]'),
diff --git a/barra2_dl/helpers.py b/barra2_dl/helpers.py
index c302909..56f9c25 100644
--- a/barra2_dl/helpers.py
+++ b/barra2_dl/helpers.py
@@ -1,11 +1,9 @@
"""
-This module contains helper functions.
+General helper functions.
"""
from pathlib import Path
import pandas as pd
-import numpy as np
-import fnmatch
from typing import List, Union
@@ -25,118 +23,6 @@ def list_months(start_datetime: str, end_datetime: str, freq: str ='MS', **kwarg
return df_to_list
-def list_csv_files(folder_path):
- """
- List all CSV files in the given folder.
-
- Args:
- folder_path (str): The path to the folder containing the CSV files.
-
- Returns:
- list: A list of CSV file names in the folder.
- """
- folder = Path(folder_path)
- csv_files = [file.name for file in folder.glob('*.csv')]
- return csv_files
-
-
-def filter_list_using_wildcard(input_list: list[str], pattern:str):
- """
- Filter a list using a wildcard pattern.
-
- Args:
- input_list (list[str]): The list of strings to be filtered.
- pattern (str): The wildcard pattern to filter the list.
-
- Returns:
- list: A list of strings that match the wildcard pattern.
- """
- filtered_list = fnmatch.filter(input_list, pattern)
- return filtered_list
-
-
-def merge_csv_files_to_dataframe(filein_folder: str,
- filename_pattern: str = '*.csv',
- index_for_join: str = None) -> pd.DataFrame:
- """
- Merge csv files from a folder based on optional filename wildcard using fnmatch.
- If filename wildcard is omitted all csv files in the folder will be merged.
- If fileout_folder is omitted the merged file will be saved in the filein_folder.
-
- Args:
- filein_folder (str): Optional
- filename_pattern (str):
- index_for_join (str):
-
- Returns:
- return_type: None.
-
- Todo:
- Change from using os to pathlib
- """
-
- # todo add .csv check for filename_prefix
-
-
- # list all csv files in folder
- csv_files = list_csv_files(filein_folder)
-
- # filter csv files
- csv_files_filtered = filter_list_using_wildcard(csv_files, filename_pattern)
-
- # initiate dataframe for combined csv results
- df_combined = pd.DataFrame()
-
- for file in Path(filein_folder).glob(filename_pattern):
- if df_combined.empty:
- # read csv file without indexing to retain time as column for join
- df_combined = pd.read_csv(file)
- else:
- # read next file into new df
- df_add = pd.read_csv(file)
- # combine on index join if not None, otherwise just concat together
- if index_for_join is not None:
- df_combined = df_combined.join(df_add.set_index(index_for_join),on=index_for_join)
- else:
- df_combined = pd.concat([df_combined, df_add], ignore_index = True)
-
- return df_combined
-
-
-def export_dataframe_to_csv(dataframe: pd.DataFrame,
- fileout_folder: str | Path,
- fileout_name: str,
- create_folder: bool = True) -> None:
- """
- Export a DataFrame to a CSV file in the specified folder with the given file name.
-
- Args:
- dataframe (pd.DataFrame): The Pandas DataFrame to export.
- fileout_folder (str or Path): The path to the folder where the CSV file will be saved.
- fileout_name (str): The name of the CSV file to save.
- create_folder (bool): If True, creates the folder if it does not exist; otherwise, exits if the folder doesn't exist.
-
- Returns:
- Path: The path of the saved CSV file.
- """
- fileout_folder = Path(fileout_folder)
- # Check if the folder exists
- if not fileout_folder.exists():
- if create_folder:
- fileout_folder.mkdir(parents=True)
- print(f"The folder '{fileout_folder}' was created.")
- else:
- print(f"The folder '{fileout_folder}' does not exist. Exiting...")
- return
-
- # Define the full path for the CSV file
- fileout_path_name = fileout_folder / fileout_name
-
- # Export the DataFrame to CSV
- dataframe.to_csv(fileout_path_name, index=False)
-
- return fileout_path_name
-
def get_timestamp_range_list(dataframe: pd.DataFrame, timestamp_column: str) -> List[pd.Timestamp]:
"""
@@ -193,121 +79,48 @@ def combine_csv_files(file_paths: list[str | Path], output_file: str | Path, ind
return
-# todo draft function to process csvs
-def process_csvs:
- # process barra2 variables to wind speed and direction todo split into modules
-
- # initiate DataFrame for adding new columns
- df_processed = df_combined
-
- # loop through df_combined to df_processed
- for tup in barra2_wind_speeds:
- mask_wind_speed_h = tup[0][2:]
- mask_ua = df_combined.columns.str.contains(tup[0]) # selects column header
- mask_va = df_combined.columns.str.contains(tup[1]) # selects column header
-
- if np.any(mask_ua == True) and np.any(mask_va == True):
- df_processed_ua = df_combined.loc[:, mask_ua] # selects mask
- df_processed_va = df_combined.loc[:, mask_va] # selects mask
-
- print('Converted: ' + tup.__str__())
-
- df_processed_v = pd.DataFrame(np.sqrt(df_processed_ua.iloc[:, 0] ** 2 + df_processed_va.iloc[:, 0] ** 2))
- df_processed_v.columns = ['v' + mask_wind_speed_h + '[unit="m s-1"]']
-
- df_processed_phi_met = pd.DataFrame()
-
- for index, row in df_combined.iterrows():
- if (df_processed_ua.iloc[index, 0] == 0) and (df_processed_va.iloc[index, 0] == 0):
- df_processed_phi_met.loc[index, 'v' + mask_wind_speed_h + '_' + 'phi_met[unit="degrees"]'] = 0.0
- else:
- df_processed_phi_met.loc[index, 'v' + mask_wind_speed_h + '_' + 'phi_met[unit="degrees"]'] = (
- np.mod(180 + np.rad2deg(
- np.arctan2(df_processed_ua.iloc[index, 0], df_processed_va.iloc[index, 0])), 360))
-
- # Merge the current variable DataFrame with the combined DataFrame
- df_processed = df_processed.join(df_processed_v)
- df_processed = df_processed.join(df_processed_phi_met)
-
- # export combined to csv
- df_processed.to_csv(
- os.path.join(output_dir,
- f"{output_filename_prefix}_processed_{start_date_time.strftime("%Y%m%d")}_{end_date_time.strftime("%Y%m%d")}.csv"))
-
- return
-
-
-# todo add tests
-def calculate_wind_speed(u: Union[float, int], v: Union[float, int]) -> float:
- """
- Args:
- u: The u component of the wind vector, which can be a float or an int.
- v: The v component of the wind vector, which can be a float or an int.
- Returns:
- Wind speed. If both u and v are zero, it returns 0.0.
- """
- if u == 0 and v == 0:
- return 0.0
- return np.sqrt(u ** 2 + v ** 2)
-
-def wind_components_to_speed(ua: Union[float, int, List[float], List[int]], va: Union[float, int, List[float], List[int]]) -> Union[float, List[float]]:
- """
- Convert wind components ua and va to wind speed v.
- Args:
- ua (Union[float, int, List[float], List[int]]): The u-component of the wind.
- va (Union[float, int, List[float], List[int]]): The v-component of the wind.
- Returns:
- float or List[float]: The calculated wind speed.
- Raises:
- ValueError: If the input types do not match or if they are neither List[float] nor float.
- """
- if isinstance(ua, (float, int)) and isinstance(va, (float, int)):
- if ua == 0 and va == 0:
- return 0.0
- return calculate_wind_speed(ua, va)
- elif isinstance(ua, list) and isinstance(va, list):
- if not all(isinstance(num, (float, int)) for num in ua + va):
- raise ValueError("All elements in both lists must be either float or int.")
- if len(ua) != len(va):
- raise ValueError("Both lists must be of the same length.")
- return [calculate_wind_speed(u, v) for u, v in zip(ua, va)]
- else:
- raise ValueError("Both arguments must be either both float/int or both lists of float/int.")
-
+# # todo draft function to process csvs
+# def process_csvs:
+# # process barra2 variables to wind speed and direction todo split into modules
+#
+# # initiate DataFrame for adding new columns
+# df_processed = df_combined
+#
+# # loop through df_combined to df_processed
+# for tup in barra2_wind_speeds:
+# mask_wind_speed_h = tup[0][2:]
+# mask_ua = df_combined.columns.str.contains(tup[0]) # selects column header
+# mask_va = df_combined.columns.str.contains(tup[1]) # selects column header
+#
+# if np.any(mask_ua == True) and np.any(mask_va == True):
+# df_processed_ua = df_combined.loc[:, mask_ua] # selects mask
+# df_processed_va = df_combined.loc[:, mask_va] # selects mask
+#
+# print('Converted: ' + tup.__str__())
+#
+# df_processed_v = pd.DataFrame(np.sqrt(df_processed_ua.iloc[:, 0] ** 2 + df_processed_va.iloc[:, 0] ** 2))
+# df_processed_v.columns = ['v' + mask_wind_speed_h + '[unit="m s-1"]']
+#
+# df_processed_phi_met = pd.DataFrame()
+#
+# for index, row in df_combined.iterrows():
+# if (df_processed_ua.iloc[index, 0] == 0) and (df_processed_va.iloc[index, 0] == 0):
+# df_processed_phi_met.loc[index, 'v' + mask_wind_speed_h + '_' + 'phi_met[unit="degrees"]'] = 0.0
+# else:
+# df_processed_phi_met.loc[index, 'v' + mask_wind_speed_h + '_' + 'phi_met[unit="degrees"]'] = (
+# np.mod(180 + np.rad2deg(
+# np.arctan2(df_processed_ua.iloc[index, 0], df_processed_va.iloc[index, 0])), 360))
+#
+# # Merge the current variable DataFrame with the combined DataFrame
+# df_processed = df_processed.join(df_processed_v)
+# df_processed = df_processed.join(df_processed_phi_met)
+#
+# # export combined to csv
+# df_processed.to_csv(
+# os.path.join(output_dir,
+# f"{output_filename_prefix}_processed_{start_date_time.strftime("%Y%m%d")}_{end_date_time.strftime("%Y%m%d")}.csv"))
+#
+# return
-# todo add tests
-def calculate_wind_direction(u: Union[float, int], v: Union[float, int]) -> float:
- """
- Args:
- u: The u component of the wind vector, which can be a float or an int.
- v: The v component of the wind vector, which can be a float or an int.
- Returns:
- Wind direction in degrees. If both u and v are zero, it returns 0.0.
- """
- if u == 0 and v == 0:
- return 0.0
- return np.mod(180 + np.rad2deg(np.arctan2(u, v)), 360)
-
-def wind_components_to_direction(ua: Union[float, int, List[float], List[int]], va: Union[float, int, List[float], List[int]]) -> Union[float, List[float]]:
- """
- Convert wind components ua and va to wind direction phi.
- Args:
- ua (Union[float, int, List[float], List[int]]): The u-component of the wind.
- va (Union[float, int, List[float], List[int]]): The v-component of the wind.
- Returns:
- float or List[float]: The calculated wind speed.
- Raises:
- ValueError: If the input types and incorrect or do not match or if lists of different lengths are provided.
- """
- if isinstance(ua, (float, int)) and isinstance(va, (float, int)):
- return calculate_wind_direction(ua, va)
- elif isinstance(ua, list) and isinstance(va, list):
- if not all(isinstance(num, (float, int)) for num in ua + va):
- raise ValueError("All elements in both lists must be either float or int.")
- if len(ua) != len(va):
- raise ValueError("Both lists must be of the same length.")
- return [calculate_wind_direction(u, v) for u, v in zip(ua, va)]
- else:
- raise ValueError("Both arguments must be either both float/int or both lists of float/int.")
diff --git a/barra2_dl/helpers_geo.py b/barra2_dl/helpers_geo.py
new file mode 100644
index 0000000..7660090
--- /dev/null
+++ b/barra2_dl/helpers_geo.py
@@ -0,0 +1,108 @@
+"""
+Helper funcitons for geo.
+todo draft functions to set grid for mapping support.
+todo implement for file naming
+"""
+
+import numpy as np
+import pandas as pd
+from typing import Union
+
+
+def generate_point_grid(lat_lon_bbox: Union[dict, tuple], lat_res: float, lon_res: float = None, offset:bool = None) -> (
+ pd.DataFrame):
+ """
+ Create a grid of longitude and latitude points between specified minimum and maximum values.
+
+ Args:
+ lat_lon_bbox (Union[dict, tuple]): Dictionary or tuple containing geographic boundaries.
+ Dictionary should have keys 'north', 'south', 'east', 'west'.
+ Tuple should contain values in the order (north, south, east, west).
+ lon_res (float): Resolution of the longitude points.
+ lat_res (float): Resolution of the latitude points. Optional lon_res = lat_res if not specified.
+ offset: Offsets the first point by half the lat_res and lon_res to create points at centre.
+
+ Returns:
+ pd.DataFrame: DataFrame containing the grid points with columns 'longitude' and 'latitude'.
+
+ Raises:
+ ValueError: If bounds is neither a dictionary nor a tuple, or if the keys/values are missing or invalid.
+ """
+
+ if isinstance(lat_lon_bbox, dict):
+ required_keys = ['north', 'south', 'east', 'west']
+ if not all(key in lat_lon_bbox for key in required_keys):
+ raise ValueError("Dictionary must contain 'north', 'south', 'east', and 'west' keys.")
+ elif isinstance(lat_lon_bbox, tuple):
+ if len(lat_lon_bbox) != 4:
+ raise ValueError("Tuple must contain exactly 4 values: (north, south, east, west).")
+ else:
+ raise ValueError("Bounds must be a dictionary or tuple.")
+
+ if lon_res is None:
+ lon_res = lat_res
+
+ if offset:
+ lat_lon_bbox = {
+ 'north': lat_lon_bbox['north'] - lat_res/2,
+ 'south': lat_lon_bbox['south'] + lat_res/2,
+ 'east': lat_lon_bbox['east'] - lon_res/2,
+ 'west': lat_lon_bbox['west'] + lon_res/2
+ }
+
+ longitudes = np.arange(lat_lon_bbox['west'], lat_lon_bbox['east'] + lon_res, lon_res)
+ latitudes = np.arange(lat_lon_bbox['south'], lat_lon_bbox['north'] + lat_res, lat_res)
+ long_grid, lat_grid = np.meshgrid(longitudes, latitudes)
+
+ df_point_grid = pd.DataFrame({
+ 'latitude': lat_grid.flatten(),
+ 'longitude': long_grid.flatten()
+ })
+
+ return df_point_grid
+
+
+def find_nearest_point(df_point_grid: pd.DataFrame, target_lat: float, target_lon: float) -> pd.Series:
+ """
+ Find the nearest point in a DataFrame of latitude, longitude points to a target point (target_lat, target_lon).
+
+ Args:
+ df_point_grid (pd.DataFrame): DataFrame containing the points with 'Longitude' and 'Latitude' columns.
+ target_lon (float): The x-coordinate of the target point.
+ target_lat (float): The y-coordinate of the target point.
+
+ Returns:
+ pd.Series: The row of the nearest point in the DataFrame.
+
+ """
+ # check if target falls within grid
+ min_lat, max_lat = df_point_grid['latitude'].min(), df_point_grid['latitude'].max()
+ min_lon, max_lon = df_point_grid['longitude'].min(), df_point_grid['longitude'].max()
+
+ if not (min_lat <= target_lat <= max_lat) or not (min_lon <= target_lon <= max_lon):
+ raise ValueError("Target latitude and/or longitude are out of the range of the DataFrame's coordinates.")
+
+ distances = np.sqrt((df_point_grid['latitude'] - target_lat) ** 2 + (df_point_grid['longitude'] - target_lon) ** 2)
+ nearest_index = distances.idxmin()
+ return df_point_grid.loc[nearest_index]
+
+
+def format_lat_lon(coordinates: dict) -> list[str]:
+ """
+ Format a dictionary containing 'lat' and 'lon' as floats to a string with 2 decimal precision,
+ converting any negative values to 'S'.
+
+ Args:
+ coordinates (dict): Dictionary containing 'lat' and 'lon' as floats.
+
+ Returns:
+ str: Formatted string of the latitude and longitude.
+ """
+ lat = coordinates.get('lat', 0.0)
+ lon = coordinates.get('lon', 0.0)
+
+ formatted_lat = ('S' if lat < 0 else '') + '{:.2f}'.format(abs(lat))
+ formatted_lon = '{:.2f}'.format(abs(lon))
+
+ return [formatted_lat, formatted_lon]
+
diff --git a/barra2_dl/helpers_wind.py b/barra2_dl/helpers_wind.py
new file mode 100644
index 0000000..efb5d10
--- /dev/null
+++ b/barra2_dl/helpers_wind.py
@@ -0,0 +1,84 @@
+"""
+Helper functions for wind calculations.
+# todo add tests
+"""
+
+from typing import List
+import numpy as np
+
+
+def calculate_wind_speed(u: float | int, v: float | int) -> float:
+ """
+ Calculate the wind speed from u and v components.
+ Args:
+ u (float | int): The u component of the wind vector.
+ v (float | int): The v component of the wind vector.
+ Returns:
+ Wind speed. If both u and v are zero, it returns 0.0.
+ """
+ if u == 0 and v == 0:
+ return 0.0
+ return np.sqrt(u ** 2 + v ** 2)
+
+
+def wind_components_to_speed(ua: float | int | list[float | int], va: float | int | list[float | int]) -> float | list[float]:
+ """
+ Convert wind components ua and va to wind speed v.
+ Args:
+ ua (float | int | list[float | int]): The u-component of the wind.
+ va (float | int | list[float | int]): The v-component of the wind.
+ Returns:
+ The calculated wind speed.
+ Raises:
+ ValueError: If the input types do not match or if they are neither list[float] nor list[int] nor float.
+ """
+ if isinstance(ua, (float, int)) and isinstance(va, (float, int)):
+ if ua == 0 and va == 0:
+ return 0.0
+ return calculate_wind_speed(ua, va)
+ elif isinstance(ua, list) and isinstance(va, list):
+ if not all(isinstance(num, (float, int)) for num in ua + va):
+ raise ValueError("All elements in both lists must be either float or int.")
+ if len(ua) != len(va):
+ raise ValueError("Both lists must be of the same length.")
+ return [calculate_wind_speed(u, v) for u, v in zip(ua, va)]
+ else:
+ raise ValueError("Both arguments must be either both float/int or both lists of float/int.")
+
+
+# todo add tests
+def calculate_wind_direction(u: float | int, v: float | int) -> float:
+ """
+ Args:
+ u (float | int): The u component of the wind vector, which can be a float or an int.
+ v (float | int): The v component of the wind vector, which can be a float or an int.
+ Returns:
+ Calculated wind direction in degrees. If both u and v are zero, it returns 0.0.
+ """
+ if u == 0 and v == 0:
+ return 0.0
+ return np.mod(180 + np.rad2deg(np.arctan2(u, v)), 360)
+
+
+def wind_components_to_direction(ua: float | int | List[float | int], va: float | int | List[float | int]) -> float | List[float]:
+ """
+ Convert wind components ua and va to wind direction phi.
+ Args:
+ ua (float | int | List[float | int]): The u-component of the wind.
+ va (float | int | List[float | int]): The v-component of the wind.
+ Returns:
+ The calculated wind speed direction.
+ Raises:
+ ValueError: If the input types and incorrect or do not match or if lists of different lengths are provided.
+ """
+
+ if isinstance(ua, (float, int)) and isinstance(va, (float, int)):
+ return calculate_wind_direction(ua, va)
+ elif isinstance(ua, list) and isinstance(va, list):
+ if not all(isinstance(num, (float, int)) for num in ua + va):
+ raise ValueError("All elements in both lists must be either float or int.")
+ if len(ua) != len(va):
+ raise ValueError("Both lists must be of the same length.")
+ return [calculate_wind_direction(u, v) for u, v in zip(ua, va)]
+ else:
+ raise ValueError("Both arguments must be either both float/int or both lists of float/int.")
diff --git a/barra2_dl/merger.py b/barra2_dl/merger.py
new file mode 100644
index 0000000..38227f3
--- /dev/null
+++ b/barra2_dl/merger.py
@@ -0,0 +1,135 @@
+"""
+Helper functions for csv files.
+"""
+from pathlib import Path
+import pandas as pd
+import fnmatch
+
+
+def list_csv_files(folder_path):
+ """
+ List all CSV files in the given folder.
+
+ Args:
+ folder_path (str): The path to the folder containing the CSV files.
+
+ Returns:
+ list: A list of CSV file names in the folder.
+ """
+ folder = Path(folder_path)
+ csv_files = [file.name for file in folder.glob('*.csv')]
+ return csv_files
+
+def filter_list_using_wildcard(input_list: list[str], pattern:str):
+ """
+ Filter a list using a wildcard pattern.
+
+ Args:
+ input_list (list[str]): The list of strings to be filtered.
+ pattern (str): The wildcard pattern to filter the list.
+
+ Returns:
+ list: A list of strings that match the wildcard pattern.
+ """
+ filtered_list = fnmatch.filter(input_list, pattern)
+ return filtered_list
+
+
+def export_df_to_csv(dataframe: pd.DataFrame,
+ fileout_folder: str | Path,
+ fileout_name: str,
+ create_folder: bool = True) -> None:
+ """
+ Export a DataFrame to a CSV file in the specified folder with the given file name.
+
+ Args:
+ dataframe (pd.DataFrame): The Pandas DataFrame to export.
+ fileout_folder (str or Path): The path to the folder where the CSV file will be saved.
+ fileout_name (str): The name of the CSV file to save.
+ create_folder (bool): If True, creates the folder if it does not exist; otherwise, exits if the folder doesn't exist.
+
+ Returns:
+ Path: The path of the saved CSV file.
+ """
+ fileout_folder = Path(fileout_folder)
+ # Check if the folder exists
+ if not fileout_folder.exists():
+ if create_folder:
+ fileout_folder.mkdir(parents=True)
+ print(f"The folder '{fileout_folder}' was created.")
+ else:
+ print(f"The folder '{fileout_folder}' does not exist. Exiting...")
+ return
+
+ # Define the full path for the CSV file
+ fileout_path_name = fileout_folder / fileout_name
+
+ # Export the DataFrame to CSV
+ dataframe.to_csv(fileout_path_name, index=False)
+
+ return fileout_path_name
+
+
+def merge_csvs_to_df(filein_folder: str,
+ filename_pattern: str = '*.csv',
+ index_for_join: str = None) -> pd.DataFrame:
+ """
+ Function to merge csv files iteratively from a folder based on filename wildcard.
+ If filename wildcard is omitted all csv files in the folder will be merged.
+
+ Args:
+ filein_folder (str): Optional
+ filename_pattern (str):
+ index_for_join (str):
+
+ Returns:
+ DataFrame: A DataFrame with the merged csvs.
+
+ Todo:
+ add .csv check for filename_prefix
+ """
+
+ def merge_suffix_columns(df: pd.DataFrame, suffix_x: str = '_x', suffix_y: str = '_y') -> pd.DataFrame:
+ """
+ Function to merge DataFrame columns with '_x' and '_y' suffixes.
+
+ Args:
+ df: The DataFrame that contains columns with suffixes to be merged.
+ suffix_x: The suffix used in the first set of columns (default is '_x').
+ suffix_y: The suffix used in the second set of columns (default is '_y').
+
+ Returns:
+ DataFrame: A DataFrame with the merged columns.
+ If no suffix_x returns the original DataFrame.
+
+ Todo:
+ Add checks for multiple and mismatched suffixed columns
+ """
+ for column in df.columns:
+ if column.endswith(suffix_x):
+ base_column = column[:-len(suffix_x)]
+ column_y = base_column + suffix_y
+ if column_y in df.columns:
+ # Create a new column without suffix and merge the values
+ df[base_column] = df[column].combine_first(df[column_y])
+ # Drop the old suffix columns
+ df.drop([column, column_y], axis=1, inplace=True)
+ return df
+
+ # initiate dataframe for combined csv results
+ df_combined = pd.DataFrame()
+
+ for file in Path(filein_folder).glob(filename_pattern):
+ print(f"Merging file: {file}")
+ if df_combined.empty:
+ # read csv file without indexing to retain time as column for join
+ df_combined = pd.read_csv(file)
+ else:
+ # read next file into new df
+ df_add = pd.read_csv(file)
+ # combine on index join if not None, otherwise just concat together
+ # todo df_combined = df1.merge(df2,how='outer') seems to guess the matching columns
+ df_combined = pd.merge(df_combined, df_add, how='outer', on=index_for_join)
+ df_combined = merge_suffix_columns(df_combined)
+
+ return df_combined
diff --git a/poetry.lock b/poetry.lock
index 95e559f..8e87aa1 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -716,25 +716,6 @@ files = [
{file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
]
-[[package]]
-name = "importlib-metadata"
-version = "7.0.1"
-description = "Read metadata from Python packages"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"},
- {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"},
-]
-
-[package.dependencies]
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
-perf = ["ipython"]
-testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
-
[[package]]
name = "iniconfig"
version = "2.0.0"
@@ -1092,118 +1073,64 @@ test = ["freezegun", "pytest", "pytest-cov", "pytest-datadir", "pytest-socket",
[[package]]
name = "numpy"
-version = "2.0.2"
-description = "Fundamental package for array computing in Python"
-optional = false
-python-versions = ">=3.9"
-files = [
- {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"},
- {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"},
- {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"},
- {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"},
- {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"},
- {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"},
- {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"},
- {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"},
- {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"},
- {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"},
- {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"},
- {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"},
- {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"},
- {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"},
- {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"},
- {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"},
- {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"},
- {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"},
- {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"},
- {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"},
- {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"},
- {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"},
- {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"},
- {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"},
- {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"},
- {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"},
- {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"},
- {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"},
- {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"},
- {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"},
- {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"},
- {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"},
- {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"},
-]
-
-[[package]]
-name = "numpy"
-version = "2.1.1"
+version = "2.1.2"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.10"
files = [
- {file = "numpy-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8a0e34993b510fc19b9a2ce7f31cb8e94ecf6e924a40c0c9dd4f62d0aac47d9"},
- {file = "numpy-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7dd86dfaf7c900c0bbdcb8b16e2f6ddf1eb1fe39c6c8cca6e94844ed3152a8fd"},
- {file = "numpy-2.1.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:5889dd24f03ca5a5b1e8a90a33b5a0846d8977565e4ae003a63d22ecddf6782f"},
- {file = "numpy-2.1.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:59ca673ad11d4b84ceb385290ed0ebe60266e356641428c845b39cd9df6713ab"},
- {file = "numpy-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13ce49a34c44b6de5241f0b38b07e44c1b2dcacd9e36c30f9c2fcb1bb5135db7"},
- {file = "numpy-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913cc1d311060b1d409e609947fa1b9753701dac96e6581b58afc36b7ee35af6"},
- {file = "numpy-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:caf5d284ddea7462c32b8d4a6b8af030b6c9fd5332afb70e7414d7fdded4bfd0"},
- {file = "numpy-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:57eb525e7c2a8fdee02d731f647146ff54ea8c973364f3b850069ffb42799647"},
- {file = "numpy-2.1.1-cp310-cp310-win32.whl", hash = "sha256:9a8e06c7a980869ea67bbf551283bbed2856915f0a792dc32dd0f9dd2fb56728"},
- {file = "numpy-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d10c39947a2d351d6d466b4ae83dad4c37cd6c3cdd6d5d0fa797da56f710a6ae"},
- {file = "numpy-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0d07841fd284718feffe7dd17a63a2e6c78679b2d386d3e82f44f0108c905550"},
- {file = "numpy-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5613cfeb1adfe791e8e681128f5f49f22f3fcaa942255a6124d58ca59d9528f"},
- {file = "numpy-2.1.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0b8cc2715a84b7c3b161f9ebbd942740aaed913584cae9cdc7f8ad5ad41943d0"},
- {file = "numpy-2.1.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:b49742cdb85f1f81e4dc1b39dcf328244f4d8d1ded95dea725b316bd2cf18c95"},
- {file = "numpy-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8d5f8a8e3bc87334f025194c6193e408903d21ebaeb10952264943a985066ca"},
- {file = "numpy-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d51fc141ddbe3f919e91a096ec739f49d686df8af254b2053ba21a910ae518bf"},
- {file = "numpy-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:98ce7fb5b8063cfdd86596b9c762bf2b5e35a2cdd7e967494ab78a1fa7f8b86e"},
- {file = "numpy-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24c2ad697bd8593887b019817ddd9974a7f429c14a5469d7fad413f28340a6d2"},
- {file = "numpy-2.1.1-cp311-cp311-win32.whl", hash = "sha256:397bc5ce62d3fb73f304bec332171535c187e0643e176a6e9421a6e3eacef06d"},
- {file = "numpy-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:ae8ce252404cdd4de56dcfce8b11eac3c594a9c16c231d081fb705cf23bd4d9e"},
- {file = "numpy-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c803b7934a7f59563db459292e6aa078bb38b7ab1446ca38dd138646a38203e"},
- {file = "numpy-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6435c48250c12f001920f0751fe50c0348f5f240852cfddc5e2f97e007544cbe"},
- {file = "numpy-2.1.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3269c9eb8745e8d975980b3a7411a98976824e1fdef11f0aacf76147f662b15f"},
- {file = "numpy-2.1.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:fac6e277a41163d27dfab5f4ec1f7a83fac94e170665a4a50191b545721c6521"},
- {file = "numpy-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcd8f556cdc8cfe35e70efb92463082b7f43dd7e547eb071ffc36abc0ca4699b"},
- {file = "numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b9cd92c8f8e7b313b80e93cedc12c0112088541dcedd9197b5dee3738c1201"},
- {file = "numpy-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:afd9c680df4de71cd58582b51e88a61feed4abcc7530bcd3d48483f20fc76f2a"},
- {file = "numpy-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8661c94e3aad18e1ea17a11f60f843a4933ccaf1a25a7c6a9182af70610b2313"},
- {file = "numpy-2.1.1-cp312-cp312-win32.whl", hash = "sha256:950802d17a33c07cba7fd7c3dcfa7d64705509206be1606f196d179e539111ed"},
- {file = "numpy-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:3fc5eabfc720db95d68e6646e88f8b399bfedd235994016351b1d9e062c4b270"},
- {file = "numpy-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:046356b19d7ad1890c751b99acad5e82dc4a02232013bd9a9a712fddf8eb60f5"},
- {file = "numpy-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6e5a9cb2be39350ae6c8f79410744e80154df658d5bea06e06e0ac5bb75480d5"},
- {file = "numpy-2.1.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:d4c57b68c8ef5e1ebf47238e99bf27657511ec3f071c465f6b1bccbef12d4136"},
- {file = "numpy-2.1.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:8ae0fd135e0b157365ac7cc31fff27f07a5572bdfc38f9c2d43b2aff416cc8b0"},
- {file = "numpy-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:981707f6b31b59c0c24bcda52e5605f9701cb46da4b86c2e8023656ad3e833cb"},
- {file = "numpy-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ca4b53e1e0b279142113b8c5eb7d7a877e967c306edc34f3b58e9be12fda8df"},
- {file = "numpy-2.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e097507396c0be4e547ff15b13dc3866f45f3680f789c1a1301b07dadd3fbc78"},
- {file = "numpy-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7506387e191fe8cdb267f912469a3cccc538ab108471291636a96a54e599556"},
- {file = "numpy-2.1.1-cp313-cp313-win32.whl", hash = "sha256:251105b7c42abe40e3a689881e1793370cc9724ad50d64b30b358bbb3a97553b"},
- {file = "numpy-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:f212d4f46b67ff604d11fff7cc62d36b3e8714edf68e44e9760e19be38c03eb0"},
- {file = "numpy-2.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:920b0911bb2e4414c50e55bd658baeb78281a47feeb064ab40c2b66ecba85553"},
- {file = "numpy-2.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bab7c09454460a487e631ffc0c42057e3d8f2a9ddccd1e60c7bb8ed774992480"},
- {file = "numpy-2.1.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:cea427d1350f3fd0d2818ce7350095c1a2ee33e30961d2f0fef48576ddbbe90f"},
- {file = "numpy-2.1.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:e30356d530528a42eeba51420ae8bf6c6c09559051887196599d96ee5f536468"},
- {file = "numpy-2.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8dfa9e94fc127c40979c3eacbae1e61fda4fe71d84869cc129e2721973231ef"},
- {file = "numpy-2.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910b47a6d0635ec1bd53b88f86120a52bf56dcc27b51f18c7b4a2e2224c29f0f"},
- {file = "numpy-2.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:13cc11c00000848702322af4de0147ced365c81d66053a67c2e962a485b3717c"},
- {file = "numpy-2.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53e27293b3a2b661c03f79aa51c3987492bd4641ef933e366e0f9f6c9bf257ec"},
- {file = "numpy-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7be6a07520b88214ea85d8ac8b7d6d8a1839b0b5cb87412ac9f49fa934eb15d5"},
- {file = "numpy-2.1.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:52ac2e48f5ad847cd43c4755520a2317f3380213493b9d8a4c5e37f3b87df504"},
- {file = "numpy-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a95ca3560a6058d6ea91d4629a83a897ee27c00630aed9d933dff191f170cd"},
- {file = "numpy-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:99f4a9ee60eed1385a86e82288971a51e71df052ed0b2900ed30bc840c0f2e39"},
- {file = "numpy-2.1.1.tar.gz", hash = "sha256:d0cf7d55b1051387807405b3898efafa862997b4cba8aa5dbe657be794afeafd"},
+ {file = "numpy-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30d53720b726ec36a7f88dc873f0eec8447fbc93d93a8f079dfac2629598d6ee"},
+ {file = "numpy-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d3ca0a72dd8846eb6f7dfe8f19088060fcb76931ed592d29128e0219652884"},
+ {file = "numpy-2.1.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:fc44e3c68ff00fd991b59092a54350e6e4911152682b4782f68070985aa9e648"},
+ {file = "numpy-2.1.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:7c1c60328bd964b53f8b835df69ae8198659e2b9302ff9ebb7de4e5a5994db3d"},
+ {file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cdb606a7478f9ad91c6283e238544451e3a95f30fb5467fbf715964341a8a86"},
+ {file = "numpy-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d666cb72687559689e9906197e3bec7b736764df6a2e58ee265e360663e9baf7"},
+ {file = "numpy-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c6eef7a2dbd0abfb0d9eaf78b73017dbfd0b54051102ff4e6a7b2980d5ac1a03"},
+ {file = "numpy-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:12edb90831ff481f7ef5f6bc6431a9d74dc0e5ff401559a71e5e4611d4f2d466"},
+ {file = "numpy-2.1.2-cp310-cp310-win32.whl", hash = "sha256:a65acfdb9c6ebb8368490dbafe83c03c7e277b37e6857f0caeadbbc56e12f4fb"},
+ {file = "numpy-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:860ec6e63e2c5c2ee5e9121808145c7bf86c96cca9ad396c0bd3e0f2798ccbe2"},
+ {file = "numpy-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b42a1a511c81cc78cbc4539675713bbcf9d9c3913386243ceff0e9429ca892fe"},
+ {file = "numpy-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:faa88bc527d0f097abdc2c663cddf37c05a1c2f113716601555249805cf573f1"},
+ {file = "numpy-2.1.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:c82af4b2ddd2ee72d1fc0c6695048d457e00b3582ccde72d8a1c991b808bb20f"},
+ {file = "numpy-2.1.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:13602b3174432a35b16c4cfb5de9a12d229727c3dd47a6ce35111f2ebdf66ff4"},
+ {file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ebec5fd716c5a5b3d8dfcc439be82a8407b7b24b230d0ad28a81b61c2f4659a"},
+ {file = "numpy-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2b49c3c0804e8ecb05d59af8386ec2f74877f7ca8fd9c1e00be2672e4d399b1"},
+ {file = "numpy-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cbba4b30bf31ddbe97f1c7205ef976909a93a66bb1583e983adbd155ba72ac2"},
+ {file = "numpy-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8e00ea6fc82e8a804433d3e9cedaa1051a1422cb6e443011590c14d2dea59146"},
+ {file = "numpy-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5006b13a06e0b38d561fab5ccc37581f23c9511879be7693bd33c7cd15ca227c"},
+ {file = "numpy-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:f1eb068ead09f4994dec71c24b2844f1e4e4e013b9629f812f292f04bd1510d9"},
+ {file = "numpy-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7bf0a4f9f15b32b5ba53147369e94296f5fffb783db5aacc1be15b4bf72f43b"},
+ {file = "numpy-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b1d0fcae4f0949f215d4632be684a539859b295e2d0cb14f78ec231915d644db"},
+ {file = "numpy-2.1.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f751ed0a2f250541e19dfca9f1eafa31a392c71c832b6bb9e113b10d050cb0f1"},
+ {file = "numpy-2.1.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:bd33f82e95ba7ad632bc57837ee99dba3d7e006536200c4e9124089e1bf42426"},
+ {file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8cde4f11f0a975d1fd59373b32e2f5a562ade7cde4f85b7137f3de8fbb29a0"},
+ {file = "numpy-2.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d95f286b8244b3649b477ac066c6906fbb2905f8ac19b170e2175d3d799f4df"},
+ {file = "numpy-2.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ab4754d432e3ac42d33a269c8567413bdb541689b02d93788af4131018cbf366"},
+ {file = "numpy-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e585c8ae871fd38ac50598f4763d73ec5497b0de9a0ab4ef5b69f01c6a046142"},
+ {file = "numpy-2.1.2-cp312-cp312-win32.whl", hash = "sha256:9c6c754df29ce6a89ed23afb25550d1c2d5fdb9901d9c67a16e0b16eaf7e2550"},
+ {file = "numpy-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:456e3b11cb79ac9946c822a56346ec80275eaf2950314b249b512896c0d2505e"},
+ {file = "numpy-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a84498e0d0a1174f2b3ed769b67b656aa5460c92c9554039e11f20a05650f00d"},
+ {file = "numpy-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4d6ec0d4222e8ffdab1744da2560f07856421b367928026fb540e1945f2eeeaf"},
+ {file = "numpy-2.1.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:259ec80d54999cc34cd1eb8ded513cb053c3bf4829152a2e00de2371bd406f5e"},
+ {file = "numpy-2.1.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:675c741d4739af2dc20cd6c6a5c4b7355c728167845e3c6b0e824e4e5d36a6c3"},
+ {file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b2d4e667895cc55e3ff2b56077e4c8a5604361fc21a042845ea3ad67465aa8"},
+ {file = "numpy-2.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43cca367bf94a14aca50b89e9bc2061683116cfe864e56740e083392f533ce7a"},
+ {file = "numpy-2.1.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:76322dcdb16fccf2ac56f99048af32259dcc488d9b7e25b51e5eca5147a3fb98"},
+ {file = "numpy-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:32e16a03138cabe0cb28e1007ee82264296ac0983714094380b408097a418cfe"},
+ {file = "numpy-2.1.2-cp313-cp313-win32.whl", hash = "sha256:242b39d00e4944431a3cd2db2f5377e15b5785920421993770cddb89992c3f3a"},
+ {file = "numpy-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f2ded8d9b6f68cc26f8425eda5d3877b47343e68ca23d0d0846f4d312ecaa445"},
+ {file = "numpy-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ffef621c14ebb0188a8633348504a35c13680d6da93ab5cb86f4e54b7e922b5"},
+ {file = "numpy-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ad369ed238b1959dfbade9018a740fb9392c5ac4f9b5173f420bd4f37ba1f7a0"},
+ {file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d82075752f40c0ddf57e6e02673a17f6cb0f8eb3f587f63ca1eaab5594da5b17"},
+ {file = "numpy-2.1.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:1600068c262af1ca9580a527d43dc9d959b0b1d8e56f8a05d830eea39b7c8af6"},
+ {file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a26ae94658d3ba3781d5e103ac07a876b3e9b29db53f68ed7df432fd033358a8"},
+ {file = "numpy-2.1.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13311c2db4c5f7609b462bc0f43d3c465424d25c626d95040f073e30f7570e35"},
+ {file = "numpy-2.1.2-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:2abbf905a0b568706391ec6fa15161fad0fb5d8b68d73c461b3c1bab6064dd62"},
+ {file = "numpy-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ef444c57d664d35cac4e18c298c47d7b504c66b17c2ea91312e979fcfbdfb08a"},
+ {file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bdd407c40483463898b84490770199d5714dcc9dd9b792f6c6caccc523c00952"},
+ {file = "numpy-2.1.2-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:da65fb46d4cbb75cb417cddf6ba5e7582eb7bb0b47db4b99c9fe5787ce5d91f5"},
+ {file = "numpy-2.1.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c193d0b0238638e6fc5f10f1b074a6993cb13b0b431f64079a509d63d3aa8b7"},
+ {file = "numpy-2.1.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a7d80b2e904faa63068ead63107189164ca443b42dd1930299e0d1cb041cec2e"},
+ {file = "numpy-2.1.2.tar.gz", hash = "sha256:13532a088217fa624c99b843eeb54640de23b3414b14aa66d023805eb731066c"},
]
[[package]]
@@ -1489,7 +1416,6 @@ files = [
]
[package.dependencies]
-importlib-metadata = {version = ">=3.6.0", markers = "python_version < \"3.10\""}
pytest = "*"
[[package]]
@@ -1819,7 +1745,6 @@ babel = ">=2.9"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
docutils = ">=0.18.1,<0.21"
imagesize = ">=1.3"
-importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""}
Jinja2 = ">=3.0"
packaging = ">=21.0"
Pygments = ">=2.14"
@@ -2124,22 +2049,7 @@ files = [
[package.extras]
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
-[[package]]
-name = "zipp"
-version = "3.17.0"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"},
- {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"},
-]
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
-testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
-
[metadata]
lock-version = "2.0"
-python-versions = "^3.9"
-content-hash = "6924569113877b7f5065dd555a3f81fcecb7b4e438bdb0d60e30d1b16cb711cc"
+python-versions = "^3.10"
+content-hash = "494a653a2e7235307dfd8ab2b09daa5520b9b2f27367f0e756dd4b7571229b16"
diff --git a/pyproject.toml b/pyproject.toml
index dc5618d..564e800 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -25,10 +25,11 @@ classifiers = [
]
[tool.poetry.dependencies]
-python = "^3.9"
+python = "^3.10"
pandas = "^2.2.3"
pathlib = "^1.0.1"
requests = "^2.32.3"
+numpy = "^2.1.2"
[tool.poetry.group.dev.dependencies]
mypy = "^1.8"
diff --git a/scripts/barra2_downloader_example.py b/scripts/barra2_downloader_example.py
index 89e37ef..af57eef 100644
--- a/scripts/barra2_downloader_example.py
+++ b/scripts/barra2_downloader_example.py
@@ -21,8 +21,8 @@
start_datetime = datetime.strptime("2023-01-01T00:00:00Z", "%Y-%m-%dT%H:%M:%SZ")
end_datetime = datetime.strptime("2023-03-31T23:00:00Z", "%Y-%m-%dT%H:%M:%SZ")
-# set output file custom name prefix to indicate a device or project location for the downloaded data
-output_filename_prefix = "test"
+# Option to set output file custom name prefix to indicate a device or project location for the downloaded data
+output_filename_prefix = "demo"
# -----------------------------------------------------------------------------
diff --git a/tests/test_downloader.py b/tests/test_downloader.py
index cd22760..1c0f62e 100644
--- a/tests/test_downloader.py
+++ b/tests/test_downloader.py
@@ -1,6 +1,6 @@
import pytest
-from barra2_dl import downloaders
+from barra2_dl import downloader
from barra2_dl.globals import *
@pytest.mark.parametrize(('first', 'second', 'expected'), [
diff --git a/tests/test_example/test_some_function.py b/tests/test_example/test_some_function.py
index 1cc48f0..b129265 100644
--- a/tests/test_example/test_some_function.py
+++ b/tests/test_example/test_some_function.py
@@ -1,5 +1,4 @@
import pytest
-
from barra2_dl.example import some_function
diff --git a/tests/test_helpers_wind.py b/tests/test_helpers_wind.py
new file mode 100644
index 0000000..3200211
--- /dev/null
+++ b/tests/test_helpers_wind.py
@@ -0,0 +1,16 @@
+import pytest
+
+from barra2_dl import helpers_wind
+
+
+@pytest.mark.parametrize(('u', 'v', 'expected'), [
+ (1, 1, 1.4142135623730951),
+ (-1, -1, 1.4142135623730951),
+ (1., 1., 1.4142135623730951),
+ (-1., -1., 1.4142135623730951),
+ (0, 0, 0),
+ (0., 0., 0.),
+])
+def test_calculate_wind_speed(u: float, v: float, expected: float) -> None:
+ """Example test with parametrization."""
+ assert helpers_wind.calculate_wind_speed(u, v) == expected