|
| 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