Source code for sfsimodels.models.foundations

from collections import OrderedDict

import numpy as np

from sfsimodels.exceptions import ModelError
from sfsimodels.models.abstract_models import PhysicalObject
from sfsimodels import checking_tools as ct
from sfsimodels.exceptions import deprecation


[docs]class Foundation(PhysicalObject): """ An object to describe building foundations """ _id = None name = None _width = None # [m], The length of the foundation in the direction of shaking _length = None # [m], The length of the foundation perpendicular to the shaking _depth = None # [m], The depth of the foundation from the surface _height = None # [m], The height of the foundation from base of foundation to ground floor _density = None # [kg/m3], Density of foundation _mass = None # kg base_type = "foundation" type = "foundation" _tolerance = 0.0001 # consistency tolerance _extra_class_inputs = [ "id", "name", "base_type", "type", "width", "length", "depth", "height", "density", "mass" ] def __str__(self): return "Foundation id: {0}, name: {1}".format(self.id, self.name) def __format__(self, format_spec): return "Foundation" def __init__(self): super(Foundation, self).__init__() self.inputs = [ "id", "name", "base_type", "type", "width", "length", "depth", "height", "density", "mass" ] @property def ancestor_types(self): return super(Foundation, self).ancestor_types + ["foundation"] @property def id(self): return self._id @id.setter def id(self, value): self._id = value @property def area(self): """ Foundation area in plan :return: """ try: return self.length * self.width except TypeError: return None @property def length(self): """ Length of the foundation (typically in the out-of-plane direction) :return: """ return self._length @property def width(self): """ Length of the foundation (typically in the in-plane direction) :return: """ return self._width @property def height(self): """ Measure of the base of the foundation to the top :return: """ return self._height @property def depth(self): """ Measure of the base of the foundation to the surface of the soil :return: """ return self._depth @property def mass(self): """ The mass of the whole foundation :return: """ return self._mass @property def density(self): """ The mass density of the foundation [kg/m3] :return: """ return self._density @property def weight(self): """ The weight of the foundation [N] :return: """ return self.mass * 9.8 @length.setter def length(self, value): if value is None or value == "": return self._length = float(value) @width.setter def width(self, value): if value is None or value == "": return self._width = float(value) @height.setter def height(self, value): if value is None or value == "": return self._height = float(value) @depth.setter def depth(self, value): if value is None or value == "": return self._depth = float(value) @density.setter def density(self, value, override=False): if value is None or value == "": return density = self._calc_density() if density is not None and not np.isclose(density, value, rtol=self._tolerance) and not override: raise ModelError("Density inconsistent with set mass") self._density = float(value) mass = self._calc_mass() if mass is not None and not ct.isclose(mass, self.mass): self.mass = mass @mass.setter def mass(self, value, override=False): if value is None or value == "": return mass = self._calc_mass() if mass is not None and not ct.isclose(mass, value, rel_tol=self._tolerance) and not override: raise ModelError("Mass inconsistent with set density") self._mass = float(value) density = self._calc_density() if density is not None and not ct.isclose(density, self.density, rel_tol=self._tolerance): self.density = density def _calc_mass(self): try: return self.area * self.height * self.density except TypeError: return None def _calc_density(self): try: return self.mass / (self.area * self.height) except TypeError: return None except ZeroDivisionError: return None
[docs]class RaftFoundation(Foundation): """ An extension to the Foundation Object to describe Raft foundations """ ftype = "raft" type = "foundation_raft" _extra_class_inputs = [] def __str__(self): return "FoundationRaft id: {0}, name: {1}".format(self.id, self.name) def __init__(self): super(RaftFoundation, self).__init__() self.inputs = self.inputs + self._extra_class_inputs @property def ancestor_types(self): return super(RaftFoundation, self).ancestor_types + ["foundation_raft"] @property def i_ww(self): """ Contact moment-area around the width axis :return: """ return self.width * self.length ** 3 / 12 @property def i_ll(self): """ Contact moment-area around the length axis :return: """ return self.length * self.width ** 3 / 12
[docs]class PadFoundation(Foundation): """ An extension to the Foundation Object to describe Pad foundations """ ftype = "pad" type = "foundation_pad" n_pads_l = 4 # Number of pads in length direction n_pads_w = 3 # Number of pads in width direction pad_length = 1.0 # m # TODO: make parameters protected pad_width = 1.0 # m _extra_class_inputs = [ "n_pads_l", "n_pads_w", "pad_length", "pad_width", ] def __str__(self): return "PadFoundation id: {0}, name: {1}".format(self.id, self.name) def __init__(self): super(PadFoundation, self).__init__() self.inputs += self._extra_class_inputs @property def ancestor_types(self): return super(PadFoundation, self).ancestor_types + ["foundation_pad"] @property def i_ww(self): """ Second moment of inertia around the width axis. :return: """ d_values = [] for i in range(self.n_pads_l): d_values.append(self.pad_position_l(i)) d_values = np.array(d_values) - self.length / 2 area_d_sqrd = sum(self.pad_area * d_values ** 2) * self.n_pads_w i_second = self.pad_i_ww * self.n_pads return area_d_sqrd + i_second @property def i_ll(self): """ Second moment of inertia around the length axis. :return: """ d_values = [] for i in range(self.n_pads_w): d_values.append(self.pad_position_w(i)) d_values = np.array(d_values) - self.width / 2 area_d_sqrd = sum(self.pad_area * d_values ** 2) * self.n_pads_l i_second = self.pad_i_ll * self.n_pads return area_d_sqrd + i_second @property def n_pads(self): """ Total number of pad footings :return: """ return self.n_pads_w * self.n_pads_l @property def pad_area(self): """ Area of a pad :return: """ return self.pad_length * self.pad_width @property def pad_i_ww(self): """ Second moment of inertia of a single pad around the width axis. :return: """ return self.pad_length ** 3 * self.pad_width / 12 @property def pad_i_ll(self): """ Second moment of inertia of a single pad around the length axis. :return: """ return self.pad_width ** 3 * self.pad_length / 12 @property def area(self): """ Contact area of the whole foundation in plan :return: """ return self.n_pads * self.pad_area
[docs] def pad_position_l(self, i): """ Determines the position of the ith pad in the length direction. Assumes equally spaced pads. :param i: ith number of pad in length direction (0-indexed) :return: """ if i >= self.n_pads_l: raise ModelError("pad index out-of-bounds") return (self.length - self.pad_length) / (self.n_pads_l - 1) * i + self.pad_length / 2
[docs] def pad_position_w(self, i): """ Determines the position of the ith pad in the width direction. Assumes equally spaced pads. :param i: ith number of pad in width direction (0-indexed) :return: """ if i >= self.n_pads_w: raise ModelError("pad index out-of-bounds") return (self.width - self.pad_width) / (self.n_pads_w - 1) * i + self.pad_width / 2
[docs]class FoundationPad(PadFoundation): def __init__(self): deprecation("FoundationPad class is deprecated, use PadFoundation.") super(FoundationPad, self).__init__()
[docs]class FoundationRaft(RaftFoundation): def __init__(self): deprecation("Foundation class is deprecated, use RaftFoundation.") super(FoundationRaft, self).__init__()