Source code for viiapackage.geometry.geometry_models.viia_stepped_foundation_wall

### ===================================================================================================================
###   CLASS: ViiaSteppedFoundation
### ===================================================================================================================
# Copyright ©VIIA 2024

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

# General imports
import abc
from typing import List, Union, Optional
from copy import deepcopy

# References for functions and classes in the rhdhv_fem package
from rhdhv_fem.fem_math import fem_roots_quadratic_equation
from rhdhv_fem.geometries import Layered, AggregateCrossSection, Rectangle


### ===================================================================================================================
###    2. SteppedMasonry class
### ===================================================================================================================

[docs]class ViiaSteppedFoundationWall: """ This class is used to create the masonry stepped foundation geometry of walls.""" def __init__( self, wall_thickness: Union[int, float], top_level: Union[int, float], bottom_of_strip: Union[int, float], heights_levels_strip: List[Union[int, float]], strip_extensions: List[Union[int, float]], original_density: Union[int, float], cavity: Optional[float] = 0): """ Input: - start_thickness (int or float): The thickness of the wall at the top level of the stepped foundation, in [mm]. - top_level (int or float): Top level of the stepped foundation, relative to z=0, in [m]. - bottom_of_strip (int or float): Bottom level of the strip foundation, relative to z=0, in [m]. - heights_levels_strip (list of ints or floats): Height of the various levels of the stepped foundation going from top to bottom, in [mm]. | | ---- ---- 120 | | ---- ---- 50 | | ---- ---- 60 | | ----------------------- height_levels = [120, 50, 60] - strip_extensions (list of ints or floats): Extensions at each level of the stepped foundation going from top to bottom, in [mm]. 60 | | 60 ---- ---- 75 | | 75 ---- ---- 40 | | 40 ---- ---- | | ----------------------- strip_extensions = [60, 75, 40] - original_density: The density of the stepped foundation material, in [kg/m3]. - cavity (float): In case of a cavity wall specify the distance between inner and outer leaf. Default value is 0, in which case no cavity wall is taken into account, in [mm]. """ self.wall_thickness = wall_thickness self.top_level = top_level self.bottom_of_strip = bottom_of_strip self.heights_levels_strip = heights_levels_strip self.strip_extensions = strip_extensions self.original_density = original_density self.cavity = cavity @property def wall_thickness(self): return self.__start_thickness @wall_thickness.setter def wall_thickness(self, new_start_thickness: Union[int, float]): if not isinstance(new_start_thickness, (int, float)): raise ValueError("ERROR: The start thickness for the viia stepped foundation wall profile should be a " "number. Please check you input.") self.__start_thickness = new_start_thickness @property def top_level(self): return self.__top_level @top_level.setter def top_level(self, new_top_level: Union[int, float]): if not isinstance(new_top_level, (int, float)): raise ValueError("ERROR: The top level for the viia stepped foundation wall profile should be a number. " "Please check you input.") self.__top_level = new_top_level @property def bottom_of_strip(self): return self.__bottom_of_strip @bottom_of_strip.setter def bottom_of_strip(self, new_bottom_of_strip: Union[int, float]): if not isinstance(new_bottom_of_strip, (int, float)): raise ValueError("ERROR: The bottom of strip for the viia stepped foundation wall profile should be a " "number. Please check you input.") self.__bottom_of_strip = new_bottom_of_strip @property def heights_levels_strip(self): return self.__heights_levels_strip @heights_levels_strip.setter def heights_levels_strip(self, new_levels_strip_heights: list): if not isinstance(new_levels_strip_heights, list): raise ValueError("ERROR: The heights levels per strip for the viia stepped foundation wall profile should " "be a list of numbers. Please check your input.") if hasattr(self, 'strip_extensions') and len(new_levels_strip_heights) != len(self.strip_extensions): raise ValueError("ERROR: The provided number of heights levels per strip and strip extensions should be " "the same. Please check your input.") self.__heights_levels_strip = new_levels_strip_heights @property def strip_extensions(self): return self.__strip_extensions @strip_extensions.setter def strip_extensions(self, new_strip_extensions: list): if not isinstance(new_strip_extensions, list): raise ValueError("ERROR: The strip extensions for the viia stepped foundation wall profile should be a " "list of numbers. Please check your input.") if hasattr(self, 'heights_levels_strip') and len(self.heights_levels_strip) != len(new_strip_extensions): raise ValueError("ERROR: The provided number of heights levels per strip and strip extensions should be " "the same. Please check your input.") self.__strip_extensions = new_strip_extensions @property def original_density(self): return self.__original_density @original_density.setter def original_density(self, new_original_density: Union[int, float]): if not isinstance(new_original_density, (int, float)): raise ValueError("ERROR: The original density for the viia stepped foundation wall profile should be a " "number. Please check you input.") self.__original_density = new_original_density @property def cavity(self): return self.__cavity @cavity.setter def cavity(self, new_cavity: Union[int, float]): if not isinstance(new_cavity, (int, float)): raise ValueError("ERROR: The cavity for the viia stepped foundation wall profile should be a float. " "Please check you input.") self.__cavity = new_cavity @property def total_strip_widths(self): # Calculate the widths of the different levels in [mm], from top to bottom width = self.wall_thickness total_strip_widths = [width - self.cavity] for extension in self.strip_extensions: width += 2 * extension total_strip_widths.append(width) total_strip_widths.reverse() return total_strip_widths @property def heights_levels(self): # Calculate the heights of the different levels, in [mm], from top to bottom original_wall_height = self.top_level * 1E3 - self.bottom_of_strip * 1E3 for level in self.heights_levels_strip: original_wall_height -= level heights_levels = deepcopy(self.heights_levels_strip) heights_levels.insert(0, original_wall_height) heights_levels.reverse() return heights_levels @property def original_cs(self): layers = [(item / 1E3, self.heights_levels[i] / 1E3) for i, item in enumerate(self.total_strip_widths)] return Layered(layers=layers) @property def eq_wall_height(self): return sum(self.heights_levels[1:]) + self.heights_levels[0]/2 @property def eq_wall_width(self): eq_fstrip_width = self.total_strip_widths[0] eq_fstrip_height = self.heights_levels[0] eq_fstrip_area = eq_fstrip_width * eq_fstrip_height eq_fstrip_arm = self.heights_levels[0] / 2 total_height = (self.top_level - self.bottom_of_strip) * 1E3 # Obtaining the coefficients of the quadratic equation c_1*x^2 + c_2*x + c_3 = 0 c_1 = -self.eq_wall_height ** 4 c_2 = -4 * eq_fstrip_area * self.eq_wall_height ** 3 + \ 12 * (total_height - eq_fstrip_arm) * eq_fstrip_area * self.eq_wall_height ** 2 - \ 12 * self.eq_wall_height * eq_fstrip_area * (total_height - eq_fstrip_arm) ** 2 - \ self.eq_wall_height * eq_fstrip_width * eq_fstrip_height ** 3 + \ 12 * self.eq_wall_height * self.original_cs.second_moment_of_inertia * 1E12 c_3 = -eq_fstrip_area * eq_fstrip_width * eq_fstrip_height ** 3 + 12 * eq_fstrip_area \ * self.original_cs.second_moment_of_inertia * 1E12 # Calculate the roots of the quadratic equation solution = fem_roots_quadratic_equation(a=c_1, b=c_2, c=c_3) # Always select the positive and rounded solution (rounded to the lower integer) eq_wall_width = int([sol for sol in solution if sol > 0][0]) # Calculate with aggregate cross-section for validation of the solution rect_1 = Rectangle(width=eq_fstrip_width / 1e3, height=eq_fstrip_height / 1e3, name='Rect_1') rect_2 = Rectangle(width=eq_wall_width / 1e3, height=self.eq_wall_height / 1e3, name='Rect_2') new_cs = AggregateCrossSection(components=[ (0.5 * eq_fstrip_height / 1e3, rect_1), (0.5 * (self.eq_wall_height + eq_fstrip_height) / 1e3, rect_2)]) # Validate solution if not new_cs.second_moment_of_inertia * 0.98 < self.original_cs.second_moment_of_inertia < \ new_cs.second_moment_of_inertia * 1.02: raise ArithmeticError("ERROR: Solution could not be found for the equivalent foundation.") return round(eq_wall_width, 3) @property def eq_density(self): eq_fstrip_width = self.total_strip_widths[0] eq_fstrip_height = self.heights_levels[0] eq_fstrip_area = eq_fstrip_width * eq_fstrip_height modified_density = (self.original_cs.area * 1E6 - eq_fstrip_area) * self.original_density / ( self.eq_wall_width * self.eq_wall_height) return round(modified_density, 3) def strip_areas(self): return [height * width for height, width in zip(self.heights_levels, self.total_strip_widths)]
### =================================================================================================================== ### 2. End of script ### ===================================================================================================================