""" Provide the ``Pile`` class.
"""
# -- Imports -----------------------------------------------------------------
from edafos.project import Project
from edafos.data import english_hpiles, si_hpiles
import numpy as np
# -- SoilProfile Class -------------------------------------------------------
[docs]class Pile(Project):
""" Class to represent a new driven or drilled pile.
.. warning::
Pay attention to the input units for each unit system that you
choose to use. Refer to the parameter definition below or the
:ref:`input_units` page.
"""
# -- Constructor ---------------------------------------------------------
[docs] def __init__(self, unit_system, pile_type, **kwargs):
"""
Args:
unit_system (str): The unit system for the project. Can only be
'English', or 'SI'. Properties inherited from the ``Project``
class.
pile_type (str): Type of driven pile. Available options are:
- ``concrete``: A rectangular (normally square) concrete pile.
Requires different keyword arguments depending on ``shape``.
Always requires ``length``.
- ``pipe_open``: An open-ended circular steel pipe pile.
Requires keyword arguments ``diameter``, ``thickness``,
``length``.
- ``pipe_closed``: A closed-ended circular steel pipe pile.
Requires keyword argument ``diameter``, ``length``.
- ``h_pile``: An H shape steel beam used as a pile.
Requires keyword argument ``shape``, ``length``.
- ``timber``: A circular timber pile.
Requires keyword argument ``diameter``, ``length``.
- ``cast-in-place``: A concrete cast-in-place pile.
Requires keyword argument ``diameter``, ``length``.
Keyword Args:
shape (str): Pile shape given pile type. For concrete piles the
options are ``square-solid``, ``square-hollow``,
``circle-closed``, ``circle-open``, ``hexagon`` and ``octagon``.
For H-piles, see :numref:`english_hpile_table` for stored
sections.
side (float): :math:`\\alpha`: Side length of square, hexagonal and
octagonal piles, at the top.
- For **SI**: Enter side length in **centimeters**.
- For **English**: Enter side length in **inches**.
diameter (float): :math:`d`: Outer diameter at the top for circular
piles and inner diameter of concrete square hollow piles.
- For **SI**: Enter diameter in **centimeters**.
- For **English**: Enter diameter in **inches**.
thickness (float): :math:`t`: Wall thickness of steel pipe piles
and concrete circular open-ended piles.
- For **SI**: Enter thickness in **centimeters**.
- For **English**: Enter thickness in **inches**.
length (float): :math:`L_t`: Total length of pile.
- For **SI**: Enter length in **meters**.
- For **English**: Enter length in **feet**.
pen_depth (float): :math:`D_p`: Penetration depth, the part of the
pile that is embedded in the ground. **Important:** if a
penetration depth is not entered, it will be assumed equal to
the total length of the pile.
- For **SI**: Enter depth in **meters**.
- For **English**: Enter depth in **feet**.
nf_zone (float): :math:`D_{nf}`: No-friction zone; this is the
length of a segment measured from ground level where frictional
resistance does not contribute to pile capacity.
- For **SI**: Enter depth in **meters**.
- For **English**: Enter depth in **feet**.
taper_dims (list of lists): [:math:`d_i,l_i`]: For tapered piles,
enter the width of the pile, :math:`d_i`, at a length,
:math:`l_i`, measured from the top of the pile. The program
allows for multiple tapered sections. Enter as a list, for
example: [[12,4], [10,4],]
- For **SI**: Enter width in **centimeters** and length
in **meters**.
- For **English**: Enter width in **inches** and length
in **feet**.
"""
super().__init__(unit_system=unit_system)
# -- Check for valid pile type ---------------------------------------
allowed_piles = ['concrete', 'pipe-open', 'pipe-closed', 'h-pile',
'timber', 'cast-in-place']
if pile_type in allowed_piles:
self.pile_type = pile_type
else:
raise ValueError("'{}' not recognized. Pile type can only be {}."
"".format(pile_type, allowed_piles))
# -- Check for valid kwargs ------------------------------------------
allowed_keys = ['shape', 'side', 'diameter', 'thickness', 'length',
'pen_depth', 'nf_zone', 'taper_dims']
for key in kwargs:
if key not in allowed_keys:
raise AttributeError("'{}' is not a valid attribute.\nThe "
"allowed attributes are: {}"
"".format(key, allowed_keys))
# -- Assign values ---------------------------------------------------
self.shape = kwargs.get('shape', None)
self.side = kwargs.get('side', None)
self.diameter = kwargs.get('diameter', None)
self.thickness = kwargs.get('thickness', None)
self.length = kwargs.get('length', None)
self.pen_depth = kwargs.get('pen_depth', self.length)
self.nf_zone = kwargs.get('nf_zone', None)
self.taper_dims = kwargs.get('taper_dims', None)
# -- Reject negative or zero values ----------------------------------
for i in [self.side, self.diameter, self.thickness, self.length,
self.pen_depth, self.nf_zone]:
if i is None:
pass
elif type(i) not in [int, float]:
raise ValueError("Cannot parse non-numerical pile properties. "
"Did you enter a string?")
try:
if i <= 0:
raise ValueError("Cannot parse negative or zero pile "
"properties.")
except TypeError:
pass
# TODO: Fix these checks so they return the missing required attr only
# TODO: Also throw a warning if additional, unnecessary attr are given
# -- Checks for concrete piles ---------------------------------------
if self.pile_type == 'concrete':
allowed_shape = ['square-solid', 'square-hollow', 'circle-closed',
'circle-open', 'hexagon', 'octagon']
if self.shape not in allowed_shape:
raise ValueError("'{}' is not a valid value for concrete pile "
"shape.\nThe allowed values are: {}"
"".format(self.shape, allowed_shape))
else:
pass
shape_reqs = {
'square-solid': [self.side, self.length],
'square-hollow': [self.side, self.diameter, self.length],
'circle-closed': [self.diameter, self.length],
'circle-open': [self.diameter, self.thickness, self.length],
'hexagon': [self.side, self.length],
'octagon': [self.side, self.length],
}
shape_kwgs = {
'square-solid': ['side', 'length'],
'square-hollow': ['side', 'diameter', 'length'],
'circle-closed': ['diameter', 'length'],
'circle-open': ['diameter', 'thickness', 'length'],
'hexagon': ['side', 'length'],
'octagon': ['side', 'length'],
}
for shape in allowed_shape:
if (self.shape == shape) and (None in shape_reqs[shape]):
raise ValueError("Missing required properties for pile "
"shape: '{}'.\nEnter values for: {}."
"".format(shape, shape_kwgs[shape]))
else:
pass
# Fix assignments and units
self.side = (self.side * self.set_units('pile_diameter')
if self.side is not None else None)
self.diameter = (self.diameter * self.set_units('pile_diameter')
if self.diameter is not None else None)
self.thickness = (self.thickness * self.set_units('pile_diameter')
if self.thickness is not None else None)
self.length = self.length * self.set_units('pile_length')
self.pen_depth = self.pen_depth * self.set_units('pile_length')
self.nf_zone = (self.nf_zone * self.set_units('pile_length')
if self.nf_zone is not None else None)
if self.shape in ['square-solid', 'hexagon', 'octagon']:
self.diameter = None
self.thickness = None
elif self.shape == 'square-hollow':
self.thickness = None
elif self.shape == 'circle-closed':
self.side = None
self.thickness = None
else:
self.side = None
# Check for taper dims diameters
if self.taper_dims is None:
pass
else:
if len(self.taper_dims) > 1:
for i, ii in zip(self.taper_dims[:-1], self.taper_dims[1:]):
if ii[0] > i[0]:
raise ValueError("Subsequent taper diameters "
"cannot be larger than preceding "
"taper diameters. Please correct.")
else:
pass
else:
pass
diam_list = []
if self.shape in ['circle-closed', 'circle-open']:
for i in self.taper_dims:
if i[0] > self.diameter.magnitude:
raise ValueError("Cannot have taper diameter larger"
" than top pile diameter.")
else:
diam_list.append(i[0])
i[0] = i[0] * self.set_units('pile_diameter')
if (len(set(diam_list)) == 1) and (diam_list[0] ==
self.diameter.magnitude):
raise ValueError("This is not a tapered pile. All "
"tapered diameters are the same and "
"equal to the top diameter.")
else:
for i in self.taper_dims:
if i[0] > self.side.magnitude:
raise ValueError("Cannot have taper diameter larger"
" than top pile diameter.")
else:
diam_list.append(i[0])
i[0] = i[0] * self.set_units('pile_diameter')
if (len(set(diam_list)) == 1) and (diam_list[0] ==
self.side.magnitude):
raise ValueError("This is not a tapered pile. All "
"tapered diameters are the same and "
"equal to the top diameter.")
# -- Checks for pipe open piles --------------------------------------
elif self.pile_type == 'pipe-open':
if (self.diameter is None) or (self.thickness is None) or \
(self.length is None):
raise ValueError("Missing required properties for pile type: "
"'{}'.\nEnter values for: ['diameter', "
"'thickness', 'length]."
"".format(self.pile_type))
else:
pass
if self.taper_dims is not None:
raise ValueError("Open-ended steel pipe piles cannot be "
"tapered.")
else:
pass
# Fix assignments and units
self.shape = 'circular'
self.side = None
self.diameter = self.diameter * self.set_units('pile_diameter')
self.thickness = self.thickness * self.set_units('pile_diameter')
self.length = self.length * self.set_units('pile_length')
self.pen_depth = self.pen_depth * self.set_units('pile_length')
self.nf_zone = (self.nf_zone * self.set_units('pile_length')
if self.nf_zone is not None else None)
# -- Checks for pipe closed piles ------------------------------------
elif self.pile_type == 'pipe-closed':
if (self.diameter is None) or (self.length is None) \
or (self.thickness is None):
raise ValueError("Missing required properties for pile type: "
"'{}'.\nEnter values for: ['diameter', "
"'thickness', 'length']."
"".format(self.pile_type))
else:
pass
if self.taper_dims is not None:
raise ValueError("Closed-ended steel pipe piles cannot be "
"tapered.")
else:
pass
# Fix assignments and units
self.shape = 'circular'
self.side = None
self.diameter = self.diameter * self.set_units('pile_diameter')
self.thickness = self.thickness * self.set_units('pile_diameter')
self.length = self.length * self.set_units('pile_length')
self.pen_depth = self.pen_depth * self.set_units('pile_length')
self.nf_zone = (self.nf_zone * self.set_units('pile_length')
if self.nf_zone is not None else None)
# -- Checks for H-Piles ----------------------------------------------
# TODO: Add logic for custom H-pile shapes
elif self.pile_type == 'h-pile':
if self.length is None:
raise ValueError("Enter value for 'length'.")
elif self.unit_system == 'English':
if self.shape not in english_hpiles:
raise ValueError(
"'{}' is not a valid shape for English H-Piles."
"\nThe allowed values are: {}"
"".format(self.shape, english_hpiles.keys()))
else:
pass
elif self.unit_system == 'SI':
if self.shape not in si_hpiles:
raise ValueError(
"'{}' is not a valid shape for S.I. H-Piles."
"\nThe allowed values are: {}"
"".format(self.shape, si_hpiles.keys()))
else:
pass
if self.taper_dims is not None:
raise ValueError("H-Piles cannot be tapered.")
else:
pass
# Fix assignments and units
self.side = None
self.diameter = None
self.thickness = None
self.length = self.length * self.set_units('pile_length')
self.pen_depth = self.pen_depth * self.set_units('pile_length')
self.nf_zone = (self.nf_zone * self.set_units('pile_length')
if self.nf_zone is not None else None)
# -- Checks for timber and cast-in-place piles -----------------------
# TODO: Most likely cast-in-place will have their own checks
elif self.pile_type in ['timber', 'cast-in-place']:
if (self.diameter is None) or (self.length is None):
raise ValueError("Missing required properties for pile type: "
"'{}'.\nEnter values for: ['diameter', "
"'length].".format(self.pile_type))
else:
pass
# Fix assignments and units
self.shape = 'circular'
self.side = None
self.diameter = self.diameter * self.set_units('pile_diameter')
self.thickness = None
self.length = self.length * self.set_units('pile_length')
self.pen_depth = self.pen_depth * self.set_units('pile_length')
self.nf_zone = (self.nf_zone * self.set_units('pile_length')
if self.nf_zone is not None else None)
# Check for taper dims diameters
if self.taper_dims is None:
pass
else:
if len(self.taper_dims) > 1:
for i, ii in zip(self.taper_dims[:-1], self.taper_dims[1:]):
if ii[0] > i[0]:
raise ValueError("Subsequent taper diameters "
"cannot be larger than preceding "
"taper diameters. Please correct.")
else:
pass
else:
pass
diam_list = []
for i in self.taper_dims:
if i[0] > self.diameter.magnitude:
raise ValueError("Cannot have taper diameter larger"
" than top pile diameter.")
else:
diam_list.append(i[0])
i[0] = i[0] * self.set_units('pile_diameter')
if (len(set(diam_list)) == 1) and (diam_list[0] ==
self.diameter.magnitude):
raise ValueError("This is not a tapered pile. All "
"tapered diameters are the same and "
"equal to the top diameter.")
else:
pass
# -- Taper dims checks -----------------------------------------------
if self.taper_dims is None:
pass
else:
if type(self.taper_dims) is not list:
raise ValueError("Taper dims must be a list of lists.")
elif len(self.taper_dims) == 0:
raise ValueError("Taper dims list cannot be empty.")
else:
pass
taper_length = 0
for i in self.taper_dims:
if (type(i) is not list) or (len(i) != 2):
raise ValueError("Taper dims must be a list of lists, "
"i.e. [[d,l],].")
elif (type(i[0].magnitude) not in [int, float]) \
or (type(i[1]) not in [int, float]):
raise ValueError("Cannot parse non-numerical taper "
"dimensions. Did you enter a string?")
elif (i[0].magnitude <= 0) or (i[1] <= 0):
raise ValueError("Cannot parse negative or zero taper "
"dimensions. Please correct.")
else:
taper_length = taper_length + i[1]
i[1] = i[1] * self.set_units('pile_length')
if taper_length != self.length.magnitude:
raise ValueError("Sum of lengths of tapered portions does "
"not equal total pile length")
else:
pass
# -- Static method for rectangle area ------------------------------------
[docs] @staticmethod
def area_of_shape(ad, shape, t=None, ad2=None, h=None):
""" Static method that calculates the area of a given shape.
Args:
ad (float): Length of side or diameter.
shape (str): Options are ``square``, ``hexagon``, ``octagon``,
``circle``, ``ring``, ``trapezoid``, ``cone``.
t (float): Thickness of pile wall.
ad2 (float): Additional length of side or diameter to obtain
side area.
h (float): Segment height to obtain side area.
Returns:
float: Area of shape (unitless)
"""
allowed = ['square', 'hexagon', 'octagon', 'circle', 'ring',
'trapezoid', 'cone']
if shape not in allowed:
raise ValueError("Shape can be {} only.".format(allowed))
else:
pass
if shape == 'square':
area = ad ** 2
elif shape == 'hexagon':
area = (3/2) * np.sqrt(3) * (ad**2)
elif shape == 'octagon':
area = 2 * (1 + np.sqrt(2)) * (ad**2)
elif shape == 'circle':
area = np.pi * (ad ** 2) / 4
elif shape == 'ring':
area = np.pi * ((ad ** 2) - (ad - 2 * t) ** 2) / 4
elif shape == 'trapezoid':
area = ((ad + ad2) / 2) * h
else: # Cone -- http://mathworld.wolfram.com/ConicalFrustum.html
s = np.sqrt((((ad - ad2)/2) ** 2) + (h ** 2))
area = np.pi * ((ad + ad2)/2) * s
return area
# -- Private method for pile a/d at z ------------------------------------
[docs] def _pile_a_d(self, z):
""" A private method that returns the side, :math:`a`, or diameter,
:math:`d`, of a pile at a depth :math:`z`.
Args:
z (float): Vertical depth to the point of interest, measured from
the top of the soil profile.
- For **SI**: Enter depth, *z*, in **meters**.
- For **English**: Enter depth, *z*, in **feet**.
Returns:
Quantity: Side :math:`a`, or diameter, :math:`d`.
"""
z = z * self.set_units('length')
# The length x from the top of the pile is defined as
x = self.length - self.pen_depth + z
if self.pile_type == 'concrete':
if self.shape in ['square-solid', 'square-hollow', 'hexagon',
'octagon']:
if self.taper_dims is None:
di = [self.side.magnitude, self.side.magnitude]
li = [0, self.length.magnitude]
else:
di = [self.side.magnitude] + [i[0].magnitude for i in
self.taper_dims]
li = [0] + [i[1].magnitude for i in self.taper_dims]
li = np.cumsum(li)
else:
if self.taper_dims is None:
di = [self.diameter.magnitude, self.diameter.magnitude]
li = [0, self.length.magnitude]
else:
di = [self.diameter.magnitude] + [i[0].magnitude for i in
self.taper_dims]
li = [0] + [i[1].magnitude for i in self.taper_dims]
li = np.cumsum(li)
elif self.pile_type in ['pipe-open', 'pipe-closed']:
di = [self.diameter.magnitude, self.diameter.magnitude]
li = [0, self.length.magnitude]
else: # Timber and cast-in-place piles
if self.taper_dims is None:
di = [self.diameter.magnitude, self.diameter.magnitude]
li = [0, self.length.magnitude]
else:
di = [self.diameter.magnitude] + [i[0].magnitude for i in
self.taper_dims]
li = [0] + [i[1].magnitude for i in self.taper_dims]
li = np.cumsum(li)
return np.interp(x.magnitude, li, di) * self.set_units('pile_diameter')
# -- Method for cross sectional area at z --------------------------------
[docs] def xsection_area(self, z, soil_plug=False, box_area=False):
""" Method that returns the pile cross sectional area at a depth,
:math:`z`, from ground surface.
.. warning::
This method was made for bearing capacity calculations.
As such, it returns the relevant cross sectional area. For example,
for steel pipe closed-ended piles, it will return the circle and not
the ring area.
TODO: For concrete square hollow piles it currently returns solid area
Args:
z (float): Vertical depth to the point of interest, measured from
the top of the soil profile.
- For **SI**: Enter depth, *z*, in **meters**.
- For **English**: Enter depth, *z*, in **feet**.
soil_plug (bool): If ``TRUE``, the method returns the full area of
open-ended piles.
box_area (bool): For H-piles, if set to ``TRUE``, the method
returns the box area.
Returns:
Quantity: The cross sectional area of the pile w/ units.
"""
if z < 0:
raise ValueError("Depth z cannot be negative here.")
else:
pass
# The length x from the top of the pile is defined as
x = self.length.magnitude - self.pen_depth.magnitude + z
if (x < 0) or (x > self.length.magnitude):
area = 0 * self.set_units('pile_xarea')
elif self.pile_type == 'concrete':
if self.shape in ['square-solid', 'square-hollow']:
area = self.area_of_shape(self._pile_a_d(z), 'square')
elif self.shape == 'hexagon':
area = self.area_of_shape(self._pile_a_d(z), 'hexagon')
elif self.shape == 'octagon':
area = self.area_of_shape(self._pile_a_d(z), 'octagon')
elif self.shape == 'circle-closed':
area = self.area_of_shape(self._pile_a_d(z), 'circle')
else: # circle-open
if soil_plug:
area = self.area_of_shape(self._pile_a_d(z), 'circle')
else:
area = self.area_of_shape(self._pile_a_d(z), 'ring',
self.thickness)
elif self.pile_type == 'pipe-open':
if soil_plug:
area = self.area_of_shape(self._pile_a_d(z), 'circle')
else:
area = self.area_of_shape(self._pile_a_d(z), 'ring',
self.thickness)
elif self.pile_type == 'pipe-closed':
area = self.area_of_shape(self._pile_a_d(z), 'circle')
elif self.pile_type == 'h-pile':
if box_area:
area = english_hpiles[self.shape]['box_area'] \
* self.set_units('pile_xarea')
else:
area = english_hpiles[self.shape]['area'] \
* self.set_units('pile_xarea')
else: # Timber and cast-in-place piles
area = self.area_of_shape(self._pile_a_d(z), 'circle')
# Had to convert area from in2 to ft2 because unit toe resistance units
# were not correctly formatted
return area.to(self.set_units('pile_xarea_alt'))
# -- Method for side area between z1, z2 ---------------------------------
[docs] def side_area(self, z1, z2, box_area=False, inside=False):
""" Method that returns the side area for a section of the pile defined
by z1 and z2.
Args:
z1 (float): Vertical depth to the highest point of interest,
measured from the top of the soil profile.
- For **SI**: Enter depth, *z1*, in **meters**.
- For **English**: Enter depth, *z1*, in **feet**.
z2 (float): Vertical depth to the lowest point of interest,
measured from the top of the soil profile.
- For **SI**: Enter depth, *z1*, in **meters**.
- For **English**: Enter depth, *z1*, in **feet**.
box_area (bool): For H-piles, if set to ``TRUE``, the method
returns the box area.
inside (bool): For open steel pipe piles only. If TRUE, it returns
the inside area of the pile for plugged calculations.
Returns:
Quantity: The side area of the pile w/ units between z1 and z2.
"""
if (z1 < 0) or (z2 < 0):
raise ValueError("Depth z cannot be negative here.")
elif z2 <= z1:
raise ValueError("z2 must be larger than z1")
else:
pass
# The length x from the top of the pile is defined as
x1 = self.length.magnitude - self.pen_depth.magnitude + z1
x2 = self.length.magnitude - self.pen_depth.magnitude + z2
h = (z2 - z1) * self.set_units('pile_length')
# TODO: Give these limits another thought, maybe not return zero.
if (x1 < 0) or (x1 > self.length.magnitude) or (x2 < 0) or \
(x2 > self.length.magnitude):
area = 0 * self.set_units('pile_xarea')
elif self.pile_type == 'concrete':
if self.shape in ['square-solid', 'square-hollow']:
area = 4 * self.area_of_shape(ad=self._pile_a_d(z1),
shape='trapezoid',
ad2=self._pile_a_d(z2), h=h)
elif self.shape == 'hexagon':
area = 6 * self.area_of_shape(ad=self._pile_a_d(z1),
shape='trapezoid',
ad2=self._pile_a_d(z2), h=h)
elif self.shape == 'octagon':
area = 8 * self.area_of_shape(ad=self._pile_a_d(z1),
shape='trapezoid',
ad2=self._pile_a_d(z2), h=h)
else: # circle-closed and circle-open
area = self.area_of_shape(ad=self._pile_a_d(z1),
shape='cone',
ad2=self._pile_a_d(z2), h=h)
elif self.pile_type in ['pipe-open', 'pipe-closed']:
if (self.pile_type == 'pipe-open') and inside:
t = self.thickness.magnitude
area = self.area_of_shape(ad=(self._pile_a_d(z1) - 2*t *
self.set_units('pile_diameter')
),
shape='cone',
ad2=(self._pile_a_d(z2) - 2*t *
self.set_units('pile_diameter')
),
h=h)
else:
area = self.area_of_shape(ad=self._pile_a_d(z1), shape='cone',
ad2=self._pile_a_d(z2), h=h)
# TODO: adjust to accept si piles as well
elif self.pile_type == 'h-pile':
if box_area:
area = (english_hpiles[self.shape]['box_perimeter']
* self.set_units('pile_diameter')) * h
else:
area = (english_hpiles[self.shape]['perimeter']
* self.set_units('pile_diameter')) * h
else: # Timber and cast-in-place piles
area = self.area_of_shape(ad=self._pile_a_d(z1), shape='cone',
ad2=self._pile_a_d(z2), h=h)
return area.to(self.set_units('pile_side_area'))
# -- Method that returns list of relevant z's ----------------------------
[docs] def z_of_pile(self):
""" Method that returns a list of depths, :math:`z`, for the pile that
correspond to the top of the pile (if below ground), the tip of the
pile and inflection points if tapered.
The assumption here is that :math:`z = x - L_t + D_p`, where :math:`x`
is a point along the length of the pile. Therefore, for :math:`x = 0`
we get the depth :math:`z_{pile.top}` at the top of the pile (if
:math:`D_p > L_t`) and for :math:`x = L_t`, we get the depth
:math:`z_{pile.toe}` at the toe (aka tip) of the pile. If the pile is
tapered, :math:`x` along inflection points will produce the
corresponding :math:`z`.
Returns:
A list of depths, :math:`z` (unitless).
"""
z_list = []
# Get z_pile-top if Dp > Lt
if self.pen_depth.magnitude > self.length.magnitude:
z = self.pen_depth.magnitude - self.length.magnitude
z_list.append(z)
else:
pass
# Get the remaining z's
if self.taper_dims is None:
z = self.pen_depth.magnitude
z_list.append(z)
else:
taper_l = []
for i in self.taper_dims:
taper_l.append(i[1].magnitude)
taper_l = np.cumsum(taper_l)
for ii in taper_l:
z = ii - self.length.magnitude + self.pen_depth.magnitude
if z > 0:
z_list.append(z)
else:
pass
return z_list
# -- Method for string representation ------------------------------------
def __str__(self):
return "Pile Details:\n------------\n" \
"Type: {0.pile_type}\n" \
"Shape: {0.shape}\n" \
"Side: {0.side}\n" \
"Diameter: {0.diameter}\n" \
"Thickness: {0.thickness}\n" \
"Total Length: {0.length}\n" \
"Penetration Depth: {0.pen_depth}\n" \
"No-Friction Zone: {0.nf_zone}\n" \
"Taper Dims [[d,l],]: {0.taper_dims}".format(self)