Source code for haskoning_atr_tools.vibration_contour_plot.equipment.equipment_functions

### ===================================================================================================================
###  Functionality for the equipments in the vibration simulation
### ===================================================================================================================
# Copyright ©2026 Haskoning Nederland B.V.

### ===================================================================================================================
###  1. Import modules
### ===================================================================================================================

# General imports
from pathlib import Path
from typing import Literal, Optional, Union, List

# References for functions and classes in the haskoning_atr_tools package
from haskoning_atr_tools.signal_processing import FrequencyDomainData
from haskoning_atr_tools.vibration_contour_plot.helper_functions import load_data_from_file, v_to_db
from haskoning_atr_tools.vibration_contour_plot.equipment.equipment import Equipment


### ===================================================================================================================
###  2. Function to create Equipment instances from file
### ===================================================================================================================

[docs] def create_equipments_from_file( project, file_path: Union[Path, str], sheet_name: Union[str, int] = 0, activity_filter: Optional[Literal['continuous', 'intermittent', 'emergency']] = None, column_mapping: Optional[dict[str, str]] = None) -> List[Equipment]: """ Function to create equipments from file for vibration analysis. Input: - project (obj): Project object containing collections of objects and project variables. - file_path (Path or str): Path to file containing the equipment data for vibration analysis. The file can be provided as Excel-file or csv-file. In case of Excel, the sheet name should be provided for the worksheet with the equipment data. In both cases the header should be provided in row 1. When providing a column 'Calculate' the user can specify to use the equipment or not (overrules other filters). If column is not present, all equipments will be loaded, depending on other filters applied. - sheet_name (str or int): Sheet name or index of sheet with the equipment data. Default value is 0, selecting the first sheet in the Excel file. Input is ignored for csv-files. - activity_filter (list): Optional input to limit the equipments loaded in the vibration simulation based on the activity. Provide one or more of the following activity types in the list: 'continuous', 'intermittent', or 'emergency'. Default value is None, all equipments are loaded. - column_mapping (dict): Optional input to specify other column headers for the input of the file. This might be convenient if the data is provided with other column names. Default value is None, the default names are used for loading the equipments from the file. Output: - The equipments are created and added to the project, based on the provided filters. - Returns list of instances of Equipment class created in the function. """ default_optional_column_mapping = { 'calculate': 'Calculate', 'center_frequency': 'Center frequency [Hz]', 'angular_frequency': 'Angular frequency [rad/s]', 'rpm': 'RPM'} # Read file and handle the default user options df, column_mapping, defaults_used = load_data_from_file( file_path=file_path, sheet_name=sheet_name, column_mapping=column_mapping, default_column_mapping={ 'name': 'Name', 'id': 'ID', 'x': 'X coordinate [m]', 'y': 'Y coordinate [m]', 'z': 'Z coordinate [m]', 'vibration_source_level': 'Vibration source level', 'unit': 'Unit', 'min_frequency': 'Min frequency [Hz]', 'max_frequency': 'Max frequency [Hz]', 'flat_noise_percent': 'Flat noise [%]', 'activity': 'Activity'}, default_optional_column_mapping=default_optional_column_mapping) # Validate mapping if not any([v in column_mapping for v in ['center_frequency', 'angular_frequency', 'rpm']]): if defaults_used: expected_columns = [ default_optional_column_mapping[v] for v in ['center_frequency', 'angular_frequency', 'rpm']] raise KeyError( f"ERROR: Missing input for either the {', '.join(expected_columns)}. Please provide file with " f"the missing inputs.") raise KeyError( "ERROR: Missing input for either the 'center_frequency', 'angular_frequency' or 'rpm'. Please provide " " file with the missing inputs.") if sum(1 for v in ['center_frequency', 'angular_frequency', 'rpm'] if v in column_mapping) != 1: raise ValueError( "ERROR: Please select one from 'center_frequency', 'angular_frequency' or 'rpm' to be provided in the " "file.") # Loop through rows with equipment data equipments_from_file = [] for i, row in df.iterrows(): # Check optional inputs if 'calculate' in column_mapping: if not row[column_mapping['calculate']]: continue # Check for activity filter if activity_filter and row[column_mapping['activity']].lower() not in activity_filter: continue # Check the name equipment_name = row[column_mapping['name']].replace('/', '_').replace('\\', '_').replace('\n', '_') # Check the ID as unique identifier for the Target equipment_identifier = row[column_mapping['id']] if equipment_identifier in [e.id for e in project.equipment_list]: raise ValueError( f"ERROR: Please provide unique ID for the equipment. Duplicate ID: {equipment_identifier}.") # Add the optional inputs kwargs = { f'_{k}': row[column_mapping[k]] for k in ['center_frequency', 'angular_frequency', 'rpm'] if k in column_mapping} # Check the vibration source level unit if row[column_mapping['unit']] == 'm/s': vibration_source_level = v_to_db(velocity=row[column_mapping['vibration_source_level']]) elif row[column_mapping['unit']] in ['dB', 'decibel']: vibration_source_level = row[column_mapping['vibration_source_level']] else: raise NotImplementedError( f"ERROR: The unit for the vibration source level '{row[column_mapping['unit']]}' is not supported. " f"Please select from 'dB' or 'm/s'.") # Create the instance of the equipment, validation executed in class equipment = Equipment( name=equipment_name, id=equipment_identifier, coordinates=(row[column_mapping['x']], row[column_mapping['y']], row[column_mapping['z']]), vibration_source_level=vibration_source_level, min_frequency=row[column_mapping['min_frequency']], max_frequency=row[column_mapping['max_frequency']], flat_noise_percent=row[column_mapping['flat_noise_percent']], activity=row[column_mapping['activity']].lower(), **kwargs) project.equipment_list.append(equipment) equipments_from_file.append(equipment) return equipments_from_file
### =================================================================================================================== ### 3. Function to create the frequency data for all equipment ### ===================================================================================================================
[docs] def create_frequency_domain_data_from_equipments(project, sampling_rate: float) -> List[FrequencyDomainData]: """ Function to create frequency domain data for all the equipments defined in the project. The frequency domain data contains the combination of the harmonic component and the white noise component. The white noise component is not included in the part where the harmonic component is defined. Input: - project (obj): Project object containing collections of objects and project variables. - sampling_rate (float): Frequency sampling rate, in [Hz]. Output: - The harmonic, white noise and combined frequency domain data are created for all the equipments and added to the respective lists in project, 'fdd_harmonic_collection', 'fdd_noise_collection' and 'fdd_sources_collection'. - Returns list of the combined frequency domain data. """ if not project.equipment_list: raise RuntimeError("ERROR: No vibration equipments available. Please create the equipments first.") return \ [eq.create_frequency_domain_data(project=project, sampling_rate=sampling_rate) for eq in project.equipment_list]
### =================================================================================================================== ### 4. End of script ### ===================================================================================================================