### ===================================================================================================================
### Utilities for Signal Processing Tool
### ===================================================================================================================
# Copyright ©2025 Haskoning Nederland B.V.
### ===================================================================================================================
### 1. Constants
### ===================================================================================================================
# General imports
import csv
import openpyxl
from pathlib import Path
from typing import Union
# Importing internal modules
from haskoning_atr_tools.signal_processing_tool.utils.constants import SRB_VIBRATION_LIMITS
### ===================================================================================================================
### 2. Handle csv and xlsx files
### ===================================================================================================================
[docs]
def read_columns_from_file(
file: Union[str, Path], skip_rows: int, columns: list, delimiter: str = ',') -> list[list[float]]:
"""
This function reads the specified columns from a file (csv or xlsx-file).
Input:
- file (Path or str): The file path to the data file.
- skip_rows (int): The number of rows to skip at the beginning of the file.
- columns (list): The names or indices of the columns to read.
- delimiter (str): The delimiter used in the csv-file. Default is ','.
Output:
- Returns a list of lists, each containing the data from the specified columns. Order according the requested
columns to be read.
"""
if isinstance(file, str):
file = Path(file)
if file.suffix == '.csv':
with open(file, 'r') as file:
reader = csv.reader(file, delimiter=delimiter)
lines = list(reader)[skip_rows-1:]
# Check if columns are provided as names
if isinstance(columns[0], str):
# Read the header row to find the indices of the specified columns
header = lines[0]
column_indices = [header.index(col) for col in columns]
else:
# Use the provided indices directly
column_indices = columns
# Skip the specified number of rows
lines = lines[1:]
num_lines = len(lines)
# Preallocate the data structure
data = [[0.0] * num_lines for _ in column_indices]
# Read the data from the specified columns
for row_idx, row in enumerate(lines):
for i, col_idx in enumerate(column_indices):
data[i][row_idx] = float(row[col_idx])
return data
elif file.suffix == '.xlsx':
wb = openpyxl.load_workbook(file, data_only=True)
sheet = wb.active
rows = list(sheet.iter_rows(values_only=True))
# Check if columns are provided as names
if isinstance(columns[0], str):
# Read the header row to find the indices of the specified columns
header = rows[skip_rows - 1]
column_indices = [header.index(col) for col in columns]
else:
# Use the provided indices directly
column_indices = columns
# Skip the specified number of rows
rows = rows[skip_rows:]
num_rows = len(rows)
# Preallocate the data structure
data = [[0.0] * num_rows for _ in column_indices]
# Read the data from the specified columns
for i, col_idx in enumerate(column_indices):
data[i] = [float(row[col_idx]) for row in rows]
return data
raise ValueError(
f"ERROR: The Signal Processing Tool is only implemented for file types 'csv' or 'xlsx'. Provided was a "
f"{file.suffix.replace('.', '')}-file.")
[docs]
def write_data_to_file(
folder_path: str, file_name: str, data: list[list[float]], columns_header: list, column_numbers: list,
skip_rows: int = 0, file_type: str = 'csv') -> Path:
"""
Writes specified columns to a file (CSV or Excel).
Input:
- folder_path (str): The path to the folder.
- file_name (str): The name of the file.
- data (list[list[float]]): The data to write, each sublist representing a column.
- columns_header (list): The names of the columns.
- column_numbers (list): The column numbers to write the data into.
- skip_rows (int): The number of rows to skip at the beginning of the file.
- file_type (str): The type of the file ('csv' or 'xlsx'). Defaults to 'csv'.
Output:
- Returns the path of the created csv- or xlsx-file.
"""
if file_type not in ['csv', 'xlsx']:
raise ValueError("ERROR: Invalid file type. Must be 'csv' or 'xlsx'.")
if file_type == 'csv':
file_path = Path(folder_path + '/' + file_name + '.csv')
with open(file_path, 'w', newline='') as file:
writer = csv.writer(file)
for _ in range(skip_rows):
writer.writerow([])
writer.writerow(columns_header) # Write the header row
for row in zip(*data):
row_data = [''] * len(columns_header)
for i, col_num in enumerate(column_numbers):
row_data[col_num] = row[i]
writer.writerow(row_data)
else:
file_path = Path(folder_path + '/' + file_name + '.xlsx')
wb = openpyxl.Workbook()
sheet = wb.active
for _ in range(skip_rows):
sheet.append([])
sheet.append(columns_header) # Write the header row
for row in zip(*data):
row_data = [''] * len(columns_header)
for i, col_num in enumerate(column_numbers):
row_data[col_num] = row[i]
sheet.append(row_data)
wb.save(file_path)
return file_path
### ===================================================================================================================
### 3. SBR vibration limits
### ===================================================================================================================
[docs]
def get_sbr_vibration_limit(building_function: str, time_of_day: str, limit_type: str) -> float:
"""
Retrieves the SRB vibration limit based on building function, time of day, and limit type.
Input:
- building_function (str): The function of the building. Select from 'residential', 'healthcare', 'meeting',
'office', or 'critical'.
- time_of_day (str): Select the time of day: 'day', or 'night'.
- limit_type (str): Select the type of limit: 'A1', 'A2', or 'A3'.
Output:
- Returns the vibration limit value.
"""
# Normalize inputs
building_function = building_function.lower()
time_of_day = time_of_day.lower()
limit_type = limit_type.upper()
# Retrieve the limit
try:
return SRB_VIBRATION_LIMITS[building_function][time_of_day][limit_type]
except KeyError:
raise KeyError(
"ERROR: Invalid input to determine the SBR vibration limit. Please check the building function, time of "
"day, or limit type.")
### ===================================================================================================================
### 4. End of script
### ===================================================================================================================