Skip to content

Commit 025f16c

Browse files
Add variables to PlasticSection class to speed up computation; fix quiver scale; add relative tolerance to zip files; release 1.0.0
1 parent c95191d commit 025f16c

File tree

6 files changed

+47
-41
lines changed

6 files changed

+47
-41
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# sectionproperties
2-
[![Documentation Status](https://readthedocs.org/projects/sectionproperties/badge/?version=latest)](https://sectionproperties.readthedocs.io/en/latest/?badge=latest)
2+
[![Build Status](https://travis-ci.com/robbievanleeuwen/section-properties.svg?branch=master)](https://travis-ci.com/robbievanleeuwen/section-properties) [![Documentation Status](https://readthedocs.org/projects/sectionproperties/badge/?version=latest)](https://sectionproperties.readthedocs.io/en/latest/?badge=latest)
33

44

55
a python package for the analysis of arbitrary cross-sections using the finite element method written by Robbie van Leeuwen. *sectionproperties* can be used to determine section properties to be used in structural design and visualise cross-sectional stresses resulting from combinations of applied forces and bending moments.

sectionproperties/analysis/cross_section.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,12 @@ class PlasticSection:
15441544
:cvar elements: List of finite element objects describing the cross-section
15451545
mesh
15461546
:vartype elements: list[:class:`~sectionproperties.analysis.fea.Tri6`]
1547+
:cvar float f_top: Current force in the top region
1548+
:cvar c_top: Centroid of the force in the top region *(c_top_x, c_top_y)*
1549+
:type c_top: list[float, float]
1550+
:cvar c_bot: Centroid of the force in the bottom region
1551+
*(c_bot_x, c_bot_y)*
1552+
:type c_bot: list[float, float]
15471553
"""
15481554

15491555
def __init__(self, geometry, materials, debug):
@@ -1881,7 +1887,7 @@ def evaluate_force_eq(self, d, u, u_p):
18811887
self.plot_mesh(nodes, elements, element_list, self.materials)
18821888

18831889
# calculate force equilibrium
1884-
(f_top, f_bot, _, _) = (
1890+
(f_top, f_bot) = (
18851891
self.calculate_plastic_force(element_list, u, p))
18861892

18871893
# return the force norm
@@ -1926,16 +1932,7 @@ def pc_algorithm(self, u, dlim, axis, pc_region):
19261932
(d, r) = brentq(self.evaluate_force_eq, a, b, args=(u, u_p),
19271933
full_output=True, disp=False, xtol=1e-6, rtol=1e-6)
19281934

1929-
# get centroids of the areas
1930-
# TODO: consider saving f, c_top, c_bot as class variables so we don't
1931-
# have to run it again
1932-
p = np.array([d * u_p[0], d * u_p[1]])
1933-
mesh = self.create_plastic_mesh([p, u])
1934-
(nodes, elements, element_list) = self.get_elements(mesh)
1935-
(f_top, f_bot, c_top, c_bot) = (
1936-
self.calculate_plastic_force(element_list, u, p))
1937-
1938-
return (d, r, f_top, c_top, c_bot)
1935+
return (d, r, self.f_top, self.c_top, self.c_bot)
19391936

19401937
def calculate_plastic_force(self, elements, u, p):
19411938
"""Sums the forces above and below the axis defined by unit vector *u*
@@ -1948,9 +1945,8 @@ def calculate_plastic_force(self, elements, u, p):
19481945
:type u: :class:`numpy.ndarray`
19491946
:param p: Point on the axis
19501947
:type p: :class:`numpy.ndarray`
1951-
:return: Force in the top and bottom areas and centroids of these
1952-
forces *(f_top, f_bot, [c_top_x, c_top_y], [c_bot_x, c_bot_y])*
1953-
:rtype: tuple(float, float, list[float, float], list[float, float])
1948+
:return: Force in the top and bottom areas *(f_top, f_bot)*
1949+
:rtype: tuple(float, float)
19541950
"""
19551951

19561952
# initialise variables
@@ -1976,11 +1972,12 @@ def calculate_plastic_force(self, elements, u, p):
19761972
qx_bot += qx_el
19771973
qy_bot += qy_el
19781974

1979-
# calculate the centroid of the top and bottom segments
1980-
c_top = [qy_top / ea_top, qx_top / ea_top]
1981-
c_bot = [qy_bot / ea_bot, qx_bot / ea_bot]
1975+
# calculate the centroid of the top and bottom segments and save
1976+
self.c_top = [qy_top / ea_top, qx_top / ea_top]
1977+
self.c_bot = [qy_bot / ea_bot, qx_bot / ea_bot]
1978+
self.f_top = f_top
19821979

1983-
return(f_top, f_bot, c_top, c_bot)
1980+
return (f_top, f_bot)
19841981

19851982
def create_plastic_mesh(self, new_line=None):
19861983
"""Generates a triangular mesh of a deep copy of the geometry stored in
@@ -2317,31 +2314,38 @@ def plot_stress_vector(self, sigxs, sigys, title, pause):
23172314
# set up the colormap
23182315
cmap = cm.get_cmap(name='jet')
23192316

2317+
# initialise quiver plot list max scale
2318+
quiv_list = []
2319+
max_scale = 0
2320+
23202321
# plot the vectors
23212322
for (i, sigx) in enumerate(sigxs):
23222323
sigy = sigys[i]
23232324

23242325
# scale the colour with respect to the magnitude of the vector
23252326
c = np.hypot(sigx, sigy)
23262327

2327-
# The scale is defined by the scale of the first plot
2328-
# TODO: return all scales then use the largest one???
2328+
quiv = ax.quiver(
2329+
self.cross_section.mesh_nodes[:, 0],
2330+
self.cross_section.mesh_nodes[:, 1],
2331+
sigx, sigy, c, cmap=cmap)
2332+
2333+
# get the scale and store the max value
2334+
quiv._init()
2335+
max_scale = max(max_scale, quiv.scale)
2336+
quiv_list.append(quiv)
2337+
2338+
# update the colormap values
23292339
if i == 0:
23302340
c_min = min(c)
23312341
c_max = max(c)
2332-
2333-
quiv = ax.quiver(
2334-
self.cross_section.mesh_nodes[:, 0],
2335-
self.cross_section.mesh_nodes[:, 1],
2336-
sigx, sigy, c, cmap=cmap, scale=None)
23372342
else:
23382343
c_min = min(c_min, min(c))
23392344
c_max = max(c_max, max(c))
23402345

2341-
ax.quiver(
2342-
self.cross_section.mesh_nodes[:, 0],
2343-
self.cross_section.mesh_nodes[:, 1],
2344-
sigx, sigy, c, cmap=cmap, scale=quiv.scale)
2346+
# apply the scale
2347+
for quiv_plot in quiv_list:
2348+
quiv_plot.scale = max_scale
23452349

23462350
# apply the colourbar
23472351
v1 = np.linspace(c_min, c_max, 15, endpoint=True)

sectionproperties/pre/pre.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def clean_geometry(self):
124124

125125
return self.geometry
126126

127-
def zip_points(self, atol=1e-5):
127+
def zip_points(self, atol=1e-8, rtol=1e-5):
128128
"""Zips points that are close to each other. Searches through the point
129129
list and merges two points if there are deemed to be sufficiently
130130
close. The average value of the coordinates is used for the new point.
@@ -133,11 +133,17 @@ def zip_points(self, atol=1e-5):
133133
remaining point indices in the facet list.
134134
135135
:param float atol: Absolute tolerance for point zipping
136+
:param float rtol: Relative tolerance (to geometry extents) for point
137+
zipping
136138
"""
137139

138-
# TODO: implement rtol and choose better vals
139140
idx_to_remove = []
140141

142+
# determine rtol
143+
(x_min, x_max, y_min, y_max) = self.geometry.calculate_extents()
144+
geom_range = max(x_max - x_min, y_max - y_min)
145+
rel_tol = rtol * geom_range
146+
141147
# loop through the list of points
142148
for (i, pt1) in enumerate(self.geometry.points):
143149
# check all other points
@@ -152,7 +158,8 @@ def zip_points(self, atol=1e-5):
152158

153159
# if the points are sufficiently close together...
154160
# and the point has not already been removed
155-
if dist < atol and idx_2 not in idx_to_remove:
161+
if ((dist < atol or dist < rel_tol) and
162+
idx_2 not in idx_to_remove):
156163
# update point1 (average of point1 + point2)
157164
pt1[0] = 0.5 * (pt1[0] + pt2[0])
158165
pt1[1] = 0.5 * (pt1[1] + pt2[1])

sectionproperties/pre/sections.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,7 @@ def mirror_section(self, axis='x', mirror_point=None):
180180
elif axis == 'y':
181181
i = 0
182182
else:
183-
pass
184-
# TODO: raise error
183+
raise RuntimeError("Enter a valid axis: 'x' or 'y'")
185184

186185
# mirror all points
187186
for point in self.points:

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ def readme():
2323
install_requires.append('meshpy')
2424

2525
setup(name='sectionproperties',
26-
version='0.0.6',
26+
version='1.0.0',
2727
description=description_text(),
2828
long_description=readme(),
2929
long_description_content_type='text/markdown',
3030
classifiers=[
31-
'Development Status :: 2 - Pre-Alpha',
31+
'Development Status :: 5 - Production/Stable',
3232
'Environment :: Console',
3333
'Intended Audience :: Science/Research',
3434
'License :: OSI Approved :: MIT License',

todo.md

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)