squid_n_core/model/element.rs
1//! 要素(部材)の型。
2//!
3//! - [`ElementKind`] — 要素種別(梁・シェル・ブレース・免震・ダンパー等)。
4//! - [`ForceRegime`] — 応力評価の方式。
5//! - [`LocalAxis`] — 部材ローカル軸の基準ベクトル。
6//! - [`EndCondition`] — 部材端の接合条件。
7//! - [`ZoneSource`] — 剛域長の出所(自動/手動)。
8//! - [`RigidZone`] — 部材端の剛域(剛域長・フェイス距離)。
9//! - [`ElementData`] — 要素の永続化データ。
10
11use super::*;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14pub enum ElementKind {
15 Beam,
16 Shell,
17 /// ファイバー梁要素(積分点断面のファイバー分割による分布塑性モデル)。
18 Fiber,
19 /// マルチスプリング梁要素(端部塑性化域を軸ばね群で置換したモデル)。
20 MultiSpring,
21 Wall,
22 PanelZone,
23 /// 一般ブレース(軸材。軸剛性のみのトラス要素。材料力学)。
24 /// 剛性は軸剛性のみのトラス要素(KB=E·A/L)で評価する。
25 /// K 型ブレースの重量配分規則(`LoadCfg::k_brace_rule`)の適用対象。
26 /// `tension_only`: 引張専用ブレースか(true の場合、弾性解析では剛性を1/2に
27 /// モデル化する。弾塑性解析では初期剛性は1倍。本実装既定の「引張と圧縮が
28 /// 対で存在するとみなす」モデル化)。
29 Brace {
30 tension_only: bool,
31 },
32 /// 節点バネ要素(ばね要素の変形と自由度。構造力学)。
33 ///
34 /// 部材の変形と自由度の考え方では、節点バネは θX=―(非考慮)、
35 /// θY=○, θZ=○, γY=○, γZ=○, δX=○。すなわちねじり以外の曲げ・せん断・
36 /// 軸方向の変形成分を独立なバネ剛性として持ちうる 2 節点要素。
37 /// 各自由度のバネ定数は `ElementData::spring` に保持する(局所軸 6 成分)。
38 NodalSpring,
39 /// 免震支承材(各免震部材指針)。
40 /// 2 節点要素で、水平は非線形せん断ばね(マルチシアスプリング=積層ゴム系
41 /// バイリニア、または摩擦ばね=弾性すべり支承 Qmax=μN)、鉛直は弾性軸ばね。
42 /// 特性は `Model::isolator_attrs` に要素 ID と対で保持する。
43 Isolator,
44 /// 制振ダンパー要素(各制振部材の力学モデル)。
45 /// 2 節点の軸方向要素で、マクスウェル要素(バネ Kd と粘性ダッシュポットの直列)等で
46 /// モデル化する。減衰要素の要素力は節点力として運動方程式へ与えられ、特性は
47 /// `Model::damper_attrs` に要素 ID と対で保持する。
48 Damper,
49}
50
51impl ElementKind {
52 /// 剛性の算定に断面(`ElementData::section`)の割当が必須な要素種別か。
53 /// 断面・材料の未割当を検出する検査は、必ず本判定で対象を絞ること。
54 ///
55 /// **材料は断面が持つ**(`Section::material`)ため、部材に要るのは断面の割当
56 /// だけである。断面が材料を持たない場合も剛性を作れないので、検査は「断面が
57 /// 割り当てられているか」と「その断面が材料を持つか」の 2 段になる
58 /// (`Model::element_material`)。
59 ///
60 /// 必須なのは線材(梁・ファイバー梁・マルチスプリング梁・ブレース)と
61 /// 面材(シェル・壁)で、断面諸元と材料定数から剛性を作るため、いずれかが
62 /// 未割当だとゼロ剛性となり解析が成立しない。
63 ///
64 /// 一方、次の要素は断面を持たないのが正常な状態であり、未割当として
65 /// 扱ってはならない。
66 /// - 仕口パネル(`PanelZone`): 剛性は取り付く柱・梁の断面から求めた実効体積 Ve
67 /// による。準備計算が自動生成するため、未割当として警告すると生成数だけ
68 /// 警告が並び、本当に割当が漏れている部材が埋もれる。
69 /// - 節点バネ(`NodalSpring`): 剛性は `ElementData::spring`(局所軸 6 成分)。
70 /// - 免震支承材(`Isolator`)・制振ダンパー(`Damper`): 特性は
71 /// `Model::isolator_attrs`・`Model::damper_attrs` に持つ。
72 ///
73 /// 要素種別を追加したときに扱いを決め忘れないよう、網羅 `match` で書く
74 /// (ワイルドカードを使わない)。
75 pub fn requires_section_and_material(self) -> bool {
76 match self {
77 ElementKind::Beam
78 | ElementKind::Fiber
79 | ElementKind::MultiSpring
80 | ElementKind::Brace { .. }
81 | ElementKind::Shell
82 | ElementKind::Wall => true,
83 ElementKind::PanelZone
84 | ElementKind::NodalSpring
85 | ElementKind::Isolator
86 | ElementKind::Damper => false,
87 }
88 }
89}
90
91#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
92pub enum ForceRegime {
93 UniaxialBendingShear,
94 AxialBendingInteract,
95 Auto,
96}
97
98#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
99pub struct LocalAxis {
100 pub ref_vector: [f64; 3],
101}
102
103#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
104pub enum EndCondition {
105 Fixed,
106 Pinned,
107 SemiRigid { k_theta: f64 },
108}
109
110/// 梁(水平材)のねじり剛性の扱い(建物一律のモデル化方針)。
111///
112/// 日本の一貫計算プログラムでは、床と一体になる大梁のねじり剛性を設計上
113/// 期待しないのが通例のため、既定は「i 端のねじれを解放する」とする。
114/// 判定と例外(解放すると材軸まわり回転が浮く節点がある部材は解放しない)は
115/// `squid_n_element::frame::beam::i_end_torsion_release` を参照。
116#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
117pub enum BeamTorsionMode {
118 /// 水平材の i 端ねじれをピン(解放)とし、梁のねじり剛性を期待しない(既定)。
119 #[default]
120 ReleaseIEnd,
121 /// ねじり剛性 GJ/L を両端で保持する。ねじりで釣り合わせるモデル化で用いる。
122 Keep,
123}
124
125/// 仕口パネル(柱梁接合部パネル)のモデル化(建物一律のモデル化方針)。
126///
127/// 有効にすると、S 造(CFT を除く)の柱梁接合節点へ仕口パネル要素を設け、
128/// 接合部のせん断変形を解析へ反映する。パネルが設けられた節点はせん断変形角
129/// `γX`・`γY` の 2 自由度を追加で持ち、その節点へ取り付く部材はパネル寸法分の
130/// オフセット位置で接合する。
131///
132/// 対象を S 造に限るのは、S 造の接合部が剛域長 0(`squid_n_element::frame::beam` の
133/// 剛域自動算定は RC/SRC の直交材のみを探す)であり、パネルのせん断変形を
134/// 明示的に評価しても剛域と二重計上にならないため。RC・SRC の接合部は
135/// 従来どおり剛域で接合部の有限寸法を評価する。
136///
137/// CFT も対象外とする。充填コンクリートと通しダイアフラムが接合部のせん断挙動へ
138/// 関与し、鋼管のみの実効体積による弾性せん断パネルでは剛性を表せないため
139/// (`squid_n_core::panel_zone::PanelJoint::has_filled_column`)。
140///
141/// 検定(S 造パネルゾーンの断面検定)は本設定によらず常に実行し、**CFT も
142/// 検定の対象に含める**(モデル化と検定で対象範囲が異なる)。
143#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
144pub enum PanelZoneMode {
145 /// 仕口パネルをモデル化する(既定)。
146 #[default]
147 Model,
148 /// 仕口パネルをモデル化しない(接合部を剛節点として扱う従来のモデル化)。
149 None,
150}
151
152impl PanelZoneMode {
153 /// モデル化が有効か。
154 pub fn is_enabled(self) -> bool {
155 matches!(self, PanelZoneMode::Model)
156 }
157}
158
159/// 剛域長の出所。Auto は再算定で上書きされる、Manual は保護される(設計書 §6.2.1)。
160#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
161pub enum ZoneSource {
162 Auto,
163 Manual,
164}
165
166/// 部材端の剛域(接合部の有限寸法)。可とう長 L' = L − 剛体アーム長。
167/// 力学計算は sc-element 側。ここではモデルに保持・永続化するデータ。
168///
169/// **次の 3 つは別概念**(設計書 §6.2.1、計算根拠 4.1.4・4.1.5)。
170/// - `length_i/j`: 剛域の自動算定・手動指定による剛域長 `λ = Lf − D_self/4`。
171/// 壁の考慮など、モデル化の設定によって変わりうる。
172/// - `panel_offset_i/j`: 仕口パネルを設けた接合部で、部材がパネル面まで離れて
173/// 接合することによるオフセット。部材配置から決まる幾何量。
174/// - `face_i/j`: 断面算定・危険断面位置(§6.2.3)に使う柱フェース距離 `D_orth/2`。
175/// 接合関係と断面せいだけで一意に決まる幾何量で、剛域長の設定には左右されない。
176///
177/// 剛性計算に効く**剛体アームの長さ**は [`Self::rigid_length_i`] /
178/// [`Self::rigid_length_j`] で取る。剛域長とパネルオフセットの大きい方になる。
179#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
180pub struct RigidZone {
181 pub length_i: f64,
182 pub length_j: f64,
183 pub source_i: ZoneSource,
184 pub source_j: ZoneSource,
185 /// 柱フェース距離 [mm](節点→フェース、= 接合する直交部材せい/2)。
186 ///
187 /// **`None` は「まだ算定していない」を表す**(直交材がなくフェース距離が
188 /// 0 の端は `Some(0.0)`)。両者を 0 で混同すると、算定前に読んだ側が
189 /// 「フェース距離 0=節点間長」として計算を進めてしまい、危険断面位置や
190 /// RC/SRC 梁の自重が静かに誤る。
191 ///
192 /// 値を埋めるのは `squid_n_element::frame::beam::apply_auto_rigid_zones`(解析の各入口が
193 /// 呼ぶ)。キャッシュを当てにできない場所からは、幾何そのものを返す
194 /// [`crate::face_distance::face_distances`] を直接使うこと。
195 ///
196 /// 読み出しは [`Self::face_i_or_zero`](表示用)と
197 /// [`Self::clear_span_from`](計算用)を使うこと。
198 #[serde(default)]
199 pub face_i: Option<f64>,
200 /// 柱フェース距離 [mm](j端)。意味は `face_i` と同様。
201 #[serde(default)]
202 pub face_j: Option<f64>,
203 /// 仕口パネル分のオフセット [mm](i 端)。パネルがない端は 0。
204 ///
205 /// 剛域長 `length_i` とは**別に保持する**。剛域の自動算定
206 /// (`apply_auto_rigid_zones`)は `Auto` 端の `length_i` を無条件に再算定するため、
207 /// 同じ場所へ入れると解析経路によってオフセットが消える。
208 #[serde(default)]
209 pub panel_offset_i: f64,
210 /// 仕口パネル分のオフセット [mm](j 端)。意味は `panel_offset_i` と同様。
211 #[serde(default)]
212 pub panel_offset_j: f64,
213}
214
215impl Default for RigidZone {
216 fn default() -> Self {
217 Self {
218 length_i: 0.0,
219 length_j: 0.0,
220 source_i: ZoneSource::Auto,
221 source_j: ZoneSource::Auto,
222 face_i: None,
223 face_j: None,
224 panel_offset_i: 0.0,
225 panel_offset_j: 0.0,
226 }
227 }
228}
229
230impl RigidZone {
231 /// i 端の柱フェース距離 [mm]。**未算定は 0 として扱う**。
232 ///
233 /// 一覧表示・図など、未算定でも破綻しない用途にだけ使うこと。計算には
234 /// [`Self::clear_span_from`] を使い、未算定を検出できるようにする。
235 pub fn face_i_or_zero(&self) -> f64 {
236 self.face_i.unwrap_or(0.0)
237 }
238
239 /// j 端の柱フェース距離 [mm]。意味は [`Self::face_i_or_zero`] と同様。
240 pub fn face_j_or_zero(&self) -> f64 {
241 self.face_j.unwrap_or(0.0)
242 }
243
244 /// 節点間長 `geom_len` から両端の柱フェース距離を差し引いた**内法長** [mm]。
245 ///
246 /// 両端とも算定済みのときだけ `Some` を返す。未算定(`None`)のまま
247 /// 節点間長で代用すると、RC/SRC 梁の自重・数量・終局耐力が過大になるため、
248 /// 呼び出し側に未算定を気づかせる。負にはならないよう 0 で下限を切る。
249 pub fn clear_span_from(&self, geom_len: f64) -> Option<f64> {
250 let (fi, fj) = (self.face_i?, self.face_j?);
251 Some((geom_len - fi - fj).max(0.0))
252 }
253
254 /// 柱フェース距離が両端とも算定済みか。
255 pub fn faces_computed(&self) -> bool {
256 self.face_i.is_some() && self.face_j.is_some()
257 }
258
259 /// 節点間長 `geom_len` から両端剛体アーム長を控除した**可撓長** [mm]。
260 ///
261 /// `geom_len − rigid_length_i − rigid_length_j`。控除後が実質 0 以下
262 /// (1e-6 mm 以下)の異常入力では `geom_len` へフォールバックする
263 /// (剛域長の過大指定で可撓長が 0 付近に縮退するのを防ぐ)。
264 ///
265 /// 座屈の内法長・プッシュオーバーせん断の内法スパン・材端バネの可撓長が
266 /// 共通で用いる(剛域フェイス距離 [`Self::clear_span_from`] とは別物)。
267 pub fn flexible_length_from(&self, geom_len: f64) -> f64 {
268 let net = geom_len - self.rigid_length_i() - self.rigid_length_j();
269 if net > 1e-6 {
270 net
271 } else {
272 geom_len
273 }
274 }
275
276 /// i 端の剛体アーム長 [mm](剛域長と仕口パネル分オフセットの大きい方)。
277 ///
278 /// 可撓長の控除・剛域変換・幾何剛性・せん断降伏の内法高さ・座屈長さの剛度比は、
279 /// いずれもこの値を用いる。
280 pub fn rigid_length_i(&self) -> f64 {
281 self.length_i.max(self.panel_offset_i)
282 }
283
284 /// j 端の剛体アーム長 [mm]。意味は [`Self::rigid_length_i`] と同様。
285 pub fn rigid_length_j(&self) -> f64 {
286 self.length_j.max(self.panel_offset_j)
287 }
288}
289
290#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
291pub struct ElementData {
292 pub id: ElemId,
293 pub kind: ElementKind,
294 pub nodes: SmallVec<[NodeId; 8]>,
295 pub section: Option<SectionId>,
296 pub local_axis: LocalAxis,
297 pub end_cond: [EndCondition; 2],
298 pub force_regime: ForceRegime,
299 /// 部材端の剛域。旧スキーマ(無し)は既定値(剛域長 0)で補完される。
300 #[serde(default)]
301 pub rigid_zone: RigidZone,
302 /// 塑性化領域長さ Lp [mm](None = 塑性化域を考慮しない従来モデル)。
303 /// ファイバー要素では端部 Lp 区間に非線形断面を配置し中央を弾性とする
304 /// モデル化(材端剛塑性ばねと適合するファイバーモデル化)に用いる。
305 #[serde(default)]
306 pub plastic_zone: Option<f64>,
307 /// 節点バネ要素(`ElementKind::NodalSpring`)の局所軸バネ定数
308 /// `[kx, ky, kz, krx, kry, krz]`(軸[N/mm]・せん断[N/mm]・回転[N·mm/rad])。
309 /// 部材の変形と自由度の一般的な取り扱い(構造力学)では、節点バネは
310 /// ねじり(θX)を非考慮とするのが既定だが、本実装では全 6 成分を入力可能とし、
311 /// `krx` を明示的に 0 とすることで既定挙動に合わせる(入力で 0 以外も指定できる)。
312 /// `None` は他要素種別、またはバネ定数未指定(剛性ゼロ扱い)。
313 #[serde(default)]
314 pub spring: Option<[f64; 6]>,
315}