Source code for viiapackage.results.result_functions.viia_pile_reactions

### ===================================================================================================================
###   Function to collect the results for the piles
### ===================================================================================================================
# Copyright ©VIIA 2024

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

# General imports
from __future__ import annotations
import json
from pathlib import Path
from typing import TYPE_CHECKING, List, Dict, Optional

# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.fem_config import Config
from rhdhv_fem.fem_json import fem_create_creation_info
from rhdhv_fem.fem_tools import fem_create_folder
from rhdhv_fem.analyses import Analysis, SteppedAnalysisReference, StaticAnalysisReference
from rhdhv_fem.fem_math import fem_compare_values

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

# 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_collect_pile_reactions
### ===================================================================================================================

[docs]def viia_collect_pile_reactions( project: ViiaProject, pile_output_file: Path, analysis: Analysis, signal: Optional[str] = None) -> Path: """ This function collects the pile forces from the DIANA output file, creates graphs per pile with the forces over time, and it creates a json-file with the collect information that can be used for reporting. Input: - project (obj): Project object containing collections and of fem objects and project variables. - pile_output_file (Path): Path to the OUTPUT_5B tb-file from DIANA NLTH analysis. - analysis (obj): Object reference of the NLTH analysis. - signal (str): String representing the signal, can be S1 to S11. Output: - Returns the folder with the created results for the piles. """ # Read the tb-file project.read_diana_tbfile(file=pile_output_file, analysis=analysis) # Loop through the supports to collect all the piles and the related pile outputs reaction_forces = {} for support in project.collections.supports: for connecting_shapes in support.connecting_shapes: pile = connecting_shapes['connecting_shape'] if pile.name not in reaction_forces: reaction_forces[pile.name] = {} # Check which node is the top node of the pile shape in the model if pile.contour.get_top_node() is pile.get_nodes()[0]: nr = 0 else: nr = 1 # For fixed base analysis the bottom node is used instead if any([item in analysis.name for item in ['A1 -', 'A4 -']]): nr = abs(nr - 1) # Collect the output-items output_items = ['F_x_tot', 'F_y_tot', 'F_z_tot'] if any([item in analysis.name for item in ['A4', 'A12', 'A15']]): output_items.extend(['U_x_tot', 'U_y_tot', 'U_z_tot']) for output_item in output_items: for result_collection in pile.results.get_result_collections(output_item=output_item): if result_collection.analysis_reference.analysis is not analysis: continue # Static analysis results if isinstance(result_collection.analysis_reference, StaticAnalysisReference): loading = result_collection.analysis_reference.loading.name if loading not in reaction_forces[pile.name]: reaction_forces[pile.name][loading] = {} if output_item not in reaction_forces[pile.name][loading]: # In fixed base the bottom node of the pile shape is used reaction_forces[pile.name][loading][output_item] = result_collection.node_results[nr] # Stepped analysis results elif isinstance(result_collection.analysis_reference, SteppedAnalysisReference): step_type = result_collection.analysis_reference.calculation_block.step_type( step=result_collection.analysis_reference.step_nr) step_value = result_collection.analysis_reference.calculation_block.step_value( step=result_collection.analysis_reference.step_nr) # Non-linear static analysis if step_type == 'LoadSteps' and \ fem_compare_values(step_value, 1.0, precision=project.check_precision): if 'VAR' not in reaction_forces[pile.name]: reaction_forces[pile.name]['VAR'] = {} reaction_forces[pile.name]['VAR'][output_item] = result_collection.node_results[nr] elif step_type == 'StartSteps' and 'A10 -' in analysis.name or 'A13 -' in analysis.name and \ fem_compare_values(step_value, 1.0, precision=project.check_precision): if 'DL' not in reaction_forces[pile.name]: reaction_forces[pile.name]['DL'] = {} reaction_forces[pile.name]['DL'][output_item] = result_collection.node_results[nr] # Non-linear time-history analysis elif step_type == 'StartSteps' and \ fem_compare_values(step_value, 1.0, precision=project.check_precision): if output_item not in reaction_forces[pile.name]: reaction_forces[pile.name][output_item] = {'times': [], 'values': []} # Only collect the last start-step (if there are multiple) # This step is set as the 0.0 sec step reaction_forces[pile.name][output_item]['times'].append(0.0) reaction_forces[pile.name][output_item]['values'].append(result_collection.node_results[nr]) elif step_type == 'TimeSteps': reaction_forces[pile.name][output_item]['times'].append(step_value) reaction_forces[pile.name][output_item]['values'].append(result_collection.node_results[nr]) # Create folder for the pile results folder = project.current_analysis_folder / 'Pile_reactions' fem_create_folder(folder) # Collect any material proper # Create json-file with data json_file = viia_create_pile_reactions_json( data=reaction_forces, output_folder=folder, analysis=analysis, analysis_folder=project.current_analysis_folder, signal=signal) if not json_file.exists(): raise ValueError("ERROR: The json-file was not created correctly, please check.") # Create plots per pile for NLTH analysis if any([item in analysis.name for item in ['A4', 'A12', 'A15']]): for pile, pile_data in reaction_forces.items(): viia_create_pile_reaction_graph( project=project, time_values=pile_data['F_x_tot']['times'], x_values=pile_data['F_x_tot']['values'], y_values=pile_data['F_y_tot']['values'], z_values=pile_data['F_z_tot']['values'], pile_name=pile, output_folder=folder, signal=signal, analysis=analysis) # Return the folder with the pile results return folder
### =================================================================================================================== ### 3. Function to create the pile results json-file for VIIA ### ===================================================================================================================
[docs]def viia_create_pile_reactions_json( data: Dict[str, Dict[str, List[float]]], output_folder: Path, analysis: Analysis, analysis_folder: Path, signal: Optional[str] = None) -> Path: """ Function to store the results of the wall displacements (in VIIA format) in a json-file in the current analysis folder. Input: - data (dict): Dictionary with the data of the pile results. - output_folder (Path): Folder where the json should be saved. Output: - Generates a json-file in the current analysis-folder with the data of the pile reactions. - Returns the path of the file created. """ # Create generic info on the analysis creation_info = fem_create_creation_info()[0] creation_info['analysis'] = analysis.name if signal: creation_info['signal'] = signal creation_info['analysis_timestamp'] = analysis_folder.name creation_info['viiaPackage'] = __version__ # Add the generic info to the data data = {Config.JSON_INFO: [creation_info]} | data # Create json-file dump dumpfile = output_folder / 'pile_reactions.json' with open(dumpfile, 'w') as fd: json.dump(data, fd, indent=2, sort_keys=True) return dumpfile
### =================================================================================================================== ### 4. Function to create the pile reaction graph ### ===================================================================================================================
[docs]def viia_create_pile_reaction_graph( project: ViiaProject, time_values: List[float], x_values: List[float], y_values: List[float], z_values: List[float], pile_name: str, output_folder: Path, analysis: Analysis, signal: str) -> Path: """ This function creates the ssi plot.""" # Initiate plot plt.close() # Apply VIIA graph style plt.style.use(project.viia_settings.graph_style_sheet.as_posix()) # Plot the values fig, axs = plt.subplots(3, 1, figsize=(project.viia_settings.GRAPH_WIDTH, project.viia_settings.GRAPH_HEIGHT + 4)) # Add plots of data axs[0].plot(time_values, [val/1E3 for val in x_values], alpha=0.7) axs[0].set_ylabel('F$_{x}$ [kN]') axs[1].plot(time_values, [val/1E3 for val in y_values], alpha=0.7) axs[1].set_ylabel('F$_{y}$ [kN]') axs[2].plot(time_values, [val/1E3 for val in z_values], alpha=0.7) axs[2].set_ylabel('F$_{z}$ [kN]') axs[2].set_xlabel('Time [ms]') # Set the three graphs with same scale limit = 0 values = [x_values, y_values, z_values] for value_series in values: average = sum(value_series) / len(value_series) dir_limit = max(abs(max(value_series) - average), abs(min(value_series) - average)) if dir_limit > limit: limit = dir_limit limit *= 1.05 for i, ax in enumerate(axs): average = sum(values[i]) / len(values[i]) ax.set_ylim((average - limit)/1e3, (average + limit)/1e3) # Set the title fig.suptitle(f'Reaction forces pile {pile_name} | {analysis.name} ({signal})') # Create the graph file = output_folder / f'{pile_name}.png' fig.savefig(file, format='png') plt.close() # Return the file with the image of the graph that was created return file
### =================================================================================================================== ### 5. End of script ### ===================================================================================================================