Skip to content

Commit 848ab96

Browse files
Merge pull request #243 from robbievanleeuwen/stress_warping_reqs
Loosen warping reqs for stress analysis
2 parents 204be8c + c1c360b commit 848ab96

File tree

3 files changed

+117
-28
lines changed

3 files changed

+117
-28
lines changed

docs/source/rst/analysis.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ A stress analysis calculates the section stresses arising from a set of forces
7171
and moments. Executing this method returns a :class:`~sectionproperties.analysis.section.StressResult`
7272
object which stores the section stresses and provides stress plotting functions.
7373

74-
.. note:: A geometric and warping analysis must be performed on the Section
75-
object before a stress analysis is carried out.
74+
.. note:: A geometric analysis must be performed on the Section object before a stress
75+
analysis is carried out. Further, if the shear force or twisting moment is non-zero
76+
a warping analysis must also be performed.
7677

7778
.. warning:: The stress analysis in *sectionproperties* is linear-elastic and does not
7879
account for the yielding of materials or any non-linearities.

sectionproperties/analysis/section.py

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,8 +1043,8 @@ def calc_plastic(progress=None):
10431043
calc_plastic()
10441044

10451045
def calculate_stress(self, N=0, Vx=0, Vy=0, Mxx=0, Myy=0, M11=0, M22=0, Mzz=0):
1046-
"""Calculates the cross-section stress resulting from design actions and returns a
1047-
:class:`~sectionproperties.analysis.section.StressPost` object allowing
1046+
"""Calculates the cross-section stress resulting from design actions and returns
1047+
a :class:`~sectionproperties.analysis.section.StressPost` object allowing
10481048
post-processing of the stress results.
10491049
10501050
:param float N: Axial force
@@ -1055,33 +1055,35 @@ def calculate_stress(self, N=0, Vx=0, Vy=0, Mxx=0, Myy=0, M11=0, M22=0, Mzz=0):
10551055
:param float M11: Bending moment about the centroidal 11-axis
10561056
:param float M22: Bending moment about the centroidal 22-axis
10571057
:param float Mzz: Torsion moment about the centroidal zz-axis
1058+
10581059
:return: Object for post-processing cross-section stresses
10591060
:rtype: :class:`~sectionproperties.analysis.section.StressPost`
10601061
1061-
Note that a geometric and warping analysis must be performed before a stress analysis is
1062-
carried out::
1062+
Note that a geometric analysis must be performed prior to performing a stress
1063+
analysis. Further, if the shear force or torsion is non-zero a warping analysis
1064+
must also be performed::
10631065
10641066
section = Section(geometry)
10651067
section.calculate_geometric_properties()
10661068
section.calculate_warping_properties()
10671069
stress_post = section.calculate_stress(N=1e3, Vy=3e3, Mxx=1e6)
10681070
1069-
:raises RuntimeError: If a geometric and warping analysis have not been performed prior to
1070-
calling this method
1071+
:raises RuntimeError: If a geometric and warping analysis (if required) have not
1072+
been performed prior to calling this method
10711073
"""
10721074

10731075
# check that a geometric and warping analysis has been performed
1074-
if (
1075-
None
1076-
in [
1077-
self.section_props.area,
1078-
self.section_props.ixx_c,
1079-
self.section_props.cx,
1080-
self.section_props.j,
1081-
]
1082-
and self.section_props.omega is None
1083-
):
1084-
err = "Perform a geometric and warping analysis before carrying out a stress analysis."
1076+
if None in [
1077+
self.section_props.area,
1078+
self.section_props.ixx_c,
1079+
self.section_props.cx,
1080+
]:
1081+
err = "Perform a geometric analysis before carrying out a stress analysis."
1082+
raise RuntimeError(err)
1083+
1084+
if self.section_props.omega is None and (Vx != 0 or Vy != 0 or Mzz != 0):
1085+
err = "Perform a warping analysis before carrying out a stress analysis "
1086+
err += "with non-zero shear forces or torsion moment."
10851087
raise RuntimeError(err)
10861088

10871089
def calc_stress(progress=None):
@@ -1115,6 +1117,16 @@ def calc_stress(progress=None):
11151117

11161118
# loop through all elements in the material group
11171119
for el in group.elements:
1120+
# get element omega and psi
1121+
if self.section_props.omega is None:
1122+
omega_el = None
1123+
psi_shear_el = None
1124+
phi_shear_el = None
1125+
else:
1126+
omega_el = self.section_props.omega[el.node_ids]
1127+
psi_shear_el = self.section_props.psi_shear[el.node_ids]
1128+
phi_shear_el = self.section_props.phi_shear[el.node_ids]
1129+
11181130
(
11191131
sig_zz_n_el,
11201132
sig_zz_mxx_el,
@@ -1148,9 +1160,9 @@ def calc_stress(progress=None):
11481160
phi,
11491161
j,
11501162
nu,
1151-
self.section_props.omega[el.node_ids],
1152-
self.section_props.psi_shear[el.node_ids],
1153-
self.section_props.phi_shear[el.node_ids],
1163+
omega_el,
1164+
psi_shear_el,
1165+
phi_shear_el,
11541166
Delta_s,
11551167
)
11561168

@@ -2214,6 +2226,12 @@ def get_stress_at_points(
22142226
:rtype: List[Union[Tuple[float, float, float], None]]
22152227
"""
22162228

2229+
# ensure warping analysis completed for shear and torsion
2230+
if self.section_props.omega is None and (Vx != 0 or Vy != 0 or Mzz != 0):
2231+
err = "Perform a warping analysis before carrying out a stress analysis "
2232+
err += "with non-zero shear forces or torsion moment."
2233+
raise RuntimeError(err)
2234+
22172235
action = {
22182236
"N": N,
22192237
"Mxx": Mxx,
@@ -2251,26 +2269,46 @@ def get_stress_at_points(
22512269
sig = None
22522270
elif len(tri_ids) == 1:
22532271
tri = self.elements[tri_ids[0]]
2272+
2273+
if self.section_props.omega is None:
2274+
omega_el = None
2275+
psi_shear_el = None
2276+
phi_shear_el = None
2277+
else:
2278+
omega_el = self.section_props.omega[tri.node_ids]
2279+
psi_shear_el = self.section_props.psi_shear[tri.node_ids]
2280+
phi_shear_el = self.section_props.phi_shear[tri.node_ids]
2281+
22542282
sig = tri.local_element_stress(
22552283
p=pt,
22562284
**action,
22572285
**sect_prop,
2258-
omega=self.section_props.omega[tri.node_ids],
2259-
psi_shear=self.section_props.psi_shear[tri.node_ids],
2260-
phi_shear=self.section_props.phi_shear[tri.node_ids],
2286+
omega=omega_el,
2287+
psi_shear=psi_shear_el,
2288+
phi_shear=phi_shear_el,
22612289
)
22622290
else:
22632291
sigs = []
22642292
for idx in tri_ids:
22652293
tri = self.elements[idx]
2294+
2295+
if self.section_props.omega is None:
2296+
omega_el = None
2297+
psi_shear_el = None
2298+
phi_shear_el = None
2299+
else:
2300+
omega_el = self.section_props.omega[tri.node_ids]
2301+
psi_shear_el = self.section_props.psi_shear[tri.node_ids]
2302+
phi_shear_el = self.section_props.phi_shear[tri.node_ids]
2303+
22662304
sigs.append(
22672305
tri.local_element_stress(
22682306
p=pt,
22692307
**action,
22702308
**sect_prop,
2271-
omega=self.section_props.omega[tri.node_ids],
2272-
psi_shear=self.section_props.psi_shear[tri.node_ids],
2273-
phi_shear=self.section_props.phi_shear[tri.node_ids],
2309+
omega=omega_el,
2310+
psi_shear=psi_shear_el,
2311+
phi_shear=phi_shear_el,
22742312
)
22752313
)
22762314
sig = (
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import pytest
2+
import sectionproperties.pre.library.primitive_sections as primitive_sections
3+
from sectionproperties.analysis.section import Section
4+
5+
# define geometry
6+
rect = primitive_sections.rectangular_section(b=50, d=100)
7+
rect.create_mesh(mesh_sizes=0) # coarse mesh
8+
sec = Section(rect)
9+
10+
11+
# test stress runtime errors
12+
def test_stress_runtime_errors():
13+
# check runtime error with no analysis performed
14+
with pytest.raises(RuntimeError):
15+
sec.calculate_stress()
16+
17+
sec.calculate_geometric_properties()
18+
19+
# check runtime errors with shear/torsion applied, no warping analysis
20+
with pytest.raises(RuntimeError):
21+
sec.calculate_stress(Vx=1)
22+
sec.get_stress_at_points(pts=[[10, 10]], Vx=1)
23+
24+
with pytest.raises(RuntimeError):
25+
sec.calculate_stress(Vy=1)
26+
sec.get_stress_at_points(pts=[[10, 10]], Vy=1)
27+
28+
with pytest.raises(RuntimeError):
29+
sec.calculate_stress(Mzz=1)
30+
sec.get_stress_at_points(pts=[[10, 10]], Mzz=1)
31+
32+
# check no runtime errors with no shear/torsion applied
33+
sec.calculate_stress(N=1)
34+
sec.calculate_stress(Mxx=1)
35+
sec.calculate_stress(Myy=1)
36+
sec.calculate_stress(M11=1)
37+
sec.calculate_stress(M22=1)
38+
39+
sec.calculate_warping_properties()
40+
41+
# check no runtime errors after warping analysis
42+
sec.calculate_stress(N=1)
43+
sec.calculate_stress(Mxx=1)
44+
sec.calculate_stress(Myy=1)
45+
sec.calculate_stress(M11=1)
46+
sec.calculate_stress(M22=1)
47+
sec.calculate_stress(Vx=1)
48+
sec.calculate_stress(Vy=1)
49+
sec.calculate_stress(Mzz=1)
50+
sec.get_stress_at_points(pts=[[10, 10]], Mzz=1)

0 commit comments

Comments
 (0)