Source code for viiapackage.results.result_functions.viia_foundation_behaviour_report

### ===================================================================================================================
###   Functions to check the foundation behaviour in the NLTH analysis
### ===================================================================================================================
# Copyright ©VIIA 2025

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

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

# References for functions and classes in the haskoning_datafusr_py_base package
from haskoning_datafusr_py_base.reporting import datafusr_convert_docx_to_pdf

# References for functions and classes in the haskoning_structural package
from haskoning_structural.analyses import Analysis
from haskoning_structural.plots import fem_start_plot, fem_save_plot
from haskoning_structural.fem_config import Config
from haskoning_structural.fem_tools import fem_si_unit_conversion_factor, fem_create_folder

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

# 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. Collect the results required for the foundation behaviour report
### ===================================================================================================================

[docs]def viia_collect_data_shallow_foundation(project: ViiaProject, analysis: Analysis) -> Dict[str, Dict[str, List[float]]]: """ This function collects the results for the shallow foundation reference elements in the project. The results are collected per reference element. Collecting the results for the relative displacements and stresses in the boundary interface (refer to the modeling approach for shallow foundation in the VIIA project). Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - analysis (obj): Analysis object of the analysis for which the report is generated. This should be the NLTH analysis (A4, A12 or A15). The results of this analysis should be present in the current analysis folder. Output: - Returns a dictionary with the results per reference element. Key is the name of the reference element (which includes the name of the boundary interface), the value is a dictionary with the arrays for the relative displacements (strains) and stresses (tractions) in x-, y- and z-direction. The lists contain the values and a separate entry for the time values per output-item. """ data = {} # Find the output-block in the analysis that defines the reference elements output_block = None for ob in analysis.get_all_output_blocks(): if ob.name == 'OUTPUT_GEO_REF': output_block = ob break if output_block is None: return data # Collect the results per reference element in the output-block for mesh_element in output_block.manual_elements: # Check if the requested reference element is actually part of the shallow foundation if mesh_element.mesh_type != 'interface': continue mesh = mesh_element.get_mesh() connection = mesh.get_connection() if connection is None or 'FOS' not in connection.name: continue # Prepare for the data collection combined_name = f"{connection.name}-Element-{mesh_element.id}" if combined_name not in data: data[combined_name] = {} # Collect the results per direction for direction in ['x', 'y', 'z']: data[combined_name][f'{direction}-displacements'] = [] data[combined_name][f'{direction}-displacements-time'] = [] data[combined_name][f'{direction}-stresses'] = [] data[combined_name][f'{direction}-stresses-time'] = [] # Find the results for the displacements in the direction of the interface result_collections = sorted( [rc for rc in connection.results.result_collections if rc.output_item.engineering_notation == f'du_{direction}_tot_intp'], key=lambda r: r.analysis_reference.step_nr) # Collect the results in lists (time and displacement) # The relative displacement (strain) is calculated as the average of the results on the integration points for result_collection in result_collections: if mesh_element not in result_collection.result_dictionary.results: continue if result_collection.analysis_reference.meta_data and \ 'time' in result_collection.analysis_reference.meta_data: data[combined_name][f'{direction}-displacements-time'].append( result_collection.analysis_reference.meta_data['time']) else: data[combined_name][f'{direction}-displacements-time'].append(0) result_dict = result_collection.result_dictionary.results[mesh_element] if not result_dict or len(result_dict) == 0: raise KeyError( f"ERROR: Unexpected error occurred, the result dictionary is empty for result-collection" f"{result_collection.unique_id}.") data[combined_name][f'{direction}-displacements'].append(sum(result_dict.values()) / len(result_dict)) # Find the results for the stresses in the direction of the interface result_collections = sorted( [rc for rc in connection.results.result_collections if rc.output_item.engineering_notation == f't_{direction}_tot_intp'], key=lambda r: r.analysis_reference.step_nr) # Collect the results in lists (time and stresses) # The stress (traction) is calculated as the average of the results on the integration points for result_collection in result_collections: if mesh_element not in result_collection.result_dictionary.results: continue if result_collection.analysis_reference.meta_data and \ 'time' in result_collection.analysis_reference.meta_data: data[combined_name][f'{direction}-stresses-time'].append( result_collection.analysis_reference.meta_data['time']) else: data[combined_name][f'{direction}-stresses-time'].append(0) result_dict = result_collection.result_dictionary.results[mesh_element] if not result_dict or len(result_dict) == 0: raise KeyError( f"ERROR: Unexpected error occurred, the result dictionary is empty for result-collection" f"{result_collection.unique_id}.") data[combined_name][f'{direction}-stresses'].append(sum(result_dict.values()) / len(result_dict)) # Return the collected data return data
[docs]def viia_collect_data_pile_foundation(project: ViiaProject) -> Dict[str, Dict[str, List[float]]]: """ This function collects the results for the relative displacements and forces in the pile springs (refer to the modeling approach for piles in the VIIA project). The results are collected per pile. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. Output: - Returns a dictionary with the results per pile. Key is the pile-name, the value is a dictionary with the arrays for the displacements and forces in x-, y- and z-direction. The lists contain the values and a separate entry for the time values per output-item. """ data = {} for pile in project.collections.piles: # Simplify identifier of pile name pile_name = f'Pile {pile.id}' if pile_name not in data: data[pile_name] = {} # Function loops through piles and checks for the translational springs connecting to the pile object, according # the modelling approach in VIIA project. The FCRITX, FCRITY and FCRITZ springs are used to collect the data. # If the spring is not found, no data is collected and function continues for next connection of the pile. for direction in ['x', 'y', 'z']: connection = None for pile_connection in pile.connections: if f'FCRIT{direction.upper()}' in pile_connection.name: connection = pile_connection break if not connection: continue data[pile_name][f'{direction}-displacements'] = [] data[pile_name][f'{direction}-displacements-time'] = [] data[pile_name][f'{direction}-forces'] = [] data[pile_name][f'{direction}-forces-time'] = [] # To collect the correct results the top- and bottom node of the spring is collected top_node = connection.mesh.get_top_meshnode()[0] bottom_node = connection.mesh.get_bottom_meshnode()[0] # Find the results for the displacements in the direction of the spring result_collections = sorted( [rc for rc in connection.results.result_collections if rc.output_item.engineering_notation == f'U_{direction}_tot'], key=lambda r: r.analysis_reference.step_nr) # Collect the results in lists (time and displacement) # The relative displacement is calculated as the difference between the top and bottom node for result_collection in result_collections: if result_collection.analysis_reference.meta_data and \ 'time' in result_collection.analysis_reference.meta_data: data[pile_name][f'{direction}-displacements-time'].append( result_collection.analysis_reference.meta_data['time']) else: data[pile_name][f'{direction}-displacements-time'].append(0) data[pile_name][f'{direction}-displacements'].append( result_collection.result_dictionary.results[top_node] - result_collection.result_dictionary.results[bottom_node]) # Find the results for the forces in the direction of the spring result_collections = sorted( [rc for rc in connection.results.result_collections if rc.output_item.engineering_notation == f'F_{direction}_tot'], key=lambda r: r.analysis_reference.step_nr) # Collect the results in lists (time and force) # The reaction force is the nodal force at the top node of the spring for result_collection in result_collections: if result_collection.analysis_reference.meta_data and \ 'time' in result_collection.analysis_reference.meta_data: data[pile_name][f'{direction}-forces-time'].append( result_collection.analysis_reference.meta_data['time']) else: data[pile_name][f'{direction}-forces-time'].append(0) data[pile_name][f'{direction}-forces'].append(result_collection.result_dictionary.results[top_node]) # Return the collected data return data
### =================================================================================================================== ### 3. Create the graphs of the foundation behaviour ### ===================================================================================================================
[docs]def create_plot( project: ViiaProject, data: Dict[str, List[float]], direction: str, x: str, y: str, label_y: str, output_folder: Path, name: str, label_x: str = 'Time [s]', factor_x: float = 1, factor_y: float = 1) \ -> Optional[Path]: """ Sub-function to create the plots for the foundation behaviour report.""" # Constants PLOT_WIDTH_CM = 17.5 * 2 PLOT_HEIGHT_CM = 5.0 * 2 CM_TO_INCH = 2.54 def _convert_unit(d: List[float], factor: float) -> List[float]: """ Helper function to multiply all values of list with the provided factor.""" return [value * factor for value in d] # Apply VIIA graph style style_file = Path(project.viia_settings.project_specific_package_location) / 'viiaGraph.mplstyle' # Create the figure for the plot if x == 'time': width = PLOT_WIDTH_CM / CM_TO_INCH height = PLOT_HEIGHT_CM / CM_TO_INCH else: width = PLOT_WIDTH_CM / CM_TO_INCH / 3 height = width fem_start_plot(project, width=width, height=height, show=False, style_file=style_file) # Create the graph in the plot ax1 = plt.subplot2grid((1, 1), (0, 0)) if x == 'time': if direction == 'xy': ax1.plot(data[f'x-{y}-time'], _convert_unit(d=data[f'x-{y}'], factor=factor_y), label='x') ax1.plot(data[f'y-{y}-time'], _convert_unit(d=data[f'y-{y}'], factor=factor_y), label='y') else: ax1.plot( data[f'{direction}-{y}-time'], _convert_unit(d=data[f'{direction}-{y}'], factor=factor_y), label=direction) else: if direction == 'xy': ax1.plot( _convert_unit(d=data[f'x-{x}'], factor=factor_x), _convert_unit(d=data[f'x-{y}'], factor=factor_y), label='x') ax1.plot( _convert_unit(d=data[f'y-{x}'], factor=factor_x), _convert_unit(d=data[f'y-{y}'], factor=factor_y), label='y') else: ax1.plot( _convert_unit(d=data[f'{direction}-{x}'], factor=factor_x), _convert_unit(d=data[f'{direction}-{y}'], factor=factor_y), label=direction) plt.xlabel(label_x) if 'N/mm2' in label_y: label = label_y.replace('N/mm2', 'N/mm$\mathrm{^2}$') plt.ylabel(label) else: plt.ylabel(label_y) plt.legend() file_name = f'{name}_{x}_vs_{y}_{direction}' file = fem_save_plot(project=project, show=False, file_name=file_name, save_folder=output_folder, dpi=200) if file.exists(): return file project.write_log( f"WARNING: The foundation behaviour graph could not be created. Plot file {file.as_posix()} could not be " f"saved.") return None
[docs]def viia_plot_shallow_foundation_behaviour_per_element( project: ViiaProject, element: str, data: Dict[str, List[float]], output_folder: Path, unit_traction: str = 'N/mm2', unit_relative_displacement: str = 'mm') -> List[Optional[Path]]: """ This function creates graphs of the stresses and displacements of the element in the shallow foundation. For these reference elements the relative displacements and the tractions are collected in DIANA software per timestep in the NLTH analysis. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - element (str): Combined name of the element, combines the name of the boundary interface and the mesh-element number. - data (dict): Dictionary with the results per reference element. Key is the name of the reference element (which includes the name of the boundary interface), the value is a dictionary with the arrays for the relative displacements (strains) and stresses (tractions) in x-, y- and z-direction. The lists contain the values and a separate entry for the time values per output-item. - output_folder (path): Path of the folder where the plots of the graphs should be saved. - unit_traction (str): Unit in which the traction (stress) should be presented in the graphs. Default value is N/mm2. - unit_relative_displacement (str): Unit in which the relative displacement (strain) should be presented in the graphs. Default value is mm. Output: - Returns a list with the paths of the created graphs. If a graph could not be created, None is returned in the list. """ # Collect the created graphs created_graphs = [] # Calculate the conversion factor for the requested units factor_traction = fem_si_unit_conversion_factor(from_unit='N/m2', to_unit=unit_traction) factor_relative_displacement = fem_si_unit_conversion_factor(from_unit='m', to_unit=unit_relative_displacement) # Create graphs of the stresses and displacements in x- and y-direction created_graphs.append(create_plot( project=project, data=data, direction='xy', x='time', y='stresses', factor_y=factor_traction, label_y=f'Stress [{unit_traction}]', output_folder=output_folder, name=element)) created_graphs.append(create_plot( project=project, data=data, direction='xy', x='time', y='displacements', factor_y=factor_relative_displacement, label_y=f'Relative displacements [{unit_relative_displacement}]', output_folder=output_folder, name=element)) # Create graphs of the stresses and displacements in z-direction created_graphs.append(create_plot( project=project, data=data, direction='z', x='time', y='stresses', factor_y=factor_traction, label_y=f'Stress [{unit_traction}]', output_folder=output_folder, name=element)) created_graphs.append(create_plot( project=project, data=data, direction='z', x='time', y='displacements', factor_y=factor_relative_displacement, label_y=f'Relative displacements [{unit_relative_displacement}]', output_folder=output_folder, name=element)) # Create graphs of the stress-strain relations in x-, y- and z-direction for direction in ['x', 'y', 'z']: created_graphs.append(create_plot( project=project, data=data, direction=direction, x='displacements', y='stresses', factor_x=factor_relative_displacement, factor_y=factor_traction, label_x=f'Relative displacement [{unit_relative_displacement}]', label_y=f'Stress [{unit_traction}]', output_folder=output_folder, name=element)) # Check if all graphs were created, else provide warning in log if any([g is None for g in created_graphs]): project.write_log(f"WARNING: Not all graphs could be created for element {element}.") return created_graphs
[docs]def viia_plot_pile_foundation_behaviour_per_element( project: ViiaProject, element: str, data: Dict[str, List[float]], output_folder: Path, unit_force: str = 'kN', unit_relative_displacement: str = 'mm') -> List[Optional[Path]]: """ This function creates graphs of the stresses and displacements of the element in the shallow foundation. For these reference elements the relative displacements and the tractions are collected in DIANA software per timestep in the NLTH analysis. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - element (str): Combined name of the element, combines the name of the boundary interface and the mesh-element number. - data (dict): Dictionary with the results per reference element. Key is the name of the reference element (which includes the name of the boundary interface), the value is a dictionary with the arrays for the relative displacements (strains) and stresses (tractions) in x-, y- and z-direction. The lists contain the values and a separate entry for the time values per output-item. - output_folder (path): Path of the folder where the plots of the graphs should be saved. - unit_force (str): Unit in which the reaction force should be presented in the graphs. Default value is kN. - unit_relative_displacement (str): Unit in which the relative displacement should be presented in the graphs. Default value is mm. Output: - Returns a list with the paths of the created graphs. If a graph could not be created, None is returned in the list. """ # Collect the created graphs created_graphs = [] # Calculate the conversion factor for the requested units factor_force = fem_si_unit_conversion_factor(from_unit='N', to_unit=unit_force) factor_relative_displacement = fem_si_unit_conversion_factor(from_unit='m', to_unit=unit_relative_displacement) # Create graphs of the stresses and displacements in x- and y-direction created_graphs.append(create_plot( project=project, data=data, direction='xy', x='time', y='forces', factor_y=factor_force, label_y=f'Reaction force [{unit_force}]', output_folder=output_folder, name=element)) created_graphs.append(create_plot( project=project, data=data, direction='xy', x='time', y='displacements', factor_y=factor_relative_displacement, label_y=f'Relative displacements [{unit_relative_displacement}]', output_folder=output_folder, name=element)) # Create graphs of the stresses and displacements in z-direction created_graphs.append(create_plot( project=project, data=data, direction='z', x='time', y='forces', factor_y=factor_force, label_y=f'Reaction force [{unit_force}]', output_folder=output_folder, name=element)) created_graphs.append(create_plot( project=project, data=data, direction='z', x='time', y='displacements', factor_y=factor_relative_displacement, label_y=f'Relative displacements [{unit_relative_displacement}]', output_folder=output_folder, name=element)) # Create graphs of the stress-strain relations in x-, y- and z-direction for direction in ['x', 'y', 'z']: created_graphs.append(create_plot( project=project, data=data, direction=direction, x='displacements', y='forces', factor_x=factor_relative_displacement, factor_y=factor_force, label_x=f'Relative displacement [{unit_relative_displacement}]', label_y=f'Reaction force [{unit_force}]', output_folder=output_folder, name=element)) # Check if all graphs were created, else provide warning in log if any([g is None for g in created_graphs]): project.write_log(f"WARNING: Not all graphs could be created for pile {element}.") return created_graphs
### =================================================================================================================== ### 4. Function to generate report ### ===================================================================================================================
[docs]def viia_generate_foundation_behaviour_report( project: ViiaProject, shallow_foundation_data: Dict[str, Dict[str, List[float]]], pile_foundation_data: Dict[str, Dict[str, List[float]]], signal: str, analysis: Analysis, output_folder: Path) -> Optional[Path]: """ This function creates a report in pdf-format. This report contains detailed information on the behaviour of the foundation. Graphs and data are generated from NLTH analysis. In this function the data is processed and the report is generated based on the inputs. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - shallow_foundation_data (dict): Dictionary with the data from the selected reference points in the shallow foundation. The input dictionary is empty in case of a sole pile foundation. - pile_foundation_data (dict): Dictionary with the data from all piles in the model. The input dictionary is empty in case of a sole shallow foundation. - signal (str): Input of the signal number, to included signal in report. Can be S1-S11. Output: - Returns the path of the created report in pdf-format. If the report could not be created, the path of the Word document is returned. If also the Word document could not be generated None is returned. """ # Collect template file template_file = \ project.viia_settings.project_specific_package_location / 'results' / 'result_functions' / 'templates' / \ 'template_foundation_behaviour.docx' # Prepare for the target location cet_time = datetime.now(pytz.timezone('CET')) time_reference = cet_time.strftime('%Y%m%d%H%M%S') output_document_name = \ f"VIIA_{project.project_information['objectnummer_viia']}_Foundation_Behaviour_{time_reference}.docx" target_file = output_folder / output_document_name # Set the grid to be used for indicating the location of the reference points main_grid = project.find_grid() # Apply VIIA graph style style_file = Path(project.viia_settings.project_specific_package_location) / 'viiaGraph.mplstyle' # Collect data for sections per reference element in the shallow foundation if applicable shallow_foundation_elements = [] if shallow_foundation_data: for element, result_data in shallow_foundation_data.items(): # Create image for the location of the reference point on the foundation plot layer = project.viia_get(collection='layers', name='F') # Collect the mesh-element for which the results are shown in the report mesh_element = project.find(description=int(element.split('-')[-1]), collection='mesh_elements') fos_interface = project.find(description=element.split('-Element')[0], collection='connections') # Create the plot of the foundation layer.plot( grid=main_grid, shape_types='fstrips', background_shapes=True, show=False, save_folder=output_folder, file_name=element, keep_plot_open=True, style_file=style_file) # Add point on foundation plot to indicate the location of the reference element ax = plt.gca() ax.plot( mesh_element.mesh_nodes[0].coordinates[0], mesh_element.mesh_nodes[0].coordinates[1], 'ro', label=f"Reference element {mesh_element.id} ({element.split('-Element')[0]})", zorder=100) # Save the plot with the location of the reference element fem_save_plot(project=project, save=True, show=False, file_name=element, save_folder=output_folder) # Collect the information and names of the images for the report per reference element in the shallow # foundation shallow_foundation_elements.append({ 'name': element, 'id': mesh_element.id, 'foundation_strip_name': fos_interface.connecting_shapes['source_connecting_shape'].name, 'fos_name': fos_interface.name, 'location': element, 'stresses_xy': f'{element}_time_vs_stresses_xy', 'stresses_z': f'{element}_time_vs_stresses_z', 'relative_displacements_xy': f'{element}_time_vs_displacements_xy', 'relative_displacements_z': f'{element}_time_vs_displacements_z', 'stresses_displacements_x': f'{element}_displacements_vs_stresses_x', 'stresses_displacements_y': f'{element}_displacements_vs_stresses_y', 'stresses_displacements_z': f'{element}_displacements_vs_stresses_z'}) # Collect data for sections per pile in the pile foundation if applicable pile_foundation_elements = [] if pile_foundation_data: for element, result_data in pile_foundation_data.items(): # Create image for the location of the pile on the foundation plot layer = project.viia_get(collection='layers', name='F') # Collect the pile to plot the location of the pile on the foundation plot pile = project.find(description=int(element.split('Pile ')[-1]), collection='piles') mesh_node = pile.contour.get_top_node() # Create the plot of the foundation layer.plot( grid=main_grid, shape_types='fstrips', background_shapes=True, show=False, save_folder=output_folder, file_name=element, keep_plot_open=True, style_file=style_file) # Add point on foundation plot to indicate the location of the reference element ax = plt.gca() ax.plot( mesh_node.coordinates[0], mesh_node.coordinates[1], 'ro', label=f"Pile {pile.name}", zorder=100) # Save the plot with the location of the reference element fem_save_plot(project=project, save=True, show=False, file_name=element, save_folder=output_folder) # Get connecting fstrips t = pile.get_connections() spring = None for s in t: if '-FCRITZ' in s.name: spring = s break fstrip = '' if spring: fstrip = spring.connecting_shapes['target_connecting_shape'].name # Collect the information and names of the images for the report per reference element in the pile # foundation pile_foundation_elements.append({ 'name': element, 'id': pile.id, 'foundation_strip_name': fstrip, 'location': element, 'forces_xy': f'{element}_time_vs_forces_xy', 'forces_z': f'{element}_time_vs_forces_z', 'relative_displacements_xy': f'{element}_time_vs_displacements_xy', 'relative_displacements_z': f'{element}_time_vs_displacements_z', 'forces_displacements_x': f'{element}_displacements_vs_forces_x', 'forces_displacements_y': f'{element}_displacements_vs_forces_y', 'forces_displacements_z': f'{element}_displacements_vs_forces_z'}) # Collect the data to be added in the report report_data = { 'date': datetime.now().strftime("%Y-%m-%d"), 'project_name': project.name, 'analysis': analysis.name, 'analysis_nr': analysis.name, 'signal': signal, 'object_nr': project.name, 'analysis_id': project.current_analysis_folder.parent.name, 'images': output_folder.as_posix(), 'shallow_foundation': shallow_foundation_elements, 'pile_foundation': pile_foundation_elements} # Create the Word document of the report project.create_report(template_file=template_file, data=report_data, output_file=target_file, images=True) # Convert the Word document to pdf format output_file = None try: output_file = datafusr_convert_docx_to_pdf(docx_file=target_file, keep_docx=True) except Exception as e: project.write_log(f"WARNING: Some issue occurred in the conversion from docx to pdf, the error report is {e}.") # Check if the pdf-file is properly created and notify user if (output_file is None or not output_file.exists()) and target_file.exists(): project.write_log( f"WARNING: The detailed report in pdf-format with the results for the foundation behaviour checks could " f"not be generated properly. The word-document could however be created. Generated report: " f"'{target_file.as_posix()}'.") return target_file elif (output_file is None or not output_file.exists()) and not target_file.exists(): project.write_log( f"WARNING: The detailed report in pdf-format with the results for the foundation behaviour checks could " f"not be generated properly. Please check the inputs and contact the automation team.") return None project.write_log( f"Successfully created pdf-report for the foundation behaviour checks. The report can be found at: " f"'{output_file.as_posix()}'.") return output_file
### =================================================================================================================== ### 5. Function to create the foundation behaviour report ### ===================================================================================================================
[docs]def viia_foundation_behaviour_report(project: ViiaProject, analysis: Analysis, signal: str) -> Optional[Path]: """ This function handles the output from NLTH analysis regarding the behaviour of the foundation. For this purpose reference points have been selected for which detailed information is collected for every step. This is done for shallow foundations, pile foundations or mixed foundations. The function generates a report that can be used to assess the behaviour of the foundation in the NLTH analysis. The report is not a deliverable for the client and should be used by the structural engineer and reviewer to check the behaviour of the model. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - analysis (obj): Analysis object of the analysis for which the report is generated. This should be the NLTH analysis (A4, A12 or A15). The results of this analysis should be present in the current analysis folder. - signal (str): Input of the signal number, to included signal in report. Can be S1-S11. Output: - Creates a Word document with the results per reference point, including graphs that show the displacements and stresses for shallow foundations and the displacements and reaction forces of pile foundations. If possible, the Word document is converted to a pdf-file. - Returns the path of the pdf-file, if the file could be generated. """ # Check if shallow foundation is present and if piles are present fos, pile = viia_check_foundation_type(project=project) # Check if files are present and inform user if function can be executed to generate report output_file_geo_ref = None output_file_geo_ref_piles = None if fos: output_file_geo_ref = project.viia_get_file( path=project.current_analysis_folder, in_name='_OUTPUT_GEO_REF', suffix='.tb') if output_file_geo_ref and output_file_geo_ref.exists(): project.read_diana_tbfile(file=output_file_geo_ref, analysis=analysis) else: output_file_geo_ref = None if pile: output_file_geo_ref_piles = project.viia_get_file( path=project.current_analysis_folder, in_name='_OUTPUT_5B', suffix='.tb') if output_file_geo_ref_piles and output_file_geo_ref_piles.exists(): project.read_diana_tbfile(file=output_file_geo_ref_piles, analysis=analysis) else: output_file_geo_ref_piles = None if not (output_file_geo_ref and output_file_geo_ref.exists()) and not \ (output_file_geo_ref_piles and output_file_geo_ref_piles.exists()): project.write_log( "WARNING: No output file for shallow foundation or pile foundation found. The report for foundation " "behaviour checks could not be generated.") return None if fos and output_file_geo_ref is None: project.write_log( "WARNING: The foundation behaviour report will be generated, but the shallow foundation part will be " "skipped, as there are no results available.") if pile and output_file_geo_ref_piles is None: project.write_log( "WARNING: The foundation behaviour report will be generated, but the pile foundation part will be " "skipped, as there are no results available.") # Check the signal number if signal not in [f'S{i}' for i in range(1, 12)]: project.write_log( f"WARNING: Signal needs to be between S1-S11, current value {signal} is not allowed. No shear forces " f"report generated.") return None # Create separate folder for the result handling of the checks for foundation behaviour output_folder = project.current_analysis_folder / 'Foundation behaviour' fem_create_folder(output_folder) # Collect data for the shallow foundation shallow_foundation_data = None if fos and output_file_geo_ref is not None: shallow_foundation_data = viia_collect_data_shallow_foundation(project=project, analysis=analysis) # Create figures for each reference element in the shallow foundation for element, element_data in shallow_foundation_data.items(): viia_plot_shallow_foundation_behaviour_per_element( project=project, element=element, data=element_data, output_folder=output_folder) # Collect data for the pile foundation pile_foundation_data = None if pile and output_file_geo_ref_piles is not None: pile_foundation_data = viia_collect_data_pile_foundation(project=project) # Create figures for each pile in the pile foundation for element, element_data in pile_foundation_data.items(): viia_plot_pile_foundation_behaviour_per_element( project=project, element=element, data=element_data, output_folder=output_folder) # Create json-dump file with the results dumpfile = output_folder / 'foundation_behaviour.json' with open(dumpfile, 'w') as fd: json.dump( {'shallow_foundation': shallow_foundation_data, 'pile_foundation': pile_foundation_data}, fd, indent=2, sort_keys=True) # Generate report return viia_generate_foundation_behaviour_report( project=project, shallow_foundation_data=shallow_foundation_data, pile_foundation_data=pile_foundation_data, signal=signal, analysis=analysis, output_folder=output_folder)
### =================================================================================================================== ### 6. End of script ### ===================================================================================================================