OpenSees 보 요소는 왜 트러스보다 더 많은 것을 요구하는가: 단면·기하변환·분포하중과 검증된 라멘 해석

회전 자유도가 가능하게 하는 것, geomTransf 가 P-델타의 존재 여부를 결정하는 이유, vecxz 벡터 하나로 3차원 답이 정확히 2배 갈리는 사례, eleLoad 가 요소 2개에서 이미 정확한 반면 절점 등가하중이 1/n² 로만 수렴하는 이유, 전단변형이 무시할 수 없어지는 지점, 그리고 독립

OpenSees 보 요소는 왜 트러스보다 더 많은 것을 요구하는가: 단면·기하변환·분포하중과 검증된 라멘 해석

트러스 요소는 단면에 대해 숫자 하나만 있으면 된다. 보 요소는 단면2차모멘트와 기하변환, 그리고 하중이 어떤 경로로 전달되는지에 대한 결정을 추가로 요구한다. 셋 다 형식이 아니라 모델링 확약이다. 늘어나기만 하던 부재에서 휘는 부재로 넘어가는 이 지점이 대부분의 OpenSees 모델이 조용히 어긋나기 시작하는 곳이다. 새로 들어가는 입력마다 그럴듯한 기본값처럼 보이는 선택지가 있고, 그 선택은 어떤 상황에서는 맞고 다른 상황에서는 크게 틀리기 때문이다.

이 글은 설계기준·부재 내력·처짐 한계·하중조합을 제시하지 않는다. 역학과 명령을 다룬다. 회전 자유도가 무엇을 가능하게 하는지, geomTransf가 평형의 의미를 어떻게 바꾸는지, eleLoad와 절점 등가하중의 수렴 속도가 왜 전혀 다른지, 전단변형이 언제부터 무시할 수 없게 되는지, 그리고 라멘을 믿는 대신 어떻게 검증하는지를 다룬다. 아래 모든 수치는 OpenSeesPy 3.8.0에서 생성했고, 모든 예제는 닫힌해나 독립적인 풀이와 대조했다. 이 글은 PipelineXLab OpenSees 시리즈 2부다. 1부에서 다룬 Domain 객체 모델과 해석 여섯 객체의 용어를 전제한다.

1. 회전 자유도가 실제로 사주는 것

ndf 2에서 ndf 3으로 가면 절점마다 숫자 하나 θz가 늘어나고, 이 하나가 모델이 표현할 수 있는 대상을 바꾼다. 트러스 절점은 부재축 방향 힘만 전달하므로 구조물의 안정성은 형상이 만들어줄 때만 성립한다. 라멘 절점은 모멘트를 전달하므로 부재가 캔틸레버로 뻗을 수 있고, 가새 없이 횡하중에 저항할 수 있으며, 고정단이 비로소 의미를 가진다.

여기서 세 가지가 곧바로 따라 나온다.

이제 모든 fix()·load()·mass()가 두 개가 아니라 세 개의 값을 받는다. 세 번째는 회전 구속이고, 회전 하중은 작용 모멘트다.

보–기둥 요소는 기하변환 태그를 요구한다. 기본값이 없다. 형식적 요구가 아니라, 평형을 원래 형상에서 쓸지 변형된 형상에서 쓸지 OpenSees가 사용자에게 묻는 지점이다.

트러스 부재와 라멘 부재가 만나는 절점에는 트러스가 구속하지 않는 회전 자유도가 생긴다. 다른 무언가가 구속하지 않으면 모델은 특이해진다. 첫 라멘 모델에서 예상 못 한 matrix singular가 뜨는 가장 흔한 원인이다.

2. elasticBeamColumn, 인수 하나씩

2차원 탄성 주력 요소는 단면을 낱개 숫자로 받는다.

ops.element('elasticBeamColumn', eleTag, iNode, jNode, A, E, Iz, transfTag)

인수의미지배하는 것흔한 실수

A단면적축강성 EA/L균열단면·유효단면을 의도했는데 총단면을 입력

E탄성계수축강성과 휨강성 모두단위 불일치: kN/m² 대 MPa

Iz휨축에 대한 단면2차모멘트휨강성 EI/L³미터 기반 모델에 cm⁴ 입력

transfTag사용할 geomTransfP-델타의 존재 여부3차원에서 다른 방향 부재용 변환을 재사용

3차원에서는 같은 명령이 정해진 순서의 단면량 여섯 개 — A, E, G, Jx, Iy, Iz — 와 변환을 요구한다. 순서는 협상 대상이 아니며, Iy와 Iz를 바꿔 넣으면 아무 문제 없이 돌아가면서 두 관성모멘트의 비만큼 틀린 모델이 된다. 4절에서 그 실패를 정확히 2배 차이로 보여준다.

두 번째 경로가 있다. section 객체를 만들고 적분 규칙과 함께 forceBeamColumn에 넘기는 방식이다. 등단면 탄성 부재에서는 두 경로가 같은 답을 주므로, 단면 문법이 중요해지기 전에 익혀두기 좋다.

# 단위: kN, m — 3 m 캔틸레버, 선단에 10 kN A, E, I = 8.45e-3, 200.0e6, 2.313e-4 # 경로 1: 요소에 물성을 직접 ops.element('elasticBeamColumn', 1, 1, 2, A, E, I, 1) # 경로 2: section 객체 + 적분 규칙 ops.section('Elastic', 1, E, A, I) ops.beamIntegration('Legendre', 1, 1, 3) # 태그, 단면태그, 적분점 3 ops.element('forceBeamColumn', 1, 1, 2, 1, 1) # 변환태그, 적분태그

선단 처짐, 경로 1 -1.9455252918287938 mm 선단 처짐, 경로 2 -1.9455252918287927 mm 닫힌해 P L³ / 3EI -1.9455252918287938 mm

15자리까지 같다. 두 경로를 모두 알아야 하는 이유는 비선형으로 넘어갔을 때 살아남는 쪽이 경로 2뿐이기 때문이다. 파이버 단면, 소성힌지, 열화 재료는 모두 section 객체를 통해 들어오고, 이 시리즈 3부는 정확히 이 문법 위에 세워진다.

3. geomTransf는 좌표 문제가 아니라 물리적 선택이다

이름만 보면 국부축에서 전역축으로 돌리는 일상적인 변환 같고, Linear에서는 실제로 그것뿐이다. 나머지 둘은 평형의 의미 자체를 바꾼다.

변환평형을 어디에 쓰는가포착하는 것쓰는 경우

Linear변형 전 원래 형상기하 효과 없음. 미소변위 이론1차 해석, 사용성 검토, 모델 디버깅

PDelta변위된 양단을 잇는 현축력이 횡변위를 통해 만드는 P-델타안정성 민감 라멘, 2차 층변위, 내진 모델

Corotational요소와 함께 회전·병진하는 좌표계큰 변위와 큰 회전을 엄밀하게케이블, 스냅스루, 매우 세장한 부재, 붕괴 해석

차이는 측정된다. 4 m 강재 캔틸레버(IPE 400) 선단에 횡하중 10 kN을 고정해 두고 축압축 P를 0부터 키운다. 캔틸레버의 탄성 임계하중은 P_cr = π²EI/(4L²) = 7133.9 kN이다. 각 변환에서 P를 0에서 0.6 P_cr까지 훑으면 이렇게 된다.

P / P_crLinear (mm)PDelta (mm)Corotational (mm)1차 × 1/(1−P/P_cr)

0.04.61164.61164.61164.6116

0.24.61165.74465.73375.7645

0.44.61167.62817.59397.6860

0.64.611611.378711.278711.5290

첫 열을 다시 보자. Linear에서는 축압축 4280 kN일 때의 변위와 0일 때의 변위가 동일하다. 근사가 부정확한 것이 아니라, 축력이 횡강성에 영향을 줄 수 있는 메커니즘 자체가 모델에 없다. 2차 효과를 검토하면서 변환을 Linear로 둔 채였다면 해석은 돌아가고 수렴하고, 찾으려던 현상을 감지할 수 없는 숫자를 보고한다. 아무 경고도 나오지 않는다.

PDelta와 Corotational이 서로 거의 일치하면서 둘 다 단순 증폭계수 1/(1−P/P_cr)보다 조금 낮다는 점도 눈여겨볼 만하다. 증폭계수는 특정 변형 형상을 가정한 근사이고, 유한요소 해는 그것과 정확히 일치할 의무가 없다. 몇 퍼센트 이내의 일치는 결함이 아니라 2차 메커니즘이 존재하며 정상 작동한다는 확인이다.

4. 3차원에서는 변환이 단면의 방향까지 정한다

3차원 변환은 벡터를 받는다. geomTransf('Linear', tag, vecxzX, vecxzY, vecxzZ). 이 벡터가 부재축과 함께 국부축을 정의하고, 따라서 Iy와 Iz 중 어느 것이 어느 전역 방향의 휨에 저항하는지를 결정한다. 벡터만 바꿔도 답이 바뀐다.

# 단위: kN, m — 전역 Z 방향 4 m 기둥, 전역 X 방향으로 10 kN # A=6000 mm², E=200 GPa, G=80 GPa, Jx=1.0e-4, Iy=1.2e-4, Iz=0.6e-4 (모두 m⁴) ops.geomTransf('Linear', 1, 1.0, 0.0, 0.0) # vecxz 를 전역 X 로 # 선단 X 변위: 8.8889 mm ops.geomTransf('Linear', 1, 0.0, 1.0, 0.0) # vecxz 를 전역 Y 로 # 선단 X 변위: 17.7778 mm

단면이 같고, 하중이 같고, 요소 명령이 한 글자도 다르지 않은데 답이 정확히 2배 — 두 관성모멘트의 비만큼 — 차이난다. 첫 경우는 Iy = 1.2 × 10⁻⁴ m⁴가 지배하는 축으로 휘어 PL³/3EI = 8.8889 mm가 되고, 둘째는 Iz = 0.6 × 10⁻⁴ m⁴로 휘어 17.7778 mm가 된다. 둘 다 서로 다른 질문에 대한 정답이다. 내가 하려던 질문은 하나뿐이다.

실무적 방어는 단순하고 습관으로 만들 가치가 있다. 3차원 모델에서 부재 방향이 다를 때마다 별도의 변환 태그를 정의하고 vecxz를 근거를 들어 정하며, 각 방향에서 부재 하나씩을 지배할 것으로 믿는 관성모멘트로 손계산과 대조한다. 기둥, 동서 방향 보, 남북 방향 보는 세 방향이고 태그도 셋이어야 한다.

5. 분포하중: eleLoad 와 load() 는 같은 개념의 두 표기가 아니다

등분포하중은 두 가지로 걸 수 있다. eleLoad는 분포를 요소에 넘기고, 요소가 자기 형상함수로부터 정확한 고정단력을 계산한다. 절점 load()는 분포를 정적으로 등가인 집중하중 집합으로 대체한다. 둘 다 정당하지만 정확도는 같지 않고, 그 차이는 사람들이 기대하는 방식으로 줄어들지 않는다.

# 단위: kN, m # 경로 A — 요소가 분포를 받는다 ops.eleLoad('-ele', eleTag, '-type', '-beamUniform', -20.0) # 경로 B — 해석자가 절점에 나눠 건다 ops.load(nodeTag, 0.0, -20.0 * 부담길이, 0.0)

지간 6.0 m 단순지지 IPE 400에 w = 20 kN/m를 건다. 정확한 지간 중앙 처짐은 5wL⁴/384EI = 7.295720 mm다. 지간을 2, 4, 8, 16, 32개 요소로 나눠 비교하면 이렇다.

요소 수eleLoad (mm)오차절점 load() (mm)오차

2−7.2957200−5.83657620.0%

4−7.2957206 × 10⁻¹⁶−6.9309345.00%

8−7.2957204 × 10⁻¹⁵−7.2045231.25%

16−7.2957206 × 10⁻¹⁴−7.2729210.31%

32−7.2957202 × 10⁻¹³−7.2900200.078%

이 표에서 멈춰 볼 결과가 둘 있다.

eleLoad 열은 요소 2개에서 정확하고 그 뒤로 좋아지지 않는다. 좋아질 수가 없기 때문이다. 일관 하중벡터를 쓴 3차 Hermite 보 요소는 등단면 Euler-Bernoulli 보의 분포하중 아래 절점 변위를 정확히 재현한다. 메시를 잘게 해도 처짐이 더 정확해지지 않는다. 처짐을 읽을 수 있는 위치가 늘어날 뿐이다. 이것은 실제로 유용한 사실이다. 탄성 라멘 모델에서 메시 밀도는 수렴의 문제가 아니라 출력 해상도의 문제다.

절점 등가하중 열은 메시가 두 배가 될 때마다 오차가 4분의 1로 준다. 교과서적인 1/n² 수렴이며, 요소 2개짜리 등가하중 모델은 처짐을 20% 작게 본다는 뜻이다. "메시가 충분히 촘촘하니까" 하중을 절점에 나눠 거는 사람은 32개에서는 대체로 옳고 4개에서는 크게 틀린다.

메시로 해결되지 않는 결과가 하나 더 있다. 절점 등가하중을 쓰면 요소가 지간 모멘트를 가지지 않는다. 요소의 모멘트도는 절점 사이에서 직선이므로 분포하중의 포물선 모멘트는 절점 값에서 되짚어야 한다. eleLoad를 쓰면 요소가 내부적으로 분포를 알고 있어 메시와 무관하게 올바른 고정단력을 돌려준다.

6. 부재력 읽기, 그리고 지간 모멘트가 사는 곳

요소 2개짜리 eleLoad 모델을 돌리고 질의해 보자.

ops.reactions() print(ops.nodeReaction(1)) # -> [0.0, 60.0, 0.0] print(ops.nodeReaction(3)) # -> [0.0, 60.0, 0.0] print(ops.basicForce(1)) # -> [0.0, 0.0, 90.0] print(ops.nodeDisp(2, 2)) # -> -0.0072957198443579765

각 반력은 wL/2 = 60 kN이고 합은 작용 총하중 120 kN과 같다. 2차원 보–기둥에서 basicForce는 세 숫자, 즉 축력과 i단 모멘트, j단 모멘트를 돌려준다. 요소 1은 핀지점에서 지간 중앙까지이므로 i단 모멘트는 0이고 j단 모멘트는 90 kN·m, 정확히 wL²/8이다. 지간 중앙 모멘트는 따로 유도해야 하는 값이 아니라 거기서 끝나는 요소의 단부 모멘트다.

양단을 고정으로 바꾸면 같은 세 숫자가 고전 해를 그대로 말해준다.

# 양단 완전고정, 요소 2개, 같은 등분포하중 print(ops.basicForce(1)) # -> [0.0, 60.0, 30.0] print(ops.nodeReaction(1)) # -> [0.0, 60.0, 60.0]

지점 모멘트는 wL²/12 = 60 kN·m, 지간 중앙 모멘트는 wL²/24 = 30 kN·m, 연직반력은 wL/2 = 60 kN이다. 요소 하나를 질의해 독립적인 교과서 값 셋을 회수했다. 어떤 라멘 모델이 부재 하나에서 이 숫자들을 재현하지 못한다면 문제는 구조가 아니라 모델에 있다.

7. 단부 해제: 접합부를 힌지로 만들기

실제 접합부가 항상 완전강접이거나 완전핀인 것은 아니지만, 먼저 모델링하는 것은 이 두 극한이다. OpenSeesPy의 탄성 보–기둥은 선택적 해제 코드를 받는다.

ops.element('elasticBeamColumn', tag, i, j, A, E, Iz, transfTag, '-release', code) # code 0 해제 없음 code 1 i 단 모멘트 해제 # code 2 j 단 모멘트 해제 code 3 양단 해제

앞의 양단고정 보에서 왼쪽 요소의 왼쪽 단부 모멘트를 해제하면 구조는 한쪽 핀·한쪽 고정의 부정정보(propped cantilever)가 되고, 고전 해는 명확하다.

항목OpenSees부정정보 닫힌해

해제단 반력45.0 kN3wL/8 = 45.0 kN

해제단 모멘트0.0 kN·m정의상 0

지간 중앙 모멘트45.0 kN·m45x − 10x², x = 3 m 에서 45.0 kN·m

주의가 둘 있다. 첫째, 해제는 강성을 없애므로 어떤 회전을 붙잡고 있던 유일한 부재의 양단을 해제하면 모델이 기구가 되고 풀이는 특이해진다. 솔버의 실패가 아니라 실제 기구를 정확히 보고한 것이다. 둘째, 해제는 절점이 아니라 요소에 속한다. 세 부재가 만나는 절점에서 한 부재의 단부만 해제하면 나머지 둘은 강접으로 남는데, 대개는 그것이 의도한 바이고 가끔은 아니다.

8. 전단변형: 취향이 아니라 지간/춤의 문제

elasticBeamColumn은 Euler-Bernoulli 요소다. 평면은 평면으로 남고 축에 직교하며, 전단변형률은 표현되지 않는다. ElasticTimoshenkoBeam은 전단 유연성을 더하고 입력 두 개, G와 전단면적 Av를 추가로 요구한다.

ops.element('ElasticTimoshenkoBeam', tag, i, j, E, G, A, Iz, Avy, transfTag)

그 차이가 중요한지는 답이 명확한 기하 문제다. 등분포하중 단순보의 닫힌해는 휨 항과 전단 항으로 분리된다.

δ_휨 = 5 w L⁴ / (384 E I) δ_전단 = w L² / (8 G Av) 비율 = 1 + δ_전단 / δ_휨

IPE 400 단면을 고정한 채 지간만 바꾸면 이렇다.

지간 / 춤Euler-Bernoulli (mm)Timoshenko (mm)비율

4−0.03689−0.056381.528

8−0.59029−0.668251.132

10−1.44113−1.562951.085

20−23.0581−23.54531.021

30−116.732−117.8281.009

모든 OpenSees 값이 손계산 공식과 기계 정밀도로 일치한다. 이 비교를 굳이 돌리는 이유가 그것이다. 입력한 Avy가 생각한 방식으로 쓰이고 있음을 확인해 준다. 지간/춤이 대략 15를 넘는 일반적인 건축 보에서는 전단을 무시해도 2% 미만이다. 전이보, 연결보, 깊은 스팬드럴, 짧은 링크처럼 지간/춤이 8 아래로 내려가는 부재에서는 1차 크기의 오차이며, 처짐과 주기 양쪽에서 위험측으로 작용한다.

전단면적은 총단면적이 아니다. 복부면 방향으로 하중을 받는 압연 I형강에서는 복부 면적이 통상적인 근사이고, 위에서 쓴 값도 그것이다. 대신 총단면적을 넣으면 전단 항이 너무 작아져 조용히 Euler-Bernoulli 답 쪽으로 되돌아간다.

9. 라멘 하나, 메시 네 가지, 독립적인 풀이

부재 단위 검증은 요소가 제대로 거동함을 확인한다. 라멘 검증은 조립이 제대로 되었음을 확인한다. 고정단 1경간 라멘을 보자. 기둥 4 m, 보 6 m, 왼쪽 절점에 횡하중 40 kN, 기둥 A = 6000 mm²·I = 1.2 × 10⁸ mm⁴, 보는 IPE 400이다.

강도가 점점 높아지는 검증 셋을 적용한다.

메시 불변성. 각 부재를 1, 2, 4, 8개로 나누면 절점 수평변위는 6.033772489039078, 6.033772489039160, 6.033772489038857, 6.033772489038708 mm가 나온다. 절점하중을 받는 등단면 탄성 부재는 부재당 요소 1개에서 이미 정확하므로, 선형탄성 라멘에서 메시에 따라 변하는 변위가 나온다면 그것은 다른 무언가의 신호다. 절점으로 나눠 건 분포하중이거나, 비선형 변환이거나, 모델링 오류다.

독립적인 풀이. NumPy로 짠 40줄짜리 직접강성 라멘 조립은 — OpenSees를 전혀 쓰지 않고 — 6.033772489039058 mm를 준다. 유효숫자 13자리까지 일치한다.

평형. 두 기초 반력은 Fx, Fy, Mz 순서로 (−20.0864, −11.7794, 44.8832)와 (−19.9136, +11.7794, 44.4406)이다. 수평력 합은 −40.000 kN으로 작용하중과 균형을 이룬다. 연직력은 상쇄된다. 왼쪽 기초에 대한 모멘트 합은 44.883 + 44.441 + 6 × 11.779 = 160.0 kN·m로 작용 모멘트 40 × 4 = 160 kN·m와 균형을 이룬다.

이 반력에서 눈여겨볼 세부가 하나 있다. 반올림 오차가 아니라 작은 물리 결과다. 수평반력은 각각 정확히 20 kN이 아니다. 20.086 / 19.914로 갈리는데, 보의 축강성이 유한해서 두 기둥의 수평변위가 완전히 같지 않기 때문이다. 보를 축방향으로 강체로 두면 — 고전적인 전단건물 가정 — 정확히 대칭이 된다. 그 가정이 허용되는지는 모델링 판단이고, 유용한 습관은 모델이 이미 어떤 가정을 했다는 사실을 알아채는 것이다.

# 독립 검증 전문 import math import numpy as np E = 200.0e6 nodes = {1: (0.0, 0.0), 2: (0.0, 4.0), 3: (6.0, 4.0), 4: (6.0, 0.0)} members = [(1, 2, 6.0e-3, 1.2e-4), (2, 3, 8.45e-3, 2.313e-4), (3, 4, 6.0e-3, 1.2e-4)] K = np.zeros((12, 12)) for i, j, A, I in members: xi, yi = nodes[i]; xj, yj = nodes[j] Le = math.hypot(xj - xi, yj - yi) c, s = (xj - xi) / Le, (yj - yi) / Le ea, ei = E * A / Le, E * I / Le ** 3 kl = np.array([ [ ea, 0, 0, -ea, 0, 0], [ 0, 12 * ei, 6 * ei * Le, 0, -12 * ei, 6 * ei * Le], [ 0, 6 * ei * Le, 4 * ei * Le**2, 0, -6 * ei * Le, 2 * ei * Le**2], [-ea, 0, 0, ea, 0, 0], [ 0, -12 * ei, -6 * ei * Le, 0, 12 * ei, -6 * ei * Le], [ 0, 6 * ei * Le, 2 * ei * Le**2, 0, -6 * ei * Le, 4 * ei * Le**2]]) Rm = np.array([[c, s, 0], [-s, c, 0], [0, 0, 1]]) T = np.zeros((6, 6)); T[:3, :3] = Rm; T[3:, 3:] = Rm dofs = [3*(i-1), 3*(i-1)+1, 3*(i-1)+2, 3*(j-1), 3*(j-1)+1, 3*(j-1)+2] K[np.ix_(dofs, dofs)] += T.T @ kl @ T free = [3, 4, 5, 6, 7, 8] # 절점 2, 3 의 자유도 전부 F = np.zeros(6); F[0] = 40.0 u = np.linalg.solve(K[np.ix_(free, free)], F) print(u[0] * 1000) # -> 6.033772489039058 mm

10. 여섯 가지 선택과 각각이 바꾸는 것

지금까지의 내용은 결국 소수의 결정으로 환원된다. 의식하든 안 하든 라멘 모델은 이 결정들을 이미 내리고 있다.

가장 자주 자동조종에 맡겨지는 것은 메시인데, 탄성 라멘에서 정확도에는 가장 덜 중요하고 무엇을 관찰할 수 있는지에는 가장 중요하다. 가장 자주 당연시되는 것은 변환인데, 어떤 거동군이 모델에 존재하기라도 하는지를 결정한다.

11. 보와 라멘에 특유한 오류

증상유력한 원인확인 방법

구속이 다 되어 보이는데 matrix singular트러스 요소만 붙은 절점의 회전 자유도구속하거나 회전강성이 있는 부재를 연결

처짐이 깔끔한 배수(2, 4, 10⁴, 10⁸)로 틀림Iy/Iz 교환 또는 cm⁴/mm⁴/m⁴ 혼용부재 하나를 PL³/3EI로 손계산 대조

세장한 라멘에서 2차 효과가 없음geomTransf('Linear', ...)PDelta로 재실행해 변위 비교

탄성 라멘인데 처짐이 메시에 따라 천천히 수렴분포하중을 eleLoad 대신 절점에 나눠 걸었음eleLoad로 바꾸고 메시 무관해지는지 확인

3차원 모델에서 부재가 엉뚱한 방향으로 휨여러 방향에 geomTransf 태그 하나를 재사용방향당 태그 하나, 각각 근거 있는 vecxz

깊은 보가 계측보다 훨씬 뻣뻣함전단변형 누락실제 지간/춤에서 ElasticTimoshenkoBeam과 비교

12. 같은 논리를 다섯 단계 깊이로

입문자는 ndf 3, 변환 태그, 일관된 단위를 맞추고 반력 합이 작용하중과 같은지 확인한다. 초급 실무자는 라멘을 믿기 전에 요소 질의로 wL²/8, wL²/12, PL³/3EI를 재현한다. 실무 해석자는 분포하중을 eleLoad로 걸고, 정확도가 아니라 출력 해상도를 기준으로 메시를 정하며, 결과가 어떤 변환에 의존하는지 명시한다. 선임 엔지니어는 여섯 선택이 확정한 이상화 — 강막인가 유연막인가, 전단변형을 포함하는가, 1차인가 2차인가 — 를 알고 숫자와 함께 보고한다. 전문가는 탄성 보–기둥이 더 이상 적절한 요소가 아닌 지점을 알고 모델을 파이버 단면과 비선형 재료로 옮긴다. 3부가 시작되는 곳이 거기다.

13. 탄성 라멘 모델 최소 점검표

ndf 3(2D) 또는 ndf 6(3D)이 일관되게 쓰였고, 모든 fix()·load()가 그만큼의 값을 가지는가?

모든 보–기둥 요소가 의도적으로 고른 변환 태그를 참조하는가?

3차원에서 부재 방향마다 변환 태그가 하나씩 있고, 각 vecxz를 근거로 설명할 수 있는가?

A, E, Iy, Iz, J의 단위 일관성을 손계산 하나로 확인했는가?

분포하중을 eleLoad로 걸었는가, 아니면 등가하중 오차를 정량화했는가?

부재 하나가 교과서 값 — PL³/3EI, 5wL⁴/384EI, wL²/8, wL²/12 — 을 재현하는가?

메시를 잘게 해도 탄성 결과가 변하지 않는가? 그래야 정상이다.

반력이 임의 점에 대해 힘과 모멘트 양쪽에서 작용하중과 균형을 이루는가?

안정성이 문제될 수 있다면 PDelta로 재실행해 차이를 보고했는가?

지간/춤이 10 아래인 부재가 있다면 전단변형을 포함했거나 명시적으로 배제했는가?

모두 몇 분 안에 답할 수 있고, 각각이 어느 시점엔가 라멘 모델이 틀린 유일한 이유였던 적이 있다. 3부는 같은 형상과 같은 검증 규율을 유지한 채 탄성 단면을 파이버 단면으로 바꾸고, 첫 항복 이후에 무슨 일이 일어나는지 묻기 시작한다.

전체 스크립트

이 글의 보를 두 가지 경로로, 기하변환 세 가지 모두로 만들고 메시를 조밀하게 해봅니다. 힘기반 요소에 건 분포하중이 80/N² 퍼센트만큼 모자라고 직접 탄성요소는 어떤 메시에서도 정확하다는 측정이기도 합니다.

# Part 2 - sections, geometric transformations and a distributed load # units: kN, m import openseespy.opensees as ops L, E, B, H, w = 6.0, 2.0e8, 0.30, 0.50, 12.0 A, I = B * H, B * H**3 / 12.0 D_X, R_X, M_X = -5*w*L**4/(384*E*I), w*L/2, w*L**2/8 def beam(route, transf='Linear', n=20, npts=5): """A simply supported beam under a uniform load, built two ways.""" ops.wipe(); ops.model('basic', '-ndm', 2, '-ndf', 3) for i in range(n + 1): ops.node(i + 1, i * L / n, 0.0) ops.fix(1, 1, 1, 0); ops.fix(n + 1, 0, 1, 0) ops.geomTransf(transf, 1) if route == 'section + forceBeamColumn': ops.section('Elastic', 1, E, A, I) ops.beamIntegration('Lobatto', 1, 1, npts) for i in range(n): ops.element('forceBeamColumn', i + 1, i + 1, i + 2, 1, 1) else: for i in range(n): ops.element('elasticBeamColumn', i + 1, i + 1, i + 2, A, E, I, 1) ops.timeSeries('Linear', 1); ops.pattern('Plain', 1, 1) for i in range(n): ops.eleLoad('-ele', i + 1, '-type', '-beamUniform', -w) # not a nodal load ops.constraints('Plain'); ops.numberer('Plain'); ops.system('BandGeneral') ops.test('NormDispIncr', 1e-12, 20); ops.algorithm('Linear') ops.integrator('LoadControl', 1.0); ops.analysis('Static'); ops.analyze(1) ops.reactions() return (ops.nodeDisp(n // 2 + 1, 2), ops.nodeReaction(1, 2), abs(ops.eleResponse(n // 2, 'basicForce')[2])) print(f'exact: midspan {D_X:.10f} m reaction {R_X:.6f} kN moment {M_X:.6f} kN m') print(f"\n{'route':30s}{'transf':14s}{'midspan (m)':>15s}{'reaction':>11s}{'moment':>10s}") for route in ('elasticBeamColumn', 'section + forceBeamColumn'): for tr in ('Linear', 'PDelta', 'Corotational'): d, R, M = beam(route, tr) print(f'{route:30s}{tr:14s}{d:15.10f}{R:11.5f}{M:10.4f}') print(f"\nthe same two routes as the mesh is refined\n") print(f"{'elements':>9s}{'elasticBeamColumn':>20s}{'err':>9s}" f"{'forceBeamColumn':>18s}{'err':>9s}{'x N^2':>8s}") errs = {} for n in (4, 20, 80): d1 = beam('elasticBeamColumn', n=n)[0] d2 = beam('section + forceBeamColumn', n=n)[0] e1, e2 = (d1 - D_X) / D_X, (d2 - D_X) / D_X errs[n] = e2 print(f'{n:9d}{d1:20.10f}{100*e1:8.3f}%{d2:18.10f}{100*e2:8.3f}%{100*e2*n*n:8.2f}') assert abs(e1) < 1e-9, 'elasticBeamColumn should be exact at any mesh' for npts in (3, 5, 8): d = beam('section + forceBeamColumn', n=20, npts=npts)[0] assert abs(d - beam('section + forceBeamColumn', n=20, npts=3)[0]) < 1e-14 print(f'\nOK elasticBeamColumn is exact at every mesh. The force-based route is') print(f' short by about {abs(100*errs[4]*16):.0f}/N^2 per cent and does not depend on the') print(f' number of integration points: for a distributed load the mesh matters') print(f' and the integration points do not.')

실행하면 이렇게 나옵니다.

exact: midspan -0.0003240000 m reaction 36.000000 kN moment 54.000000 kN m route transf midspan (m) reaction moment elasticBeamColumn Linear -0.0003240000 36.00000 54.0000 elasticBeamColumn PDelta -0.0003240000 36.00000 54.0000 elasticBeamColumn Corotational -0.0003240000 35.99993 54.0000 section + forceBeamColumn Linear -0.0003233520 36.00000 53.9100 section + forceBeamColumn PDelta -0.0003233520 36.00000 53.9100 section + forceBeamColumn Corotational -0.0003233520 35.99993 53.9100 the same two routes as the mesh is refined elements elasticBeamColumn err forceBeamColumn err x N^2 4 -0.0003240000 0.000% -0.0003078000 -5.000% -80.00 20 -0.0003240000 -0.000% -0.0003233520 -0.200% -80.00 80 -0.0003240000 -0.000% -0.0003239595 -0.012% -80.00 OK elasticBeamColumn is exact at every mesh. The force-based route is short by about 80/N^2 per cent and does not depend on the number of integration points: for a distributed load the mesh matters and the integration points do not.

OpenSees 시리즈 전체

각 편은 닫힌해·독립적인 풀이·OpenSees 소스 중 하나와 대조해 검증했다. 순서대로 읽도록 썼지만 각 편이 자기 전제를 스스로 밝힌다.

1부 — 도메인 모델과 해석 조립

2부 — 단면·기하변환·분포하중 — 지금 보는 글

3부 — 파이버 단면·모멘트–곡률·푸시오버

4부 — 질량·감쇠·시간적분

5부 — 라이브러리 읽기와 재현 가능한 워크플로

6부 — 철근콘크리트 파이버 단면과 구속

7부 — 실제 지진기록·층간변위·증분동적해석

8부 — 3차원: 강막·비틀림·leaning column

9부 — 수렴하지 않을 때: 실패·알고리즘·한계점

10부 — Tcl 읽기와 공개 스크립트 이식

11부 — 쉘·솔리드·지반: 락킹·메시·부지응답

12부 — 후처리: recorder·질의, 그리고 그림이 증명하는 것

13부 — 좌굴과 한계점: 분기점·스냅백·호장법

14부 — Windows: 설치·파일 형식·조용한 실패

15부 — 검증된 정답이 딸린 연습문제와 한영 용어집

16부 — 어떻게 동작하는가: 시행상태·확정상태·해석 루프

17부 — 커뮤니티가 말하는 것, 측정해보면

18부 — 절점 변위에서 파이버 응력까지

19부 — 면진과 감쇠: 속도 의존 요소와 베어링

참고 자료

위에서 쓴 모든 명령의 1차 문서와, 닫힌해 대조에 쓴 역학 자료다.

OpenSeesPy, elasticBeamColumn element — 2D·3D 인수 목록과 -release 옵션.

OpenSeesPy, ElasticTimoshenkoBeam element — 전단 유연 탄성 보–기둥.

OpenSeesPy, geomTransf, 그리고 Linear, PDelta, Corotational.

OpenSeesPy, eleLoad — 요소에 거는 분포·집중 하중.

OpenSeesPy, Portal Frame 2D 예제 — 같은 명령 체계로 작성된 공식 라멘 예제.

OpenSeesPy, section, beamIntegration, forceBeamColumn — 단면 기반 경로.

Pacific Earthquake Engineering Research Center, OpenSees Wiki — 명령 레퍼런스와 예제.

McKenna, F., OpenSees: A Framework for Earthquake Engineering Simulation, Computing in Science & Engineering 13(4), 2011.

MIT OpenCourseWare, 1.571 Structural Analysis and Control — 행렬강성법 정식화와 기하강성.

NAFEMS, Code Verification Benchmarks — 조립을 믿기 전에 요소를 벤치마크하는 관행.

자료 확인 2026-08-30. 이 글의 모든 수치는 OpenSeesPy 3.8.0에서 생성되었으며 위의 완전한 스크립트로 재현할 수 있다. 요소와 프레임워크의 동작을 보여주는 것이지 프로젝트별 해석이나 기준 적합성 검토를 대신하지 않는다.