Skip to content

Commit 9e9f9ed

Browse files
authored
Merge pull request #299 from gaoflow/fix/128-prop2-product-of-inertia
Fix product of inertia (Ixy) weighting in cutwp.prop2 (part of #128)
2 parents 0c45def + 3f0db7f commit 9e9f9ed

2 files changed

Lines changed: 48 additions & 1 deletion

File tree

pycufsm/pre/cutwp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def prop2(coord: np.ndarray, ends: np.ndarray) -> Sect_Props:
152152
# Compute moment of inertia
153153
I_xx = np.sum((y_diffs**2 / 12 + (y_means - y_centroid) ** 2) * lengths * thicknesses)
154154
I_yy = np.sum((x_diffs**2 / 12 + (x_means - x_centroid) ** 2) * lengths * thicknesses)
155-
I_xy = np.sum((x_diffs * y_diffs / 12 + (x_means - x_centroid) * (y_means - y_centroid) * lengths * thicknesses))
155+
I_xy = np.sum((x_diffs * y_diffs / 12 + (x_means - x_centroid) * (y_means - y_centroid)) * lengths * thicknesses)
156156
if np.abs(I_xy / area**2) < 1e-12:
157157
I_xy = np.float64(0.0)
158158

tests/test_cutwp.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import numpy as np
2+
from pytest import approx
3+
4+
from pycufsm.pre import cutwp
5+
6+
7+
def _independent_ixy(coord: np.ndarray, ends: np.ndarray) -> float:
8+
"""Product of inertia by the standard thin-walled line-element formula.
9+
10+
For each line element the contribution is
11+
``(dx*dy/12 + (xm - xc)*(ym - yc)) * length * thickness`` -- i.e. the
12+
element's own product of inertia about its midpoint plus the parallel-axis
13+
term, both weighted by the element area. This mirrors how ``Ixx``/``Iyy``
14+
are formed in :func:`cutwp.prop2`.
15+
"""
16+
x_mean, y_mean, x_diff, y_diff, length, thick = [], [], [], [], [], []
17+
for start, end, t in ends:
18+
s, e = int(start), int(end)
19+
x_mean.append((coord[s, 0] + coord[e, 0]) / 2)
20+
y_mean.append((coord[s, 1] + coord[e, 1]) / 2)
21+
x_diff.append(coord[e, 0] - coord[s, 0])
22+
y_diff.append(coord[e, 1] - coord[s, 1])
23+
length.append(np.hypot(coord[e, 0] - coord[s, 0], coord[e, 1] - coord[s, 1]))
24+
thick.append(t)
25+
x_mean, y_mean, x_diff, y_diff, length, thick = map(np.array, (x_mean, y_mean, x_diff, y_diff, length, thick))
26+
area = np.sum(length * thick)
27+
x_c = np.sum(length * thick * x_mean) / area
28+
y_c = np.sum(length * thick * y_mean) / area
29+
return float(np.sum((x_diff * y_diff / 12 + (x_mean - x_c) * (y_mean - y_c)) * length * thick))
30+
31+
32+
def describe_prop2():
33+
def context_product_of_inertia():
34+
def it_matches_the_thin_walled_formula_for_inclined_elements():
35+
# A section with an inclined element, so the element's own
36+
# contribution ``dx*dy/12`` to the product of inertia is non-zero
37+
# and must be weighted by ``length * thickness`` (issue #128).
38+
coord = np.array([[0.0, 0.0], [4.0, 0.0], [6.0, 3.0]])
39+
ends = np.array([[0, 1, 0.1], [1, 2, 0.1]], dtype=float)
40+
sect = cutwp.prop2(coord.copy(), ends.copy())
41+
assert sect["Ixy"] == approx(_independent_ixy(coord, ends))
42+
43+
def it_is_zero_for_a_section_symmetric_about_x():
44+
coord = np.array([[0.0, -2.0], [2.0, -2.0], [0.0, 2.0], [2.0, 2.0]])
45+
ends = np.array([[0, 1, 0.1], [2, 3, 0.1], [0, 2, 0.1]], dtype=float)
46+
sect = cutwp.prop2(coord.copy(), ends.copy())
47+
assert sect["Ixy"] == approx(0.0)

0 commit comments

Comments
 (0)