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