|
1 | 1 | """Tests for the yield moment calculation."""
|
2 | 2 |
|
| 3 | +import numpy as np |
3 | 4 | import pytest
|
4 | 5 |
|
5 | 6 | from sectionproperties.analysis import Section
|
| 7 | +from sectionproperties.post.stress_post import StressPost |
6 | 8 | from sectionproperties.pre import Material
|
7 |
| -from sectionproperties.pre.library import rectangular_section |
| 9 | +from sectionproperties.pre.library import i_section, rectangular_section |
8 | 10 |
|
9 | 11 | STEEL = Material(
|
10 | 12 | name="Steel",
|
|
18 | 20 |
|
19 | 21 | def test_get_without_analysis():
|
20 | 22 | """Test for raising an error if a geometric analysis has not been performed."""
|
21 |
| - geom = rectangular_section(d=50, b=50) |
| 23 | + geom = rectangular_section(d=50, b=50, material=STEEL) |
22 | 24 | geom.create_mesh(mesh_sizes=0, coarse=True)
|
23 | 25 | sec = Section(geometry=geom)
|
24 | 26 |
|
@@ -52,14 +54,195 @@ def test_rectangle():
|
52 | 54 |
|
53 | 55 | my_xx, my_yy = sec.get_my()
|
54 | 56 | my_11, my_22 = sec.get_my()
|
| 57 | + my_xx_calc = 50 * 100 * 100 / 6 * 500 |
| 58 | + my_yy_calc = 100 * 50 * 50 / 6 * 500 |
| 59 | + |
| 60 | + # compare with theoretical values |
| 61 | + assert my_xx == pytest.approx(my_xx_calc) |
| 62 | + assert my_yy == pytest.approx(my_yy_calc) |
| 63 | + assert my_11 == pytest.approx(my_xx_calc) |
| 64 | + assert my_22 == pytest.approx(my_yy_calc) |
| 65 | + |
| 66 | + # compare with stress analysis |
| 67 | + stress = sec.calculate_stress(mxx=my_xx, myy=my_yy, m11=my_11, m22=my_22) |
| 68 | + assert check_yield_index(stress, "sig_zz_mxx") == pytest.approx(1.0) |
| 69 | + assert check_yield_index(stress, "sig_zz_myy") == pytest.approx(1.0) |
| 70 | + assert check_yield_index(stress, "sig_zz_m11") == pytest.approx(1.0) |
| 71 | + assert check_yield_index(stress, "sig_zz_m22") == pytest.approx(1.0) |
| 72 | + |
| 73 | + |
| 74 | +def test_rectangle_rotated(): |
| 75 | + """Test the yield moment of a simple rotated rectangle.""" |
| 76 | + geom = rectangular_section(d=100, b=50, material=STEEL) |
| 77 | + geom.rotate_section(angle=45.0) |
| 78 | + geom.create_mesh(mesh_sizes=0, coarse=True) |
| 79 | + sec = Section(geometry=geom) |
| 80 | + sec.calculate_geometric_properties() |
| 81 | + |
| 82 | + my_11, my_22 = sec.get_my() |
| 83 | + my_xx_calc = 50 * 100 * 100 / 6 * 500 |
| 84 | + my_yy_calc = 100 * 50 * 50 / 6 * 500 |
| 85 | + |
| 86 | + # compare with theoretical values |
| 87 | + assert my_11 == pytest.approx(my_xx_calc) |
| 88 | + assert my_22 == pytest.approx(my_yy_calc) |
| 89 | + |
| 90 | + # compare with stress analysis |
| 91 | + stress = sec.calculate_stress(m11=my_11, m22=my_22) |
| 92 | + assert check_yield_index(stress, "sig_zz_m11") == pytest.approx(1.0) |
| 93 | + assert check_yield_index(stress, "sig_zz_m22") == pytest.approx(1.0) |
| 94 | + |
| 95 | + |
| 96 | +def test_isection(): |
| 97 | + """Test the yield moment of an isection.""" |
| 98 | + geom = i_section(d=200, b=100, t_f=10, t_w=5, r=12, n_r=8, material=STEEL) |
| 99 | + geom.create_mesh(mesh_sizes=0, coarse=True) |
| 100 | + sec = Section(geometry=geom) |
| 101 | + sec.calculate_geometric_properties() |
| 102 | + |
| 103 | + my_xx, my_yy = sec.get_my() |
| 104 | + my_11, my_22 = sec.get_my() |
| 105 | + ezxx, _, ezyy, _ = sec.get_ez() |
| 106 | + my_xx_calc = ezxx / 200e3 * 500 |
| 107 | + my_yy_calc = ezyy / 200e3 * 500 |
55 | 108 |
|
56 |
| - my_xx_calc = 50 * 100 * 100 / 4 * 500 |
57 |
| - my_yy_calc = 100 * 50 * 50 / 4 * 500 |
| 109 | + # compare with theoretical values |
| 110 | + assert my_xx == pytest.approx(my_xx_calc) |
| 111 | + assert my_yy == pytest.approx(my_yy_calc) |
| 112 | + assert my_11 == pytest.approx(my_xx_calc) |
| 113 | + assert my_22 == pytest.approx(my_yy_calc) |
| 114 | + |
| 115 | + # compare with stress analysis |
| 116 | + stress = sec.calculate_stress(mxx=my_xx, myy=my_yy, m11=my_11, m22=my_22) |
| 117 | + assert check_yield_index(stress, "sig_zz_mxx") == pytest.approx(1.0) |
| 118 | + assert check_yield_index(stress, "sig_zz_myy") == pytest.approx(1.0) |
| 119 | + assert check_yield_index(stress, "sig_zz_m11") == pytest.approx(1.0) |
| 120 | + assert check_yield_index(stress, "sig_zz_m22") == pytest.approx(1.0) |
| 121 | + |
| 122 | + |
| 123 | +def test_rectangle_composite(): |
| 124 | + """Test the yield moment of a composite rectangular section.""" |
| 125 | + mat1 = Material("a", 2, 0, 2, 1, "b") |
| 126 | + mat2 = Material("b", 1, 0, 1, 1, "r") |
58 | 127 |
|
| 128 | + rect1 = rectangular_section(d=20, b=20, material=mat1) |
| 129 | + rect2 = rectangular_section(d=20, b=20, material=mat2).align_to(rect1, "top") |
| 130 | + rect3 = rectangular_section(d=20, b=20, material=mat1).align_to(rect2, "top") |
| 131 | + geom = rect1 + rect2 + rect3 |
| 132 | + geom.create_mesh(mesh_sizes=0, coarse=True) |
| 133 | + sec = Section(geom) |
| 134 | + sec.calculate_geometric_properties() |
| 135 | + |
| 136 | + my_xx, my_yy = sec.get_my() |
| 137 | + my_11, my_22 = sec.get_my() |
| 138 | + eixx_calc = (20 * 20**3 / 12) + 2 * 2 * ((20 * 20**3 / 12) + (20 * 20 * 20**2)) |
| 139 | + eiyy_calc = 5 * (20 * 20**3 / 12) |
| 140 | + # myield = f * Ieff / y |
| 141 | + my_xx_calc = 2 * (eixx_calc / 2) / 30 |
| 142 | + my_yy_calc = 1 * eiyy_calc / 10 |
| 143 | + |
| 144 | + # compare with theoretical values |
59 | 145 | assert my_xx == pytest.approx(my_xx_calc)
|
60 | 146 | assert my_yy == pytest.approx(my_yy_calc)
|
61 | 147 | assert my_11 == pytest.approx(my_xx_calc)
|
62 | 148 | assert my_22 == pytest.approx(my_yy_calc)
|
63 | 149 |
|
| 150 | + # compare with stress analysis |
| 151 | + stress = sec.calculate_stress(mxx=my_xx, myy=my_yy, m11=my_11, m22=my_22) |
| 152 | + assert check_yield_index(stress, "sig_zz_mxx") == pytest.approx(1.0) |
| 153 | + assert check_yield_index(stress, "sig_zz_myy") == pytest.approx(1.0) |
| 154 | + assert check_yield_index(stress, "sig_zz_m11") == pytest.approx(1.0) |
| 155 | + assert check_yield_index(stress, "sig_zz_m22") == pytest.approx(1.0) |
| 156 | + |
| 157 | + |
| 158 | +def test_composite_example(): |
| 159 | + """Tests the composite example from the docs, compares to stress analysis.""" |
| 160 | + timber = Material( |
| 161 | + name="Timber", |
| 162 | + elastic_modulus=8e3, |
| 163 | + poissons_ratio=0.35, |
| 164 | + yield_strength=20, |
| 165 | + density=0.78e-6, |
| 166 | + color="burlywood", |
| 167 | + ) |
| 168 | + |
| 169 | + ub = i_section(d=304, b=165, t_f=10.2, t_w=6.1, r=11.4, n_r=8, material=STEEL) |
| 170 | + panel = rectangular_section(d=100, b=600, material=timber) |
| 171 | + panel = panel.align_center(align_to=ub).align_to(other=ub, on="top") |
| 172 | + geom = ub + panel |
| 173 | + geom.create_mesh(mesh_sizes=[10, 500]) |
| 174 | + sec = Section(geometry=geom) |
| 175 | + sec.calculate_geometric_properties() |
| 176 | + |
| 177 | + # compare with stress analysis |
| 178 | + my_xx, my_yy = sec.get_my() |
| 179 | + my_11, my_22 = sec.get_my() |
| 180 | + stress = sec.calculate_stress(mxx=my_xx, myy=my_yy, m11=my_11, m22=my_22) |
| 181 | + assert check_yield_index(stress, "sig_zz_mxx") == pytest.approx(1.0) |
| 182 | + assert check_yield_index(stress, "sig_zz_myy") == pytest.approx(1.0) |
| 183 | + assert check_yield_index(stress, "sig_zz_m11") == pytest.approx(1.0) |
| 184 | + assert check_yield_index(stress, "sig_zz_m22") == pytest.approx(1.0) |
| 185 | + |
| 186 | + |
| 187 | +def test_yield_internal(): |
| 188 | + """Test where the internal material yields first.""" |
| 189 | + mat1 = Material( |
| 190 | + name="Material_1", |
| 191 | + elastic_modulus=0.75, |
| 192 | + poissons_ratio=0, |
| 193 | + yield_strength=1, |
| 194 | + density=1, |
| 195 | + color="gold", |
| 196 | + ) |
| 197 | + mat2 = Material( |
| 198 | + name="Material_2", |
| 199 | + elastic_modulus=1, |
| 200 | + poissons_ratio=0, |
| 201 | + yield_strength=1, |
| 202 | + density=1, |
| 203 | + color="blue", |
| 204 | + ) |
| 205 | + mat3 = Material( |
| 206 | + name="Material 3", |
| 207 | + elastic_modulus=3, |
| 208 | + poissons_ratio=0, |
| 209 | + yield_strength=1, |
| 210 | + density=1, |
| 211 | + color="red", |
| 212 | + ) |
| 213 | + |
| 214 | + sq1 = rectangular_section(d=100, b=100, material=mat1).align_center() |
| 215 | + sq2 = rectangular_section(d=75, b=75, material=mat2).align_center() |
| 216 | + sq3 = rectangular_section(d=50, b=50, material=mat3).align_center() |
| 217 | + hole = rectangular_section(d=25, b=25).align_center() |
| 218 | + compound = (sq1 - sq2) + (sq2 - sq3) + (sq3 - hole) |
| 219 | + compound.create_mesh(10) |
| 220 | + sec = Section(compound) |
| 221 | + sec.calculate_geometric_properties() |
| 222 | + |
| 223 | + # compare with stress analysis |
| 224 | + my_xx, my_yy = sec.get_my() |
| 225 | + my_11, my_22 = sec.get_my() |
| 226 | + stress = sec.calculate_stress(mxx=my_xx, myy=my_yy, m11=my_11, m22=my_22) |
| 227 | + assert check_yield_index(stress, "sig_zz_mxx") == pytest.approx(1.0) |
| 228 | + assert check_yield_index(stress, "sig_zz_myy") == pytest.approx(1.0) |
| 229 | + assert check_yield_index(stress, "sig_zz_m11") == pytest.approx(1.0) |
| 230 | + assert check_yield_index(stress, "sig_zz_m22") == pytest.approx(1.0) |
| 231 | + |
| 232 | + |
| 233 | +def check_yield_index(stress: StressPost, key: str) -> float: |
| 234 | + """Returns the largest yield index. |
| 235 | +
|
| 236 | + Given the output from StressPost object and a dict key representing the type of |
| 237 | + stress, returns the largest yield index. |
| 238 | + """ |
| 239 | + yield_index = 0.0 |
| 240 | + |
| 241 | + for idx, mat_dict in enumerate(stress.get_stress()): |
| 242 | + fy = stress.material_groups[idx].material.yield_strength |
| 243 | + sigs = mat_dict[key] |
| 244 | + sig_max = max(np.absolute(sigs)) |
| 245 | + |
| 246 | + yield_index = max(yield_index, sig_max / fy) |
64 | 247 |
|
65 |
| -# TODO: add more tests |
| 248 | + return yield_index |
0 commit comments