### ===================================================================================================================
### FUNCTION Seismic assessment based on wind comparison
### ===================================================================================================================
# Copyright ©2026 Haskoning Nederland B.V.
# For use by VIIA
### ===================================================================================================================
### 1. Import modules
### ===================================================================================================================
# General imports
from __future__ import annotations
import sys
import pandas as pd
from pathlib import Path
from warnings import warn
from typing import TYPE_CHECKING, Literal, Optional
# References for functions and classes in the haskoning_sd_tools package
from haskoning_sd_tools.wind_design import WindForcesTool
# References for functions and classes in the haskoning_structural package
from haskoning_structural.tools.NPR9998_webtool import fem_lat_lng_to_rd
# References for functions and classes in the viiaPackage
if TYPE_CHECKING:
from viiapackage.viiaStatus import ViiaProject
### ===================================================================================================================
### 2. Function to find maximum wind metric over lifetime
### ===================================================================================================================
WindKey = Literal['FHVEC', 'FG', 'FHX', 'FHN']
WIND_INFO = {
'FHVEC': 'Vector-averaged wind speed',
'FG': 'Daily average wind speed',
'FHX': 'Highest hourly average wind speed',
'FHN': 'Lowest hourly average wind speed'}
[docs]def viia_maximum_wind_lifetime(project: ViiaProject, year: int, wind_key: WindKey = 'FHX') -> float:
"""
Function to compute the maximum highest hourly average wind speed over the lifetime of the structure. The wind
metric is retrieved from the Royal Netherlands Meteorological Institute
`KNMI <https://daggegevens.knmi.nl/klimatologie/daggegevens>`_ for weather station of Eelde.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- year (int): Inclusive lower bound for the year filter (e.g., 1970 means filter `date.year >= 1970`).
- wind_key (str): The wind metric column in the database to maximize. Default value for the VIIA project is the
highest hourly average wind speed.
Output:
- Returns the maximum value of the highest hourly average wind speed, in [m/s], according measurements at
weather station Eelde, over the lifetime of the structure.
"""
# Check input
if not isinstance(year, int):
raise TypeError(f"ERROR: Input for the year must be an integer. Provided was {year} of type {type(year)}.")
if wind_key not in WIND_INFO:
raise KeyError(
f"ERROR: Input for the wind-key must be selected from this list: {', '.join(WIND_INFO.keys())}. Provided "
f"was {wind_key}.")
if year > 2025:
raise NotImplementedError(
f"ERROR: Input for the year cannot be greater than 2025. Wind data is collected up to 2025. Provided was "
f"{year}.")
# Load Parquet
file_path = Path(__file__).parent / f'wind_data.parquet'
if not file_path.exists():
raise FileNotFoundError(
f"ERROR: Wind-data file for calculating the maximum wind over lifetime of structure is not found at "
f"{file_path.as_posix()}.")
df = pd.read_parquet(file_path, columns=['date', wind_key])
# Get the maximum value since and including the requested year
row = (
df.assign(
date=pd.to_datetime(df['date'], utc=True, errors='coerce'),
FHX=pd.to_numeric(df[wind_key], errors='coerce'))
.loc[lambda d: d['date'].dt.year >= year]
.dropna(subset=[wind_key])
.nlargest(1, wind_key)
.iloc[0])
# Values provided by KNMI are in 0.1m/s these are converted to m/s
max_wind_velocity = 0.1 * float(row[wind_key])
# Log information retrieved
project.write_log(
f"The maximum {WIND_INFO[wind_key].lower()} of {max_wind_velocity:.1f}m/s occurred on {row['date']}. For the "
f"structure since {year}.")
# Return the requested maximum value
return max_wind_velocity
### ===================================================================================================================
### 3. Function to generate wind comparison report
### ===================================================================================================================
[docs]def viia_create_wind_comparison_report(
project: ViiaProject, height: float, width: float, depth: float, year: int,
roof_type: Literal['flat', 'duopitch'] = 'flat', roof_angle: Optional[float] = None,
orientation_angle: float = 0) -> Path:
"""
This function is used to execute the seismic assessment of the structure based on the wind comparison procedure.
Currently, the wind part of this comparison is available in an automated workflow. User should still copy the
relevant data to the NCG template and include the lateral force part for the seismic part of the comparison. Future
developments will further assist the user in this workflow.
Input:
- project (obj): VIIA project object containing collections of fem objects and project variables.
- height (float): The height of the (simplified) building structure, in [m].
- width (float): The width of the (simplified) building structure, in [m]. This is the dimension perpendicular
to the wind at 0 degrees. The specification of the front facade aligns with EN1991-1-4 for different
roof-types.
- depth (float): The depth of the (simplified) building structure, in [m]. This is the dimension in the
direction of the wind at 0 degrees. The specification of the front facade aligns with EN1991-1-4 for different
roof-types.
- year (int): Input for the year used to determine the wind load over the lifetime of the current load-bearing
structure (before 2026).
- roof_type (str): Select the type of roof for the building structure. Select from 'flat' or 'duopitch'.
Default value is 'flat'.
- roof_angle (float): For duopitch roofs, the angle of the roof should be provided, in [degrees]. The input
is ignored for roof-type 'flat'. Default value is None.
- orientation_angle (float): Rotation of the building, in [deg]. Default value is 0. Input is used for the
sections of the terrain roughness calculation. 0 degrees is a front facade facing South.
Output:
- Returns the file-path of the generated report with the wind part of the comparison.
"""
# Check Python version
if sys.version_info < (3, 11):
raise RuntimeError(
"ERROR: The wind comparison functionality is only available for Python 3.11 and above (it is also not "
"available in DIANA 10.9). Please run your script in a higher version of Python.")
# Get the x, y coordinates of 'rijksdriehoeksstelsel' (RD)
rd_x, rd_y = fem_lat_lng_to_rd(
lat=project.project_information['gps']['latitude'], lng=project.project_information['gps']['longitude'])
# Create the wind forces tool
wind_force_tool = WindForcesTool(
height=height, width=width, depth=depth, roof_type=roof_type, roof_angle=roof_angle,
name=project.project_information['objectnummer_viia'], x=rd_x, y=rd_y, orientation_angle=orientation_angle)
# Get the reduced basic wind velocity based on the maximum wind load during the lifetime of the structure
# For this the maximum highest hourly average wind speed is determined during the lifetime, based on measurements
# of the weather station Eelde. The fundamental value of the basic wind velocity is the characteristic 10 minutes
# mean wind velocity, irrespective of wind direction and time of year, at 10m above ground level in terrain
# category II. The measurements in Eelde are at 10m above ground level and is situated in terrain category II.
# The site is expected to be representative for the average location in Groningen, or conservative.
# It is assumed that the ratio between 10-minute and hourly average wind speed is 1.10. Conservative estimation
# based on literature.
wind_force_tool.wind.v_b_0 = 1.1 * viia_maximum_wind_lifetime(project=project, year=year, wind_key='FHX')
# Create the report for the wind comparison. Currently, the Haskoning report is generated, in future developments
# the NCG template will be added.
warn("WARNING: The wind force tool currently reports in the Haskoning template. The NCG template will be added in "
"future development.")
return wind_force_tool.create_report(security_classification='project related', reference_code='VIIA')
### ===================================================================================================================
### 4. End of script
### ===================================================================================================================