Source code for viiapackage.pictures.model_plots.viia_foundation_plots

### ===================================================================================================================
###  FUNCTION: Make foundation plots for VIIA
### ===================================================================================================================
# Copyright ©VIIA 2025

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

# General imports
from __future__ import annotations
from typing import TYPE_CHECKING, List, Optional, Dict, Tuple, Any
from pathlib import Path
import sys

# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.shapes import Wall, Fstrip
from rhdhv_fem.fem_math import fem_angle_between_2_vectors, fem_flip_vector, fem_compare_values, \
    fem_ordered_coordinates_list

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

# Import matplotlib
import matplotlib.pyplot as plt


### ===================================================================================================================
###   2. Functions to collect foundation detail info
### ===================================================================================================================

[docs]def viia_collect_unique_foundation_details(project: ViiaProject) -> Tuple[Dict[int, Any], Dict[int, Any]]: """ This function collects the data from the model that defines the foundation details. The function uses the information that is stored in the foundation strip objects that are created in the modelscript. This information is combined and a unique set is created to plot the cross-sections and the overview of the location of these details. The functionality depends on the naming conventions and workflow for the VIIA project. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. Output: - Returns a tuple with the unique strip foundation details and the unique stepped foundation details. - The keys in both dictionaries is the number of the detail, as integer. - The values are is the collected data that defines the type of foundation detail. - The list of foundation strip elements for which the detail is applicable is stored in the dictionary, with the key 'fstrips'. """ def _compare_values(value, compare_value) -> bool: """ Recursive comparing the contents of dictionary, that can contain floats or list of floats.""" if isinstance(value, (float, int)): if not isinstance(compare_value, (float, int)): return False if not fem_compare_values(value1=value, value2=compare_value, precision=project.check_precision): return False elif isinstance(value, list): for i, item in enumerate(value): if not _compare_values(value=item, compare_value=compare_value[i]): return False elif isinstance(value, bool): if value != compare_value: return False elif value is None: if compare_value is not None: return False return True def _compare_strip_data_dict(dict1: Dict[str, float], dict2: Dict[str, float]) -> bool: """ Check if the two dictionaries with strip data is equal. Excluding the fstrip values.""" if not dict1.keys() == dict2.keys(): return False for k, v in dict1.items(): if k == 'fstrips': continue if not _compare_values(value=v, compare_value=dict2[k]): return False return True # Collect foundation data for all fstrips in the model counter = 0 strip_foundation_dict = dict() stepped_foundation_dict = dict() for strip in project.collections.fstrips: # Foundation details under columns are not yet available and are skipped if strip.meta_data and strip.meta_data.get('supported_column'): project.write_log("WARNING: The foundation plot is not supported for columns. For now it is skipped.") continue # Collect foundation strips and data if strip.meta_data and 'strip_foundation' in strip.meta_data: # Check if enough information is provided to plot the strip and foundation wall. is_sufficient_info = True for required_item in ['supported_wall', 'foundation_wall']: if not strip.meta_data.get(required_item): project.write_log( f"WARNING: '{required_item}' is not defined in meta-data of fstrip with id " f"{strip.id}, foundation picture cannot be created.") is_sufficient_info = False if not is_sufficient_info: continue wall_z_min = strip.meta_data['supported_wall'].contour.get_min_z() foundation_wall_thickness = strip.meta_data['foundation_wall'].geometry.geometry_model.thickness cavity_wall_thickness = None cavity = None if 'foundation_cavity_wall' in strip.meta_data: cavity_wall_thickness = strip.meta_data['foundation_cavity_wall'].geometry.geometry_model.thickness cavity = strip.meta_data['cavity'] / 1E3 foundation_wall_height = \ round(abs( strip.meta_data['foundation_wall'].contour.get_max_z() - strip.meta_data['foundation_wall'].contour.get_min_z()), 3) foundation_strip_thickness = strip.geometry.geometry_model.thickness foundation_strip_width = viia_get_fstrip_width(fstrip=strip) strip_data = { 'fstrips': [strip], 'wall_zmin': wall_z_min, 'fwall_thickness': foundation_wall_thickness, 'fwall_height': foundation_wall_height, 'fstrip_thickness': foundation_strip_thickness, 'fstrip_width': foundation_strip_width, 'cavity': cavity, 'cavity_wall_thickness': cavity_wall_thickness} # Only store unique foundation strips for unique_strip_data in strip_foundation_dict.values(): if _compare_strip_data_dict(dict1=strip_data, dict2=unique_strip_data): unique_strip_data['fstrips'].append(strip) break else: strip_foundation_dict[counter + 1] = strip_data counter += 1 # Collect stepped foundation and data if strip.meta_data and 'stepped_foundation' in strip.meta_data: # Check if enough information is provided to plot the strip and foundation wall. is_sufficient_info = True if not strip.meta_data['equiv_dimensions']['normal_wall'] and ( 'cavity_extension_wall' not in strip.meta_data['equiv_dimensions'] or not strip.meta_data['equiv_dimensions']['cavity_extension_wall']): project.write_log( f"WARNING: 'normal_wall' or 'cavity_extension_wall' is not defined in meta-data of fstrip with id " f"{strip.id}, foundation picture cannot be created.") is_sufficient_info = False if not strip.meta_data['equiv_dimensions']['equiv_wall']: project.write_log( f"WARNING: 'equiv_wall' is not defined in meta-data of fstrip with id " f"{strip.id}, foundation picture cannot be created.") is_sufficient_info = False if not strip.meta_data['equiv_dimensions']['normal_wall']: if 'cavity_extension_wall' in strip.meta_data['equiv_dimensions'] and \ strip.meta_data['equiv_dimensions']['cavity_extension_wall']: if fem_compare_values( strip.meta_data['equiv_dimensions']['cavity_extension_wall'].contour.get_min_z(), strip.meta_data['equiv_dimensions']['equiv_wall'].contour.get_max_z()): pass else: project.write_log( f"WARNING: A non-zero height of normal_wall is expected for fstrip with id " f"{strip.id}, foundation picture cannot be created.") is_sufficient_info = False if not is_sufficient_info: continue if 'cavity_extension_wall' in strip.meta_data['equiv_dimensions']: wall_z_min = strip.meta_data['equiv_dimensions']['cavity_extension_wall'].contour.get_max_z() wall_thickness = \ strip.meta_data['equiv_dimensions']['cavity_extension_wall'].geometry.geometry_model.thickness else: wall_z_min = strip.meta_data['equiv_dimensions']['normal_wall'].contour.get_max_z() wall_thickness = strip.meta_data['equiv_dimensions']['normal_wall'].geometry.geometry_model.thickness # Get normal wall data if strip.meta_data['equiv_dimensions'] and \ strip.meta_data['equiv_dimensions']['normal_wall']: normal_wall_thickness = \ strip.meta_data['equiv_dimensions']['normal_wall'].geometry.geometry_model.thickness normal_wall_height = \ round(abs(strip.meta_data['equiv_dimensions']['normal_wall'].contour.get_max_z() - strip.meta_data['equiv_dimensions']['normal_wall'].contour.get_min_z()), 3) normal_wall_dimensions = [True, normal_wall_thickness, normal_wall_height] else: normal_wall_dimensions = [False, wall_thickness] # Get cavity extension wall data if 'cavity_extension_wall' in strip.meta_data['equiv_dimensions'] and \ 'cavity_distance' in strip.meta_data['equiv_dimensions']: cavity_extension_wall_thickness = \ strip.meta_data['equiv_dimensions']['cavity_extension_wall'].geometry.geometry_model.thickness cavity_extension_wall_height = \ round(abs(strip.meta_data['equiv_dimensions']['cavity_extension_wall'].contour.get_max_z() - strip.meta_data['equiv_dimensions']['cavity_extension_wall'].contour.get_min_z()), 3) cavity_extension_wall_dimensions = [ True, cavity_extension_wall_thickness, cavity_extension_wall_height, strip.meta_data['equiv_dimensions']['cavity_distance'], strip.meta_data['equiv_dimensions']['outer_leaf_thickness']] elif 'cavity_distance' in strip.meta_data['equiv_dimensions']: cavity_extension_wall_dimensions = [ False, wall_thickness, 0, strip.meta_data['equiv_dimensions']['cavity_distance'], strip.meta_data['equiv_dimensions']['outer_leaf_thickness']] else: cavity_extension_wall_dimensions = [False, wall_thickness] # Get equiv wall data equiv_wall_height = \ round(abs( strip.meta_data['equiv_dimensions']['equiv_wall'].contour.get_max_z() - strip.meta_data['equiv_dimensions']['equiv_wall'].contour.get_min_z()), 3) equiv_wall_dimensions = [ strip.meta_data['equiv_dimensions']['equiv_wall'].geometry.geometry_model.thickness, equiv_wall_height] # Get strip data foundation_strip_thickness = strip.geometry.geometry_model.thickness foundation_strip_width = viia_get_fstrip_width(fstrip=strip) strip_dimensions = [foundation_strip_thickness, foundation_strip_width] # Get strip depth depth = strip.contour.get_max_z() - 0.5 * strip.geometry.geometry_model.thickness stepped_data = { 'fstrips': [strip], 'wall_thickness': wall_thickness, 'wall_zmin': wall_z_min, 'real_dimensions': strip.meta_data['real_dimensions'], 'normal_wall_dimensions': normal_wall_dimensions, 'cavity_extension_wall_dimensions': cavity_extension_wall_dimensions, 'equiv_wall_dimensions': equiv_wall_dimensions, 'strip_dimensions': strip_dimensions, 'depth': depth} # Only store unique stepped foundation for unique_stepped_data in stepped_foundation_dict.values(): if _compare_strip_data_dict(dict1=stepped_data, dict2=unique_stepped_data): unique_stepped_data['fstrips'].append(strip) break else: stepped_foundation_dict[counter + 1] = stepped_data counter += 1 # Return both dictionaries, the first is the strip foundation details, the second the stepped foundation details return strip_foundation_dict, stepped_foundation_dict
### =================================================================================================================== ### 3. Function to create foundation cross section pictures ### ===================================================================================================================
[docs]def viia_plot_foundation_details( project: ViiaProject, save_folder: Optional[Path] = None, dpi: Optional[int] = None) -> List[Path]: """ This function plots the unique foundation details for shallow foundations in the model. This includes strip and stepped foundations that have been created with the functionality in the viiaPackage. The functionality expects a grid to be defined. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - save_folder (str): Path to folder where the pictures should be saved. Default value is None, in which case the current workfolder will be used. - dpi (int): Optional input to specify the quality of the picture (use for bigger plots). Default value is None, using default matplotlib dpi setting. Output: - Returns a list of files with the plots of the foundation details. - The first file presents an overview of the locations of the foundation details in the model. """ if save_folder is None: save_folder = project.workfolder_location strip_foundation_details, stepped_foundation_details = viia_collect_unique_foundation_details(project=project) plots = viia_plot_foundation_cross_section( project=project, save_folder=save_folder, dpi=dpi, strip_foundation_dict=strip_foundation_details, stepped_foundation_dict=stepped_foundation_details) overview_plot = viia_plot_foundation_details_overview( project=project, save_folder=save_folder, dpi=dpi, strip_foundation_dict=strip_foundation_details, stepped_foundation_dict=stepped_foundation_details) return [overview_plot] + plots
[docs]def viia_plot_foundation_cross_section( project: ViiaProject, save_folder: Optional[Path] = None, dpi: Optional[int] = None, strip_foundation_dict: Optional[Dict[int, Any]] = None, stepped_foundation_dict: Optional[Dict[int, Any]] = None) -> List[Path]: """ This function plots the cross-sections of shallow foundation in the model. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - save_folder (str): Path to folder where the pictures should be saved. Default value is None, in which case the current workfolder will be used. - dpi (int): Optional input to specify the quality of the picture (use for bigger plots). Default value is None, using default matplotlib dpi setting. - strip_foundation_dict (dict): Dictionary with the information of the unique strip foundation details. Default value is None, in which case the unique foundation details are collected. - stepped_foundation_dict (dict): Dictionary with the information of the unique stepped foundation details. Default value is None, in which case the unique foundation details are collected. Output: - Returns the plots of the shallow foundation cross-sections in the specified folder. """ # When this function is executed alone, the foundation details can be collected if strip_foundation_dict is None or stepped_foundation_dict is None: strip_foundation_dict, stepped_foundation_dict = viia_collect_unique_foundation_details(project=project) # Make plots of strip foundation collected_plots = [] for counter, strip in strip_foundation_dict.items(): if strip['cavity'] and strip['cavity_wall_thickness']: total_wall_thickness = strip['cavity_wall_thickness'] + strip['cavity'] + strip['fwall_thickness'] outer_outside = -total_wall_thickness / 2 outer_inside = outer_outside + strip['cavity_wall_thickness'] inner_outside = outer_inside + strip['cavity'] inner_inside = inner_outside + strip['fwall_thickness'] fstrip_outside = -0.5 * strip['fstrip_width'] fstrip_inside = 0.5 * strip['fstrip_width'] x_values = [fstrip_outside, outer_outside, outer_inside, inner_outside, inner_inside, fstrip_inside] x_values_plot = [ outer_outside, outer_outside, fstrip_outside, fstrip_outside, fstrip_inside, fstrip_inside, inner_inside, inner_inside] x_values_plot_cavity = [inner_outside, inner_outside, outer_inside, outer_inside] wall_top = strip['wall_zmin'] fstrip_top = strip['wall_zmin'] - (strip['fwall_height'] - 0.5 * strip['fstrip_thickness']) fstrip_bottom = strip['wall_zmin'] - (strip['fwall_height'] + 0.5 * strip['fstrip_thickness']) y_values = [wall_top, fstrip_top, fstrip_bottom] y_values_plot = [ wall_top, fstrip_top, fstrip_top, fstrip_bottom, fstrip_bottom, fstrip_top, fstrip_top, wall_top] y_values_plot_cavity = [wall_top, fstrip_top, fstrip_top, wall_top] else: x_values = [ -0.5 * strip['fwall_thickness'] - 0.5 * (strip['fstrip_width'] - strip['fwall_thickness']), -0.5 * strip['fwall_thickness'], 0.5 * strip['fwall_thickness'], 0.5 * strip['fwall_thickness'] + 0.5 * (strip['fstrip_width'] - strip['fwall_thickness'])] y_values = [ strip['wall_zmin'], strip['wall_zmin'] - (strip['fwall_height'] - 0.5 * strip['fstrip_thickness']), strip['wall_zmin'] - (strip['fwall_height'] + 0.5 * strip['fstrip_thickness'])] x_values_plot = [ x_values[1], x_values[1], x_values[0], x_values[0], x_values[3], x_values[3], x_values[2], x_values[2]] x_values_plot_cavity = [] y_values_plot = [ y_values[0], y_values[1], y_values[1], y_values[2], y_values[2], y_values[1], y_values[1], y_values[0]] y_values_plot_cavity = [] # Plot foundation plt.plot(x_values_plot, y_values_plot, color='k', linewidth=2) if x_values_plot_cavity and y_values_plot_cavity: plt.plot(x_values_plot_cavity, y_values_plot_cavity, color='k', linewidth=2) plt.ylabel('Depth [m]', fontsize=10) plt.xlabel('Width [mm]', fontsize=10) # Make axes scaled plt.axis('square') axes = plt.gca() xmin, xmax = axes.get_xlim() xrange = abs(xmax-xmin) axes.set_xlim(0 - 0.5 * xrange, 0 + 0.5 * xrange) ymin, ymax = axes.get_ylim() yrange = abs(ymax - ymin) mid_y = (y_values[0]+y_values[-1])/2 axes.set_ylim(mid_y - 0.6 * yrange, mid_y + 0.5 * yrange) # Set axes ticks axes.set_xticks(x_values) axes.set_yticks(y_values) axes.axes.xaxis.set_ticklabels([]) axes.tick_params(axis='both', which='major', labelsize=8) axes.grid(linestyle='--') # Add horizontal dimensions ymin, ymax = axes.get_ylim() yrange = abs(ymax - ymin) for i in range(len(x_values)-1): plt.annotate( text='', xy=(x_values[i], ymin+0.03*yrange), xytext=(x_values[i+1], ymin+0.03*yrange), arrowprops={'arrowstyle': '<->', 'color': 'k'}) plt.text( (x_values[i]+x_values[i+1])/2, ymin+0.06*yrange, f'{int(round(x_values[i+1]-x_values[i], 3) * 1e3)}', fontsize='x-small', ha='center', va='center', color='k') # Fill foundation area with color axes.fill(x_values_plot + x_values_plot_cavity, y_values_plot + y_values_plot_cavity, c='lightgrey') # Save picture plt.savefig(save_folder / f'Foundations - Cross section strip foundation - {counter}.png', dpi=dpi) plt.close() collected_plots.append(save_folder / f'Foundations - Cross section strip foundation - {counter}.png') # Make plots of stepped foundation for counter, strip in stepped_foundation_dict.items(): # Make plot of real dimensions # Get plot values x_values = [-0.5 * strip['wall_thickness'], 0.5 * strip['wall_thickness']] y_values = [strip['wall_zmin']] cavity_extension_data = None if strip['cavity_extension_wall_dimensions'][0] is True: cavity_extension_data = strip['cavity_extension_wall_dimensions'] x_values = [ -0.5 * (cavity_extension_data[1] + cavity_extension_data[3]), -0.5 * (cavity_extension_data[1] + cavity_extension_data[3]) + cavity_extension_data[4], -0.5 * (cavity_extension_data[1] + cavity_extension_data[3]) + cavity_extension_data[4] + cavity_extension_data[3], 0.5 * (cavity_extension_data[1] + cavity_extension_data[3])] x_steps = [ round(sum(strip['real_dimensions'][0][:i+1]) / 1000, 3) for i in range(len(strip['real_dimensions'][0]))] y_steps = [ round(sum(strip['real_dimensions'][1][-(i+1):]) / 1000, 3) for i in range(len(strip['real_dimensions'][1]))] x_min = min(x_values) x_max = max(x_values) for i in x_steps: x_values.append(round(x_min - i, 3)) x_values.append(round(x_max + i, 3)) for i in y_steps: y_values.append(strip['depth'] + i) y_values.append(strip['depth']) x_values.sort() y_values.sort(reverse=True) if strip['cavity_extension_wall_dimensions'][0] is True: y_values.insert(0, strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2]) # Collect the surface area to be coloured # If cavity wall exists, in the picture, left side is always the outer leaf and right side is inner leaf if strip['cavity_extension_wall_dimensions'][0] is True: x_values_plot = [x_min + cavity_extension_data[4], x_min + cavity_extension_data[4]] else: x_values_plot = [x_min, x_min] for i in range(int(len(x_values) / 2) - 1): x_values_plot.append(x_values[int(len(x_values) / 2 - 2) - i]) x_values_plot.append(x_values[int(len(x_values) / 2 - 2) - i]) for i in range(int(len(x_values) / 2)): x_values_plot.append(x_values[int(len(x_values) - 1) - i]) x_values_plot.append(x_values[int(len(x_values) - 1) - i]) y_values_plot = [y_values[0]] for i in range(len(y_values)-1): y_values_plot.append(y_values[i + 1]) y_values_plot.append(y_values[i + 1]) for i in range(len(y_values) - 2): y_values_plot.append(y_values[- (i + 2)]) y_values_plot.append(y_values[- (i + 2)]) y_values_plot.append(y_values[0]) # Collect the contour lines cavity_extension = False if strip['cavity_extension_wall_dimensions'][0]: cavity_extension = True if cavity_extension: x_values_contour_plot = [] else: x_values_contour_plot = [x_values_plot[0], x_values_plot[0]] for i in range(int(len(x_values) / 2) - 1): x_values_contour_plot.append(x_values[int(len(x_values) / 2 - 2) - i]) x_values_contour_plot.append(x_values[int(len(x_values) / 2 - 2) - i]) for i in range(int(len(x_values) / 2) - 1): x_values_contour_plot.append(x_values[int(len(x_values) - 1) - i]) x_values_contour_plot.append(x_values[int(len(x_values) - 1) - i]) if not cavity_extension: x_values_contour_plot += [x_values_plot[-1], x_values_plot[-1]] if cavity_extension: y_values_contour_plot = [y_values[1]] for i in range(1, len(y_values) - 1): y_values_contour_plot.append(y_values[i + 1]) y_values_contour_plot.append(y_values[i + 1]) for i in range(len(y_values) - 3): y_values_contour_plot.append(y_values[- (i + 2)]) y_values_contour_plot.append(y_values[- (i + 2)]) y_values_contour_plot.append(y_values[1]) else: y_values_contour_plot = [y_values[0]] for i in range(len(y_values)-1): y_values_contour_plot.append(y_values[i + 1]) y_values_contour_plot.append(y_values[i + 1]) for i in range(len(y_values) - 2): y_values_contour_plot.append(y_values[- (i + 2)]) y_values_contour_plot.append(y_values[- (i + 2)]) y_values_contour_plot.append(y_values[0]) # Close the cavity extension wall dimension on bottom of extension x_values_cavity_extension = None y_values_cavity_extension = None if cavity_extension: x = x_values_contour_plot[0] + strip['cavity_extension_wall_dimensions'][4] x_values_cavity_extension = [x, x] x += strip['cavity_extension_wall_dimensions'][3] x_values_cavity_extension.append(x) x_values_cavity_extension.append(x) y_values_cavity_extension = [y_values[1], y_values[0], y_values[0], y_values[1]] elif strip['cavity_extension_wall_dimensions'] and len(strip['cavity_extension_wall_dimensions']) == 5: x_values_cavity_extension = [ x_values_contour_plot[0] + strip['cavity_extension_wall_dimensions'][4], x_values_contour_plot[0] + strip['cavity_extension_wall_dimensions'][4] + strip['cavity_extension_wall_dimensions'][3]] y_values_cavity_extension = [y_values[0], y_values[0]] # Plot real foundation plt.plot(x_values_contour_plot, y_values_contour_plot, color='k', linewidth=3, label='Real foundation') plt.ylabel('Depth [m]', fontsize=10) if x_values_cavity_extension and y_values_cavity_extension: plt.plot(x_values_cavity_extension, y_values_cavity_extension, color='k', linewidth=3) # Make axes scaled plt.axis('square') axes = plt.gca() xmin, xmax = axes.get_xlim() xrange = abs(xmax-xmin) axes.set_xlim(0 - 0.5 * xrange, 0 + 0.5 * xrange) ymin, ymax = axes.get_ylim() yrange = abs(ymax - ymin) y_values = sorted(y_values) mid_y = (y_values[0]+y_values[-1])/2 axes.set_ylim(mid_y - 0.6 * yrange, mid_y + 0.5 * yrange) # Set axes ticks axes.set_xticks(x_values) axes.set_yticks(y_values) axes.axes.xaxis.set_ticklabels([]) axes.tick_params(axis='both', which='major', labelsize=8) axes.grid(linestyle='--') # Add horizontal dimensions ymin, ymax = axes.get_ylim() yrange = abs(ymax - ymin) level_high = False # This takes care of the flipping of high/low to prevent overlapping dimensions for i in range(len(x_values)-1): # Draw the arrows on one horizontal line plt.annotate( text='', xy=(x_values[i], ymin+0.03*yrange), xytext=(x_values[i+1], ymin+0.03*yrange), arrowprops={'arrowstyle': '<->, head_width=0.2', 'color': 'k'}) # Prevent overlapping dimensions texts if (x_values[i + 1] - x_values[i] < 0.06) and \ (x_values[i + 1] - x_values[i])/yrange <= 0.07 and not level_high: # Draw a vertical line to the arrow plt.annotate( text='', xy=((x_values[i] + x_values[i + 1]) / 2, ymin+0.035*yrange), xytext=((x_values[i] + x_values[i + 1]) / 2, ymin + 0.08 * yrange), arrowprops={'arrowstyle': '-', 'lw': 0.5, 'color': 'dimgrey'}) # Set the text with the dimension on higher level plt.text( (x_values[i] + x_values[i + 1]) / 2, ymin + 0.08 * yrange, f'{round(x_values[i + 1] - x_values[i], 3)}m', fontsize='xx-small', ha='center', va='center', color='k') level_high = True else: level_high = False # Set the text of the dimension on the standard level plt.text( (x_values[i] + x_values[i + 1]) / 2, ymin + 0.06 * yrange, f'{round(x_values[i + 1] - x_values[i], 3)}m', fontsize='xx-small', ha='center', va='center', color='k') # Fill foundation area with color axes.fill(x_values_plot, y_values_plot, c='lightgrey') # Make plot of modelled dimensions # Get plot values # Check if both cavity extension wall and normal wall present if strip['cavity_extension_wall_dimensions'][0] and strip['normal_wall_dimensions'][0]: x_values = [ strip['cavity_extension_wall_dimensions'][1] / 2, -strip['cavity_extension_wall_dimensions'][1] / 2, strip['normal_wall_dimensions'][1] / 2, -strip['normal_wall_dimensions'][1] / 2, strip['equiv_wall_dimensions'][0] / 2, -strip['equiv_wall_dimensions'][0] / 2, strip['strip_dimensions'][1] / 2, -strip['strip_dimensions'][1] / 2] x_values.sort() y_values = [ strip['wall_zmin'], strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2], strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2] - strip['normal_wall_dimensions'][2], strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2] - strip['normal_wall_dimensions'][2] - (strip['equiv_wall_dimensions'][1] - 0.5 * strip['strip_dimensions'][0]), strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2] - strip['normal_wall_dimensions'][2] - strip['equiv_wall_dimensions'][1] - 0.5 * strip['strip_dimensions'][0] ] y_values.sort(reverse=True) x_values_plot = [ x_values[3], x_values[3], x_values[2], x_values[2], x_values[1], x_values[1], x_values[0], x_values[0], x_values[7], x_values[7], x_values[6], x_values[6], x_values[5], x_values[5], x_values[4], x_values[4]] y_values_plot = [ y_values[0], y_values[1], y_values[1], y_values[2], y_values[2], y_values[3], y_values[3], y_values[4], y_values[4], y_values[3], y_values[3], y_values[2], y_values[2], y_values[1], y_values[1], y_values[0]] # Check if only cavity extension wall present elif strip['cavity_extension_wall_dimensions'][0] and not strip['normal_wall_dimensions'][0]: x_values = [ strip['cavity_extension_wall_dimensions'][1] / 2, -strip['cavity_extension_wall_dimensions'][1] / 2, strip['equiv_wall_dimensions'][0] / 2, -strip['equiv_wall_dimensions'][0] / 2, strip['strip_dimensions'][1] / 2, -strip['strip_dimensions'][1] / 2] x_values.sort() y_values = [ strip['wall_zmin'], strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2], strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2] - (strip['equiv_wall_dimensions'][1] - 0.5 * strip['strip_dimensions'][0]), strip['wall_zmin'] - strip['cavity_extension_wall_dimensions'][2] - strip['equiv_wall_dimensions'][1] - 0.5 * strip['strip_dimensions'][0] ] y_values.sort(reverse=True) x_values_plot = [ x_values[2], x_values[2], x_values[1], x_values[1], x_values[0], x_values[0], x_values[5], x_values[5], x_values[4], x_values[4], x_values[3], x_values[3]] y_values_plot = [ y_values[0], y_values[1], y_values[1], y_values[2], y_values[2], y_values[3], y_values[3], y_values[2], y_values[2], y_values[1], y_values[1], y_values[0]] # Check if only normal wall present elif strip['normal_wall_dimensions'][0]: x_values = [ strip['normal_wall_dimensions'][1] / 2, -strip['normal_wall_dimensions'][1] / 2, strip['equiv_wall_dimensions'][0] / 2, -strip['equiv_wall_dimensions'][0] / 2, strip['strip_dimensions'][1] / 2, -strip['strip_dimensions'][1] / 2] x_values.sort() y_values = [ strip['wall_zmin'], strip['wall_zmin']-strip['normal_wall_dimensions'][2], strip['wall_zmin']-strip['normal_wall_dimensions'][2] - (strip['equiv_wall_dimensions'][1]-0.5*strip['strip_dimensions'][0]), strip['wall_zmin']-strip['normal_wall_dimensions'][2] - strip['equiv_wall_dimensions'][1]-0.5*strip['strip_dimensions'][0]] y_values.sort(reverse=True) x_values_plot = [ x_values[2], x_values[2], x_values[1], x_values[1], x_values[0], x_values[0], x_values[5], x_values[5], x_values[4], x_values[4], x_values[3], x_values[3]] y_values_plot = [ y_values[0], y_values[1], y_values[1], y_values[2], y_values[2], y_values[3], y_values[3], y_values[2], y_values[2], y_values[1], y_values[1], y_values[0]] else: x_values = [ strip['normal_wall_dimensions'][1] / 2, -strip['normal_wall_dimensions'][1] / 2, strip['equiv_wall_dimensions'][0] / 2, -strip['equiv_wall_dimensions'][0] / 2, strip['strip_dimensions'][1] / 2, -strip['strip_dimensions'][1] / 2] x_values.sort() y_values = [ strip['wall_zmin'], strip['wall_zmin'] - (strip['equiv_wall_dimensions'][1]-0.5*strip['strip_dimensions'][0]), strip['wall_zmin']-strip['equiv_wall_dimensions'][1]-0.5*strip['strip_dimensions'][0]] y_values.sort(reverse=True) x_values_plot = [ x_values[2], x_values[1], x_values[1], x_values[0], x_values[0], x_values[5], x_values[5], x_values[4], x_values[4], x_values[3]] y_values_plot = [ y_values[0], y_values[0], y_values[1], y_values[1], y_values[2], y_values[2], y_values[1], y_values[1], y_values[0], y_values[0]] # Plot foundation plt.plot(x_values_plot, y_values_plot, color='r', linewidth=1.5, linestyle='--', label='Modelled foundation') plt.legend(loc=(1.04, 0.5)) # Add horizontal dimension for equivalent wall if strip['cavity_extension_wall_dimensions'][0] and strip['normal_wall_dimensions'][0]: plt.annotate( text='', xy=(x_values[1], (y_values[2] + y_values[3]) / 2), xytext=(x_values[6], (y_values[2] + y_values[3]) / 2), arrowprops={'arrowstyle': '<->', 'color': 'r'}) plt.text( (x_values[1] + x_values[6]) / 2, (y_values[2] + y_values[3]) / 2 - 0.03 * yrange, f'{round(x_values[6] - x_values[1], 3)} m', fontsize='x-small', ha='center', va='center', color='r') elif strip['cavity_extension_wall_dimensions'][0] and not strip['normal_wall_dimensions'][0]: plt.annotate( text='', xy=(x_values[1], (y_values[1] + y_values[2]) / 2), xytext=(x_values[4], (y_values[1] + y_values[2]) / 2), arrowprops={'arrowstyle': '<->', 'color': 'r'}) plt.text( (x_values[1] + x_values[4]) / 2, (y_values[1] + y_values[2]) / 2 - 0.03 * yrange, f'{round(x_values[4] - x_values[1], 3)} m', fontsize='x-small', ha='center', va='center', color='r') elif strip['normal_wall_dimensions'][0]: plt.annotate( text='', xy=(x_values[1], (y_values[1] + y_values[2]) / 2), xytext=(x_values[4], (y_values[1] + y_values[2]) / 2), arrowprops={'arrowstyle': '<->', 'color': 'r'}) plt.text( (x_values[1] + x_values[4]) / 2, (y_values[1] + y_values[2]) / 2 - 0.03 * yrange, f'{round(x_values[4] - x_values[1], 3)} m', fontsize='x-small', ha='center', va='center', color='r') else: plt.annotate( text='', xy=(x_values[1], (y_values[0]+y_values[1])/2), xytext=(x_values[4], (y_values[0]+y_values[1])/2), arrowprops={'arrowstyle': '<->', 'color': 'r'}) plt.text( (x_values[1] + x_values[4]) / 2, (y_values[0] + y_values[1]) / 2 - 0.05 * yrange, f'{round(x_values[4] - x_values[1], 3)} m', fontsize='x-small', ha='center', va='center', color='r') # Save picture plt.savefig( save_folder / f'Foundations - Cross section stepped foundation - {counter}.png', bbox_inches='tight', dpi=dpi) plt.close() collected_plots.append(save_folder / f'Foundations - Cross section stepped foundation - {counter}.png') return collected_plots
[docs]def viia_plot_foundation_details_overview( project: ViiaProject, save_folder: Optional[Path] = None, dpi: Optional[int] = None, strip_foundation_dict: Optional[Dict[int, Any]] = None, stepped_foundation_dict: Optional[Dict[int, Any]] = None) -> Path: """ This function creates a plot with an overview of the foundation details in the model. Input: - project (obj): VIIA project object containing collections of fem objects and project variables. - save_folder (str): Path to folder where the pictures should be saved. Default value is None, in which case the current workfolder will be used. - dpi (int): Optional input to specify the quality of the picture (use for bigger plots). Default value is None, using default matplotlib dpi setting. - strip_foundation_dict (dict): Dictionary with the information of the unique strip foundation details. Default value is None, in which case the unique foundation details are collected. - stepped_foundation_dict (dict): Dictionary with the information of the unique stepped foundation details. Default value is None, in which case the unique foundation details are collected. Output: - Returns the plot of the shallow foundation details overview in the specified folder. """ def _get_foundation_wall(strip: Fstrip) -> Optional[Wall]: """ Function to get the wall defining the detail in the overview.""" if not strip.meta_data: return None if 'strip_foundation' in strip.meta_data.keys() and 'foundation_wall' in strip.meta_data.keys(): return strip.meta_data['foundation_wall'] if 'stepped_foundation' in strip.meta_data.keys() and 'equiv_dimensions' in strip.meta_data.keys() and \ 'equiv_wall' in strip.meta_data['equiv_dimensions']: return strip.meta_data['equiv_dimensions']['equiv_wall'] return None def _get_bottom_outer_points_wall(wall: Wall) -> Tuple[List[float], List[float]]: """ Returns the x-coordinates and y-coordinates of the bottom points of the foundation wall.""" nodes = [] for line in wall.get_bottom_edges(): nodes.append(line.node_start) nodes.append(line.node_end) ordered_list = fem_ordered_coordinates_list(coordinates_list=[node.coordinates for node in nodes]) return [ordered_list[0][0], ordered_list[-1][0]], [ordered_list[0][1], ordered_list[-1][1]] # When this function is executed alone, the foundation details can be collected if strip_foundation_dict is None or stepped_foundation_dict is None: strip_foundation_dict, stepped_foundation_dict = viia_collect_unique_foundation_details(project=project) # Create a dictionary that contains the z-order value, indicating which z-order the various elements should be nr_z_order = 10 z_orders = {f'zorder {i}': nr_z_order - (i - 1) for i in range(1, nr_z_order + 1)} # Kwargs for different types of texts kwargs_for_text = { 'fontsize': 'small', 'ha': 'center', 'va': 'center', 'zorder': z_orders['zorder 1'], 'bbox': {'boxstyle': 'square', 'fc': 'none', 'pad': 0.2, 'lw': 1}} # General setup of the plot grid = project.collections.grids[0] grid.plot(tags='none', show=False, show_dimensions=False, keep_plot=True) ax1 = plt.gca() fig = plt.gcf() # Set all gridlines to the bottom z-order for grid_line in ax1.get_lines(): grid_line.zorder = list(z_orders.values())[-1] # Collect the unique foundation details (same function that is used to generate the details with) shapes_colours_dict = {} all_strip_data = strip_foundation_dict | stepped_foundation_dict # Per foundation detail collect the foundation walls that are used to specify the location of the detail # Set colour for the different details ordered_keys = sorted(all_strip_data.keys()) for strip_nr in ordered_keys: strip_data = all_strip_data[strip_nr] shapes_colours_dict[strip_nr] = [ project.colours[int(strip_nr)], [_get_foundation_wall(strip=fstrip) for fstrip in strip_data['fstrips']]] for cross_section_type, (colour, foundation_walls) in shapes_colours_dict.items(): for foundation_wall in foundation_walls: x_points, y_points = _get_bottom_outer_points_wall(wall=foundation_wall) ax1.plot( x_points, y_points, color=colour, linewidth=2, label=cross_section_type, zorder=list(z_orders.values())[-2]) # Get the normal vector of the shape (in the horizontal plane for lines) normal = fem_flip_vector(foundation_walls[0].outward_vector()) # Set the ID for the foundation detail (only first place is numbered) x_points, y_points = _get_bottom_outer_points_wall(wall=foundation_walls[0]) x_text = sum(x_points) / len(x_points) + abs(normal[0]) * 0.3 y_text = sum(y_points) / len(y_points) + abs(normal[1]) * 0.3 # Get the rotation of the label based on orientation of beam x_axis = foundation_walls[0].get_horizontal_direction().vector if x_axis[0] < 0: new_x_axis = [-x for x in x_axis] x_axis = new_x_axis rot_factor = 1 if x_axis[1] > 0: rot_factor = -1 rotation = -1 * abs(fem_angle_between_2_vectors([1, 0, 0], x_axis, degrees=True)) rotation *= rot_factor plt.text(x_text, y_text, str(cross_section_type), rotation=rotation, **kwargs_for_text) # Clean the title (else the grid title will be there) plt.title('', fontsize=16) # Kwargs for saving figure kwargs_for_savefig = {'bbox_inches': 'tight', 'format': 'png', 'dpi': dpi} # Save figure fig.canvas.start_event_loop(sys.float_info.min) save_location = save_folder / f'Foundations - Foundation Details Overview.png' if save_location.exists(): project.write_log( f"WARNING: Plot {save_location} already exists and will be overwritten.") plt.savefig(save_location, **kwargs_for_savefig) # Close the plot del fig plt.clf() plt.close() # Return the file with the foundation detail overview return save_location
### =================================================================================================================== ### 4. End of script ### ===================================================================================================================