Source code for viiapackage.results.result_functions.viia_sra

### ===================================================================================================================
###   Function to calculate the site response
### ===================================================================================================================
# Copyright ©VIIA 2024

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

# General imports
from __future__ import annotations
from typing import TYPE_CHECKING, Dict
from copy import deepcopy
from pathlib import Path

# References for functions and classes in the rhdhv_fem
from rhdhv_fem.fem_config import Config
from rhdhv_fem.fem_tools import fem_read_file
from rhdhv_fem.tools import fem_convert_signal_responsespectrum

# References for functions and classes in the viiaPackage
if TYPE_CHECKING:
    from viiapackage.viiaStatus import ViiaProject

# Import module matplotlib
import matplotlib
# Switch to a non-interactive backend to properly import matplotlib.pyplot
matplotlib.use(Config.MPL_NONINTERACTIVE(notify=False))
import matplotlib.pyplot as plt


### ===================================================================================================================
###   2. Function viia_sra
### ===================================================================================================================

[docs]def viia_sra( project: ViiaProject, sra_tb_file: str, check_nodes: Dict, single_graph: bool = False, base_signals: bool = False, response_spectrum: bool = False, result_item: str = 'accelerations'): """ This function reads the acceleration output of the reference points and creates graphs to visualise the results. The graphs can be imported to the Engineering Report. The accelarations can be plotted versus time, or the response spectrum can be calculated with this function. Input: - project (obj): Project object containing collections and of fem objects and project variables. - sra_tb_file(str): Name of the file, and contains the complete folder and type in the string. If set to None, the results are already read and set in the results dictionary. Renewed data entrance can be omitted. This is useful (will speed up) if function is performed more than one time in a mainscript. - check_nodes (dict): Keys (int) are the nodes for which the graph needs to be created. The nodes should be in the file with the results. Values (str) are the descriptions of the reference node that will be entered in the legend of the graph. - singe_graph (bool): X-, y- and z-direction are plotted in one graph if set to 'True'. Default value is 'False' which will create a figure with 3 graphs, each graph containing the accelerations in respectively x-, y- and z-direction. - base_signals (bool): The site specific site respons spectrum analysis has been performed for a free field situation (this calculation is called the soilcolumn calculation). The results of this analysis is the base acceleration signal that is used in flexbase calculations. These accelerations will be added to the graph. The signals need to be present in the 'TimeseriesCombinationSet' class. - response_spectrum (bool): The results can be given for a response spectrum analysis with the signal as input. Default setting is to plot the timesignal. The response spectrum analysis will take some time to finish. - result_item (str): By default the function plots the accelerations, but by changing the result_item to 'displacements', the displacements are plotted. Output: - A figure with the requested items is created and saved in the analysisfolder. - The DIANA resultfile is saved as csv file for use in excel. """ def _viiaMakeListOfText(string): str_list = string.replace('\n', '').replace(' ', ' ').replace(' ', ' ').replace(' ', ' '). \ replace(' ', ' ').replace(' ', ' ').split(' ') if str_list[0] == '': del str_list[0] if str_list[-1] == '' and len(str_list) > 1: del str_list[-1] return str_list check_nodes = deepcopy(check_nodes) if sra_tb_file: # Read file if '.tb' not in sra_tb_file: raise FileNotFoundError( "ERROR: Output 3 with accelerations not found in directory, make sure it is there and that it is " f"called 'X_OUTPUT_3.tb'.") lines = fem_read_file(file=sra_tb_file) if not lines: return # Read the tabulated output file results = {} phase = 0 factor = 0 step = 0 time = 0.0 result = None result_type = None for i, line in enumerate(lines): text = _viiaMakeListOfText(line) # Get the settings for the following result items if 'Phase nr.' in line: phase = int(text[2]) elif 'Step nr' in line: step = int(text[2]) elif 'Time' in line: time = float(text[1]) result_type = 'timesteps' elif 'Load factor' in line: factor = float(text[2]) result_type = 'loadsteps' elif 'Result' in line: if 'DISPLA' in line: result = 'displacements' elif 'ACCELE' in line: result = 'accelerations' else: result = None # Get the values from line (key should be already assigned if len(text) == 4 and text[0].isdecimal(): node = int(text[0]) if result: if node not in results: results[node] = {} if step not in results[node]: results[node][step] = {} if result_type == 'loadsteps': results[node][step]['load'] = factor elif result_type == 'timesteps': results[node][step]['time'] = time results[node][step]['phase'] = phase results[node][step][result] = [float(text[1]), float(text[2]), float(text[3])] # Save result items in 'project.results' analysis = project.LatestDCFfile.split('\\')[-1].split('-')[-1].split('.dcf')[0] if analysis not in project.Results: project.results[analysis] = {} if project.project_specific['signal']['current signal'] not in project.results[analysis]: project.results[analysis][project.project_specific['signal']['current signal']] = {} if 'SRA' not in project.results[analysis][project.project_specific['signal']['current signal']]: project.results[analysis][project.project_specific['signal']['current signal']]['SRA'] = results else: for node in results: if node in project.results[analysis][project.project_specific['signal']['current signal']]['SRA']: for step in results[node]: if step in \ project.results[analysis][project.project_specific['signal']['current signal']]['SRA'][ node]: for key in results[node][step]: if key not in \ project.results[analysis][project.project_specific['signal']['current signal']][ 'SRA'][node][step]: project.results[analysis][project.project_specific['signal']['current signal']][ 'SRA'][node][step][key] = \ results[node][step][key] else: project.results[analysis][project.project_specific['signal']['current signal']]['SRA'][ node][step] = results[node][step] else: project.results[analysis][project.project_specific['signal']['current signal']]['SRA'][node] = \ results[node] # Write results to csv-file and save to analysisfolder relative_path = project.current_analysis_folder.split(Path.cwd() + '\\')[1] file_name = relative_path + project.LatestDCFfile.split('\\')[-1].split('.dcf')[0] + '_accelerations_' + \ project.project_specific['signal']['current signal'] + '.csv' f = open(file_name, 'w') f.write('ACCELERATIONS:') for node in results: for step in results[node]: if 'time' in results[node][step] and 'accelerations' in results[node][step]: f.write('{:.2e}'.format(results[node][step]['time']) + ', ' + str(node) + ', ' + '{:.5e}'.format(results[node][step]['accelerations'][0]) + ', ' + '{:.5e}'.format(results[node][step]['accelerations'][1]) + ', ' + '{:.5e}'.format(results[node][step]['accelerations'][2]) + '\n') f.write('DISPLACEMENTS:') for node in results: for step in results[node]: if 'time' in results[node][step] and 'displacements' in results[node][step]: f.write('{:.2e}'.format(results[node][step]['time']) + ', ' + str(node) + ', ' + '{:.5e}'.format(results[node][step]['displacements'][0]) + ', ' + '{:.5e}'.format(results[node][step]['displacements'][1]) + ', ' + '{:.5e}'.format(results[node][step]['displacements'][2]) + '\n') # Use results from dictionary results else: analysis = project.LatestDCFfile.split(' - ')[0] results = project.results[analysis][project.project_specific['signal']['current signal']]['SRA'] # Check input requested nodes and remove results from other nodes for checkNode in check_nodes: if checkNode not in results: project.write_log( f"WARNING: Node {checkNode} can not be found in result items. This node will not be plotted.") for node in list(results.keys()): if node not in check_nodes: del results[node] if len(results.keys()) == 0 and not base_signals: project.write_log("ERROR: No nodes found to be plotted. Check your input.") return # Create lists of result item accelerations time_list = {} result_list_x = {} result_list_y = {} result_list_z = {} for node in results: time_list[node] = [] result_list_x[node] = [] result_list_y[node] = [] result_list_z[node] = [] for step in results[node]: if 'time' in results[node][step]: time_list[node].append(results[node][step]['time']) if result_item == 'displacements': result_list_x[node].append(results[node][step]['displacements'][0]) result_list_y[node].append(results[node][step]['displacements'][1]) result_list_z[node].append(results[node][step]['displacements'][2]) else: # default value 'accelerations' result_list_x[node].append(results[node][step]['accelerations'][0]) result_list_y[node].append(results[node][step]['accelerations'][1]) result_list_z[node].append(results[node][step]['accelerations'][2]) # Add site response if requested if base_signals: current_cluster = project.project_information['cluster_nen'] current_signal = project.project_specific['signal']['current signal'] for timeseries_combination_set in project.collections.timeseries_combination_sets: if timeseries_combination_set.name.split('_')[-1] == 'cluster' + current_cluster: time_list['SRA'] = deepcopy(timeseries_combination_set.get_timeseries_combination( f'base_signal_{current_signal}').x_direction.time_series) result_list_x['SRA'] = deepcopy(timeseries_combination_set.get_timeseries_combination( f'base_signal_{current_signal}').x_direction.value_series) result_list_y['SRA'] = deepcopy(timeseries_combination_set.get_timeseries_combination( f'base_signal_{current_signal}').y_direction.value_series) result_list_z['SRA'] = deepcopy(timeseries_combination_set.get_timeseries_combination( f'base_signal_{current_signal}').z_direction.value_series) check_nodes['SRA'] = 'Controle punt locatie-specifieke SRA' # If a response spectrum output is requested, the result items will be changed in this function only to response # spectrum values if response_spectrum: for node in result_list_x: response_spectrum_tab = fem_convert_signal_responsespectrum( time_list=time_list[node], acceleration_list=result_list_x[node], gravitational_acceleration=project.gravitational_acceleration) result_list_x[node] = [] for period in response_spectrum_tab: result_list_x[node].append(response_spectrum_tab[period][8]) response_spectrum_tab = fem_convert_signal_responsespectrum( time_list=time_list[node], acceleration_list=result_list_y[node], gravitational_acceleration=project.gravitational_acceleration) result_list_y[node] = [] for period in response_spectrum_tab: result_list_y[node].append(response_spectrum_tab[period][8]) response_spectrum_tab = fem_convert_signal_responsespectrum( time_list=time_list[node], acceleration_list=result_list_z[node], gravitational_acceleration=project.gravitational_acceleration) result_list_z[node] = [] time_list[node] = [] for period in response_spectrum_tab: result_list_z[node].append(response_spectrum_tab[period][8]) time_list[node].append(response_spectrum_tab[period][0]) # In case of displacements graphs are in mm if result_item == 'displacements': for node in result_list_x: for i, result in enumerate(result_list_x[node]): result_list_x[node][i] = result * 1000 for node in result_list_y: for i, result in enumerate(result_list_y[node]): result_list_y[node][i] = result * 1000 for node in result_list_z: for i, result in enumerate(result_list_z[node]): result_list_z[node][i] = result * 1000 # Create a list with minimum and maximum values minmaxList = {} for node in result_list_x: minmaxList[node] = { 'minX': min(result_list_x[node]), 'minY': min(result_list_y[node]), 'minZ': min(result_list_z[node]), 'maxX': max(result_list_x[node]), 'maxY': max(result_list_y[node]), 'maxZ': max(result_list_z[node])} # Determine the size of the scale on the x- and y-axis of the graph min_ygraph = [] max_ygraph = [] min_xgraph = [] max_xgraph = [] for node in check_nodes: min_ygraph.append(minmaxList[node]['minX']) min_ygraph.append(minmaxList[node]['minY']) min_ygraph.append(minmaxList[node]['minZ']) max_ygraph.append(minmaxList[node]['maxX']) max_ygraph.append(minmaxList[node]['maxY']) max_ygraph.append(minmaxList[node]['maxZ']) min_xgraph.append(min(time_list[node])) max_xgraph.append(max(time_list[node])) min_ygraph = min(min_ygraph) max_ygraph = max(max_ygraph) min_xgraph = min(min_xgraph) max_xgraph = max(max_xgraph) if response_spectrum: ygraph = [0, max(max_ygraph, -min_ygraph) * 1.1] xgraph = [min_xgraph, max_xgraph] else: ygraph = [-max(max_ygraph, -min_ygraph) * 1.1, max(max_ygraph, -min_ygraph) * 1.1] xgraph = [min_xgraph, max_xgraph + 0.5] if not single_graph: # Create the graph (close existing previous ones) plt.close() plt.figure(figsize=(15, 15)) # Apply VIIA graph style style_file = Path(project.viia_settings.project_specific_package_location) / 'viiaGraph.mplstyle' plt.style.use(style_file.as_posix()) ax1 = plt.subplot(3, 1, 1) for node in check_nodes: if node == 'SRA': ax1.plot(time_list[node], result_list_x[node], linestyle='--', color='#004080') else: ax1.plot(time_list[node], result_list_x[node]) ax1.set_xlim(xgraph[0], xgraph[1]) ax1.set_ylim(ygraph[0], ygraph[1]) ax1.spines['bottom'].set_position('zero') if result_item == 'displacements': plt.ylabel('Verplaatsingen x-richting [mm]') if response_spectrum: plt.title('Respons spectrum verplaatsingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.', fontsize=20) else: plt.title('Verplaatsingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.', fontsize=20) else: plt.ylabel('Versnellingen x-richting [m/s2]') if response_spectrum: plt.title('Respons spectrum versnellingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.', fontsize=20) else: plt.title('Versnellingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.', fontsize=20) ax2 = plt.subplot(3, 1, 2) for node in check_nodes: if node == 'SRA': ax2.plot(time_list[node], result_list_y[node], linestyle='--', color='#004080') else: ax2.plot(time_list[node], result_list_y[node]) ax2.set_xlim(xgraph[0], xgraph[1]) ax2.set_ylim(ygraph[0], ygraph[1]) ax2.spines['bottom'].set_position('zero') if result_item == 'displacements': plt.ylabel('Verplaatsingen y-richting [mm]') else: plt.ylabel('Versnellingen y-richting [m/s2]') ax3 = plt.subplot(3, 1, 3) for node in check_nodes: if node == 'SRA': ax3.plot(time_list[node], result_list_z[node], linestyle='--', color='#004080', label=str(node)) else: ax3.plot(time_list[node], result_list_z[node], label=str(node)) ax3.set_xlim(xgraph[0], xgraph[1]) ax3.set_ylim(ygraph[0], ygraph[1]) ax3.spines['bottom'].set_position('zero') if result_item == 'displacements': plt.ylabel('Verplaatsingen z-richting [mm]') else: plt.ylabel('Versnellingen z-richting [m/s2]') if response_spectrum: plt.xlabel('Eigen periode [s]') else: plt.xlabel('Tijd [s]') plt.legend(loc='lower right') # Save the graph to the same folder if result_item == 'displacements': plt.savefig(project.current_analysis_folder + '/SRA-Verplaatsingen' + str(len(check_nodes)) + '.png') else: plt.savefig(project.current_analysis_folder + '/SRA-Versnellingen' + str(len(check_nodes)) + '.png') else: # Create the graph (close existing previous ones plt.close() plt.figure(figsize=(15, 5)) # Apply VIIA graph style style_file = Path(project.viia_settings.project_specific_package_location) / 'viiaGraph.mplstyle' plt.style.use(style_file.as_posix()) ax1 = plt.subplot(1, 1, 1) for node in check_nodes: if (len(check_nodes.keys()) == 1 and not base_signals) or (len(check_nodes.keys()) == 2 and base_signals): if node == 'SRA': ax1.plot( time_list[node], result_list_x[node], linestyle='--', color='#004080', label='x-richting SRA') ax1.plot( time_list[node], result_list_y[node], linestyle='--', color='#E24A33', label='y-richting SRA') ax1.plot( time_list[node], result_list_z[node], linestyle='--', color='#777777', label='z-richting SRA') else: ax1.plot(time_list[node], result_list_x[node], label='x-richting') ax1.plot(time_list[node], result_list_y[node], label='y-richting') ax1.plot(time_list[node], result_list_z[node], label='z-richting') else: if node == 'SRA': ax1.plot(time_list[node], result_list_x[node], linestyle='--', label='x-richting (' + str(node) + ')', color='#004080') ax1.plot(time_list[node], result_list_y[node], linestyle='--', label='x-richting (' + str(node) + ')', color='#E24A33') ax1.plot(time_list[node], result_list_z[node], linestyle='--', label='x-richting (' + str(node) + ')', color='#777777') else: ax1.plot(time_list[node], result_list_x[node], label='x-richting (' + str(node) + ')') ax1.plot(time_list[node], result_list_y[node], label='y-richting (' + str(node) + ')') ax1.plot(time_list[node], result_list_z[node], label='z-richting (' + str(node) + ')') ax1.set_xlim(xgraph[0], xgraph[1]) ax1.set_ylim(ygraph[0], ygraph[1]) ax1.spines['bottom'].set_position('zero') current_signal = project.project_specific['signal']['current signal'] signal_name = project.project_specific['signal'][current_signal] if result_item == 'displacements': plt.ylabel('Verplaatsingen [mm]') if (len(check_nodes.keys()) == 1 and not base_signals) or (len(check_nodes.keys()) == 2 and base_signals): if response_spectrum: plt.title(f'Respons spectrum verplaatsingen {check_nodes[node]} {signal_name.lower()}.') else: plt.title(f'Verplaatsingen {check_nodes[node]} {signal_name.lower()}.') else: if response_spectrum: plt.title('Respons spectrum verplaatsingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.') else: plt.title('Verplaatsingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.') else: plt.ylabel('Versnellingen [m/s2]') if (len(check_nodes.keys()) == 1 and not base_signals) or (len(check_nodes.keys()) == 2 and base_signals): if response_spectrum: plt.title('Respons spectrum versnellingen ' + check_nodes[node] + ' ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.') else: plt.title('Versnellingen ' + check_nodes[node] + ' ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.') else: if response_spectrum: plt.title('Respons spectrum versnellingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.') else: plt.title('Versnellingen referentiepunten ' + project.SignalNamesRef[ project.project_specific['signal']['current signal']].lower() + '.') if response_spectrum: ax1.set_xlabel('Eigen periode [s]') else: ax1.set_xlabel('Tijd [s]') ax1.xaxis.set_label_position('bottom') plt.legend(loc='upper right') # Save the graph to the same folder if result_item == 'displacements': plt.savefig(project.current_analysis_folder + '/SRA-Verplaatsingen-singleGraph.png') else: plt.savefig(project.current_analysis_folder + '/SRA-Versnellingen-singleGraph.png')
### =================================================================================================================== ### 3. End of script ### ===================================================================================================================