Skip to main content

squid_n_core/section_shape/
properties.rs

1//! [`SectionShape`] の基本断面性能(A, Zp, Iy, Iz, J, 軸剛性用断面積)。
2
3use super::constants::N_S_EQ;
4use super::geometry::{
5    angle_centroid, built_h_centroid_y, lip_channel_centroid_z, plastic_modulus_strips,
6    rect_torsion_j, tee_centroid,
7};
8use super::types::SectionShape;
9
10impl SectionShape {
11    /// Compute the cross‑sectional area [mm²].
12    pub fn calc_area(&self) -> f64 {
13        match *self {
14            SectionShape::SteelH {
15                height,
16                width,
17                web_thick,
18                flange_thick,
19            } => 2.0 * width * flange_thick + (height - 2.0 * flange_thick) * web_thick,
20            SectionShape::SteelBox {
21                height,
22                width,
23                thick,
24                ..
25            } => width * height - (width - 2.0 * thick) * (height - 2.0 * thick),
26            SectionShape::SteelAngle {
27                leg_a,
28                leg_b,
29                thick,
30            } => thick * (leg_a + leg_b - thick),
31            SectionShape::SteelChannel {
32                height,
33                width,
34                web_thick,
35                flange_thick,
36            } => 2.0 * width * flange_thick + (height - 2.0 * flange_thick) * web_thick,
37            SectionShape::SteelTee {
38                height,
39                width,
40                web_thick,
41                flange_thick,
42            } => width * flange_thick + (height - flange_thick) * web_thick,
43            SectionShape::SteelPipe { outer_dia, thick } => {
44                let r = outer_dia / 2.0;
45                let ri = r - thick;
46                std::f64::consts::PI * (r * r - ri * ri)
47            }
48            SectionShape::SteelFlatBar { width, thick } => width * thick,
49            SectionShape::SteelRoundBar { dia } => std::f64::consts::PI * dia * dia / 4.0,
50            SectionShape::SteelLipChannel {
51                height,
52                width,
53                lip,
54                thick,
55            } => {
56                let (_, area) = lip_channel_centroid_z(height, width, lip, thick);
57                area
58            }
59            SectionShape::SteelBuiltH {
60                height,
61                upper_width,
62                upper_thick,
63                lower_width,
64                lower_thick,
65                web_thick,
66            } => {
67                let (_, area) = built_h_centroid_y(
68                    height,
69                    upper_width,
70                    upper_thick,
71                    lower_width,
72                    lower_thick,
73                    web_thick,
74                );
75                area
76            }
77            SectionShape::RcRect { b, d, .. } => b * d,
78            SectionShape::RcCircle { d, .. } => std::f64::consts::PI * d * d / 4.0,
79            // SRC: 質量算定への影響を避けるためコンクリート全断面とする(doc 参照)。
80            SectionShape::SrcRect { b, d, .. } => b * d,
81            SectionShape::CftBox {
82                height,
83                width,
84                thick,
85            } => width * height - (width - 2.0 * thick) * (height - 2.0 * thick),
86            SectionShape::CftPipe { outer_dia, thick } => {
87                let r = outer_dia / 2.0;
88                let ri = r - thick;
89                std::f64::consts::PI * (r * r - ri * ri)
90            }
91            // 壁・スラブ: 名目値(1m 幅相当の板断面。解析剛性は要素実装側の課題)。
92            SectionShape::RcWall { thickness, .. } | SectionShape::RcSlab { thickness } => {
93                thickness * 1000.0
94            }
95        }
96    }
97
98    /// 鉄骨断面の塑性断面係数 Zp [mm³](強軸)。RC・SRC・CFT・不明形状は `None`
99    /// を返す(鉄骨梁の全塑性モーメント Mp=Zp·σy の算定に用いる。材料力学)。
100    ///
101    /// H・箱・パイプ・中実丸鋼は閉形式、それ以外は矩形分解から等面積軸まわりで
102    /// 積分する([`plastic_modulus_strips`])。軸は [`calc_iy`](Self::calc_iy) と
103    /// **同一**(山形鋼は図心を通る幾何軸で、主軸ではない。Ze と軸を揃えるため
104    /// 意図的にこの定義を採る。主軸まわりで扱うには断面相乗モーメント Iyz を
105    /// 断面データに持たせて二軸連成を解く必要がある)。
106    pub fn plastic_modulus_strong(&self) -> Option<f64> {
107        match *self {
108            SectionShape::SteelH {
109                height,
110                width,
111                web_thick,
112                flange_thick,
113            } => Some(
114                width * flange_thick * (height - flange_thick)
115                    + web_thick * (height - 2.0 * flange_thick).powi(2) / 4.0,
116            ),
117            SectionShape::SteelBox {
118                height,
119                width,
120                thick,
121                ..
122            } => Some(
123                width * height * height / 4.0
124                    - (width - 2.0 * thick) * (height - 2.0 * thick).powi(2) / 4.0,
125            ),
126            SectionShape::SteelPipe { outer_dia, thick } => {
127                Some((outer_dia.powi(3) - (outer_dia - 2.0 * thick).powi(3)) / 6.0)
128            }
129            // 中実丸鋼: Zp = D³/6。
130            SectionShape::SteelRoundBar { dia } => Some(dia.powi(3) / 6.0),
131            // 平鋼: せい t の中実矩形。Zp = B·t²/4。
132            SectionShape::SteelFlatBar { width, thick } => Some(width * thick * thick / 4.0),
133            // 溝形鋼: 強軸まわりの鉛直方向の分布は H 形と同じ(上下対称)。
134            SectionShape::SteelChannel {
135                height,
136                width,
137                web_thick,
138                flange_thick,
139            } => Some(plastic_modulus_strips(&[
140                (0.0, flange_thick, width),
141                (flange_thick, height - flange_thick, web_thick),
142                (height - flange_thick, height, width),
143            ])),
144            // T 形鋼: フランジが上端のみの非対称断面(`calc_iy` と同じ配置)。
145            SectionShape::SteelTee {
146                height,
147                width,
148                web_thick,
149                flange_thick,
150            } => Some(plastic_modulus_strips(&[
151                (0.0, height - flange_thick, web_thick),
152                (height - flange_thick, height, width),
153            ])),
154            // 非対称組立 H 形: 上下フランジの寸法が異なる。
155            SectionShape::SteelBuiltH {
156                height,
157                upper_width,
158                upper_thick,
159                lower_width,
160                lower_thick,
161                web_thick,
162            } => Some(plastic_modulus_strips(&[
163                (0.0, lower_thick, lower_width),
164                (lower_thick, height - upper_thick, web_thick),
165                (height - upper_thick, height, upper_width),
166            ])),
167            // リップ溝形鋼: ウェブ/上下フランジ/上下リップの 5 枚(上下対称)。
168            // 分解は `lip_channel_centroid_z` の doc と同一。
169            SectionShape::SteelLipChannel {
170                height,
171                width,
172                lip,
173                thick,
174            } => Some(plastic_modulus_strips(&[
175                (0.0, height, thick),
176                (0.0, thick, width - thick),
177                (height - thick, height, width - thick),
178                (thick, lip, thick),
179                (height - lip, height - thick, thick),
180            ])),
181            // 山形鋼: 鉛直脚(幅 t×せい leg_a)+水平脚(幅 leg_b−t×せい t)。
182            // `calc_iy` と同じ幾何 y 軸まわり(主軸ではない)。
183            SectionShape::SteelAngle {
184                leg_a,
185                leg_b,
186                thick,
187            } => Some(plastic_modulus_strips(&[
188                (0.0, leg_a, thick),
189                (0.0, thick, leg_b - thick),
190            ])),
191            _ => None,
192        }
193    }
194
195    /// Moment of inertia about the local y‑axis [mm⁴] (strong axis for beams).
196    pub fn calc_iy(&self) -> f64 {
197        match *self {
198            SectionShape::SteelH {
199                height,
200                width,
201                web_thick,
202                flange_thick,
203            } => {
204                let hw = height - 2.0 * flange_thick;
205                (width * height.powi(3) - (width - web_thick) * hw.powi(3)) / 12.0
206            }
207            SectionShape::SteelBox {
208                height,
209                width,
210                thick,
211                ..
212            } => {
213                let hi = height - 2.0 * thick;
214                (width * height.powi(3) - (width - 2.0 * thick) * hi.powi(3)) / 12.0
215            }
216            SectionShape::SteelAngle {
217                leg_a,
218                leg_b,
219                thick,
220            } => {
221                let (_, cy, _) = angle_centroid(leg_a, leg_b, thick);
222                let a1 = leg_a * thick;
223                let y1 = leg_a / 2.0;
224                let a2 = (leg_b - thick) * thick;
225                let y2 = thick / 2.0;
226                let i1 = thick * leg_a.powi(3) / 12.0;
227                let i2 = (leg_b - thick) * thick.powi(3) / 12.0;
228                (i1 + a1 * (y1 - cy).powi(2)) + (i2 + a2 * (y2 - cy).powi(2))
229            }
230            SectionShape::SteelChannel {
231                height,
232                width,
233                web_thick,
234                flange_thick,
235            } => {
236                let hw = height - 2.0 * flange_thick;
237                (width * height.powi(3) - (width - web_thick) * hw.powi(3)) / 12.0
238            }
239            SectionShape::SteelTee {
240                height,
241                width,
242                web_thick,
243                flange_thick,
244            } => {
245                let y_bar = tee_centroid(height, width, web_thick, flange_thick);
246                let a_f = width * flange_thick;
247                let a_w = (height - flange_thick) * web_thick;
248                let i_f = width * flange_thick.powi(3) / 12.0
249                    + a_f * (height - flange_thick / 2.0 - y_bar).powi(2);
250                let i_w = web_thick * (height - flange_thick).powi(3) / 12.0
251                    + a_w * ((height - flange_thick) / 2.0 - y_bar).powi(2);
252                i_f + i_w
253            }
254            SectionShape::SteelPipe { outer_dia, thick } => {
255                let r = outer_dia / 2.0;
256                let ri = r - thick;
257                std::f64::consts::PI / 4.0 * (r.powi(4) - ri.powi(4))
258            }
259            // 平鋼は中実矩形(せい d=thick、幅 b=width)。iy は b·d³/12。
260            SectionShape::SteelFlatBar { width, thick } => width * thick.powi(3) / 12.0,
261            SectionShape::SteelRoundBar { dia } => std::f64::consts::PI * dia.powi(4) / 64.0,
262            // リップ溝形: 強軸(せい方向 y=H/2 まわり)。矩形分解+平行軸。上下対称。
263            SectionShape::SteelLipChannel {
264                height,
265                width,
266                lip,
267                thick,
268            } => {
269                let t = thick;
270                // ウェブ(幅 t×せい H、図心 y=H/2 でオフセット 0)。
271                let i_web = t * height.powi(3) / 12.0;
272                // フランジ(幅 (B−t)×厚 t、図心 y=H−t/2 → オフセット (H−t)/2)。2 枚。
273                let a_f = (width - t) * t;
274                let off_f = (height - t) / 2.0;
275                let i_f = (width - t) * t.powi(3) / 12.0 + a_f * off_f.powi(2);
276                // リップ(幅 t×せい (C−t)、図心 y=H−(C+t)/2 → オフセット (H−C−t)/2)。2 枚。
277                let a_l = t * (lip - t);
278                let off_l = (height - lip - t) / 2.0;
279                let i_l = t * (lip - t).powi(3) / 12.0 + a_l * off_l.powi(2);
280                i_web + 2.0 * i_f + 2.0 * i_l
281            }
282            // 非対称組立 H: 強軸(図心 y_bar まわり)。上下フランジ+ウェブの平行軸。
283            SectionShape::SteelBuiltH {
284                height,
285                upper_width,
286                upper_thick,
287                lower_width,
288                lower_thick,
289                web_thick,
290            } => {
291                let (y_bar, _) = built_h_centroid_y(
292                    height,
293                    upper_width,
294                    upper_thick,
295                    lower_width,
296                    lower_thick,
297                    web_thick,
298                );
299                let hw = (height - upper_thick - lower_thick).max(0.0);
300                let a_uf = upper_width * upper_thick;
301                let y_uf = height - upper_thick / 2.0;
302                let i_uf = upper_width * upper_thick.powi(3) / 12.0 + a_uf * (y_uf - y_bar).powi(2);
303                let a_lf = lower_width * lower_thick;
304                let y_lf = lower_thick / 2.0;
305                let i_lf = lower_width * lower_thick.powi(3) / 12.0 + a_lf * (y_lf - y_bar).powi(2);
306                let a_w = web_thick * hw;
307                let y_w = lower_thick + hw / 2.0;
308                let i_w = web_thick * hw.powi(3) / 12.0 + a_w * (y_w - y_bar).powi(2);
309                i_uf + i_lf + i_w
310            }
311            SectionShape::RcRect { b, d, .. } => b * d.powi(3) / 12.0,
312            SectionShape::RcCircle { d, .. } => std::f64::consts::PI * d.powi(4) / 64.0,
313            SectionShape::SrcRect {
314                b,
315                d,
316                steel_height,
317                steel_width,
318                steel_web_thick,
319                steel_flange_thick,
320                ..
321            } => {
322                let i_c = b * d.powi(3) / 12.0;
323                let hw = steel_height - 2.0 * steel_flange_thick;
324                let i_s = (steel_width * steel_height.powi(3)
325                    - (steel_width - steel_web_thick) * hw.powi(3))
326                    / 12.0;
327                i_c + (N_S_EQ - 1.0) * i_s
328            }
329            SectionShape::CftBox {
330                height,
331                width,
332                thick,
333            } => {
334                let hi = height - 2.0 * thick;
335                (width * height.powi(3) - (width - 2.0 * thick) * hi.powi(3)) / 12.0
336            }
337            SectionShape::CftPipe { outer_dia, thick } => {
338                let r = outer_dia / 2.0;
339                let ri = r - thick;
340                std::f64::consts::PI / 4.0 * (r.powi(4) - ri.powi(4))
341            }
342            SectionShape::RcWall { thickness, .. } | SectionShape::RcSlab { thickness } => {
343                1000.0 * thickness.powi(3) / 12.0
344            }
345        }
346    }
347
348    /// Moment of inertia about the local z‑axis [mm⁴] (weak axis for beams).
349    pub fn calc_iz(&self) -> f64 {
350        match *self {
351            SectionShape::SteelH {
352                height,
353                width,
354                web_thick,
355                flange_thick,
356            } => {
357                let hw = height - 2.0 * flange_thick;
358                (2.0 * flange_thick * width.powi(3) + hw * web_thick.powi(3)) / 12.0
359            }
360            SectionShape::SteelBox {
361                height,
362                width,
363                thick,
364                ..
365            } => {
366                let wi = width - 2.0 * thick;
367                (height * width.powi(3) - (height - 2.0 * thick) * wi.powi(3)) / 12.0
368            }
369            SectionShape::SteelAngle {
370                leg_a,
371                leg_b,
372                thick,
373            } => {
374                let (cx, _, _) = angle_centroid(leg_a, leg_b, thick);
375                let a1 = leg_a * thick;
376                let z1 = thick / 2.0;
377                let a2 = (leg_b - thick) * thick;
378                let z2 = thick + (leg_b - thick) / 2.0;
379                let i1 = leg_a * thick.powi(3) / 12.0;
380                let i2 = thick * (leg_b - thick).powi(3) / 12.0;
381                (i1 + a1 * (z1 - cx).powi(2)) + (i2 + a2 * (z2 - cx).powi(2))
382            }
383            SectionShape::SteelChannel {
384                height,
385                width,
386                web_thick,
387                flange_thick,
388            } => {
389                let hw = height - 2.0 * flange_thick;
390                let a_f = width * flange_thick;
391                let a_w = hw * web_thick;
392                let a_total = 2.0 * a_f + a_w;
393                let z_bar = if a_total > 0.0 {
394                    (2.0 * a_f * width / 2.0 + a_w * web_thick / 2.0) / a_total
395                } else {
396                    0.0
397                };
398                // 上下フランジは同一寄与(左右対称)。2 枚分をまとめて計上する。
399                let i_f = flange_thick * width.powi(3) / 12.0 + a_f * (width / 2.0 - z_bar).powi(2);
400                let i_w = hw * web_thick.powi(3) / 12.0 + a_w * (web_thick / 2.0 - z_bar).powi(2);
401                2.0 * i_f + i_w
402            }
403            SectionShape::SteelTee {
404                height,
405                width,
406                web_thick,
407                flange_thick,
408            } => {
409                let iz = flange_thick * width.powi(3) / 12.0;
410                let iz_w = (height - flange_thick) * web_thick.powi(3) / 12.0;
411                iz + iz_w
412            }
413            SectionShape::SteelPipe { .. } => self.calc_iy(),
414            // 平鋼は中実矩形。iz は d·b³/12(b=width、d=thick)。
415            SectionShape::SteelFlatBar { width, thick } => thick * width.powi(3) / 12.0,
416            SectionShape::SteelRoundBar { .. } => self.calc_iy(),
417            // リップ溝形: 弱軸(幅方向 z=z_bar まわり)。矩形分解+平行軸(Z へ偏心)。
418            SectionShape::SteelLipChannel {
419                height,
420                width,
421                lip,
422                thick,
423            } => {
424                let t = thick;
425                let (z_bar, _) = lip_channel_centroid_z(height, width, lip, thick);
426                // ウェブ(z 方向厚 t、y 方向せい H、z 図心 t/2)。
427                let a_web = t * height;
428                let i_web = height * t.powi(3) / 12.0 + a_web * (t / 2.0 - z_bar).powi(2);
429                // フランジ(z 方向 (B−t)、y 方向 t、z 図心 (t+B)/2)。2 枚。
430                let a_f = (width - t) * t;
431                let z_f = (t + width) / 2.0;
432                let i_f = t * (width - t).powi(3) / 12.0 + a_f * (z_f - z_bar).powi(2);
433                // リップ(z 方向厚 t、y 方向 (C−t)、z 図心 B−t/2)。2 枚。
434                let a_l = t * (lip - t);
435                let z_l = width - t / 2.0;
436                let i_l = (lip - t) * t.powi(3) / 12.0 + a_l * (z_l - z_bar).powi(2);
437                i_web + 2.0 * i_f + 2.0 * i_l
438            }
439            // 非対称組立 H: 弱軸(z=0、左右対称なので各板の自己慣性のみ)。
440            SectionShape::SteelBuiltH {
441                height,
442                upper_width,
443                upper_thick,
444                lower_width,
445                lower_thick,
446                web_thick,
447            } => {
448                let hw = (height - upper_thick - lower_thick).max(0.0);
449                upper_thick * upper_width.powi(3) / 12.0
450                    + lower_thick * lower_width.powi(3) / 12.0
451                    + hw * web_thick.powi(3) / 12.0
452            }
453            SectionShape::RcRect { b, d, .. } => d * b.powi(3) / 12.0,
454            SectionShape::RcCircle { .. } => self.calc_iy(),
455            SectionShape::SrcRect {
456                b,
457                d,
458                steel_height,
459                steel_width,
460                steel_web_thick,
461                steel_flange_thick,
462                ..
463            } => {
464                let i_c = d * b.powi(3) / 12.0;
465                let hw = steel_height - 2.0 * steel_flange_thick;
466                let i_s = (2.0 * steel_flange_thick * steel_width.powi(3)
467                    + hw * steel_web_thick.powi(3))
468                    / 12.0;
469                i_c + (N_S_EQ - 1.0) * i_s
470            }
471            SectionShape::CftBox {
472                height,
473                width,
474                thick,
475            } => {
476                let wi = width - 2.0 * thick;
477                (height * width.powi(3) - (height - 2.0 * thick) * wi.powi(3)) / 12.0
478            }
479            SectionShape::CftPipe { .. } => self.calc_iy(),
480            // 壁・スラブ: 面外は薄いため名目的に iy と同値の板剛性を返す。
481            SectionShape::RcWall { .. } | SectionShape::RcSlab { .. } => self.calc_iy(),
482        }
483    }
484
485    /// Torsional constant J [mm⁴].
486    pub fn calc_j(&self) -> f64 {
487        match *self {
488            SectionShape::SteelH {
489                height,
490                width,
491                web_thick,
492                flange_thick,
493            } => {
494                (2.0 * width * flange_thick.powi(3)
495                    + (height - 2.0 * flange_thick) * web_thick.powi(3))
496                    / 3.0
497            }
498            SectionShape::SteelBox {
499                height,
500                width,
501                thick,
502                ..
503            } => {
504                let a0 = (height - thick) * (width - thick);
505                let perim = 2.0 * (height + width - 2.0 * thick);
506                4.0 * a0 * a0 * thick / perim
507            }
508            SectionShape::SteelAngle {
509                leg_a,
510                leg_b,
511                thick,
512            } => ((leg_a + leg_b - thick) * thick.powi(3)) / 3.0,
513            SectionShape::SteelChannel {
514                height,
515                width,
516                web_thick,
517                flange_thick,
518            } => {
519                (2.0 * width * flange_thick.powi(3)
520                    + (height - 2.0 * flange_thick) * web_thick.powi(3))
521                    / 3.0
522            }
523            SectionShape::SteelTee {
524                height,
525                width,
526                web_thick,
527                flange_thick,
528            } => (width * flange_thick.powi(3) + (height - flange_thick) * web_thick.powi(3)) / 3.0,
529            SectionShape::SteelPipe { outer_dia, thick } => {
530                let r = outer_dia / 2.0;
531                let ri = r - thick;
532                std::f64::consts::PI / 2.0 * (r.powi(4) - ri.powi(4))
533            }
534            // 平鋼は中実矩形のねじり定数(RC 矩形と同じ閉形式)。
535            SectionShape::SteelFlatBar { width, thick } => rect_torsion_j(width, thick),
536            SectionShape::SteelRoundBar { dia } => std::f64::consts::PI * dia.powi(4) / 32.0,
537            // リップ溝形(薄肉開断面): J = (1/3)Σ l·t³。矩形分解の板長で近似。
538            SectionShape::SteelLipChannel {
539                height,
540                width,
541                lip,
542                thick,
543            } => {
544                let len = height + 2.0 * (width - thick) + 2.0 * (lip - thick);
545                len * thick.powi(3) / 3.0
546            }
547            // 非対称組立 H(開断面): J = (1/3)Σ b·t³(各板)。
548            SectionShape::SteelBuiltH {
549                height,
550                upper_width,
551                upper_thick,
552                lower_width,
553                lower_thick,
554                web_thick,
555            } => {
556                let hw = (height - upper_thick - lower_thick).max(0.0);
557                (upper_width * upper_thick.powi(3)
558                    + lower_width * lower_thick.powi(3)
559                    + hw * web_thick.powi(3))
560                    / 3.0
561            }
562            SectionShape::RcRect { b, d, .. } => rect_torsion_j(b, d),
563            SectionShape::RcCircle { d, .. } => std::f64::consts::PI * d.powi(4) / 32.0,
564            // ねじりは RC 矩形と同じ扱い(内蔵鉄骨の寄与は無視。
565            // 各種合成構造設計指針の J=(sG/cG)·sJ+cJ 複合換算は Material 依存のため今後の課題)。
566            SectionShape::SrcRect { b, d, .. } => rect_torsion_j(b, d),
567            SectionShape::CftBox {
568                height,
569                width,
570                thick,
571            } => {
572                let a0 = (height - thick) * (width - thick);
573                let perim = 2.0 * (height + width - 2.0 * thick);
574                4.0 * a0 * a0 * thick / perim
575            }
576            SectionShape::CftPipe { outer_dia, thick } => {
577                let r = outer_dia / 2.0;
578                let ri = r - thick;
579                std::f64::consts::PI / 2.0 * (r.powi(4) - ri.powi(4))
580            }
581            SectionShape::RcWall { thickness, .. } | SectionShape::RcSlab { thickness } => {
582                1000.0 * thickness.powi(3) / 3.0
583            }
584        }
585    }
586
587    /// 軸剛性(EA)算定用の等価断面積 [mm²]。
588    ///
589    /// SRC は各種合成構造設計指針の
590    /// An = rcAn + sAn·(ns−1) に従い鉄骨の等価換算断面を累加する
591    /// (ns は暫定的に `N_S_EQ`)。質量算定用の断面積(`calc_area` は
592    /// コンクリート全断面)とは区別して用いること。他形状は `calc_area` と同値。
593    pub fn calc_axial_stiffness_area(&self) -> f64 {
594        match *self {
595            SectionShape::SrcRect {
596                b,
597                d,
598                steel_height,
599                steel_width,
600                steel_web_thick,
601                steel_flange_thick,
602                ..
603            } => {
604                let s_a = 2.0 * steel_width * steel_flange_thick
605                    + (steel_height - 2.0 * steel_flange_thick) * steel_web_thick;
606                b * d + (N_S_EQ - 1.0) * s_a
607            }
608            _ => self.calc_area(),
609        }
610    }
611}