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