ข้ามไปยังเนื้อหา

บทที่ 7 อ่าน Results

ก่อนอ่าน Results

Frame Force (แรงในชิ้นส่วน)

โค้ดตัวอย่าง

# อ่าน Frame Force ของ frame ชื่อ "B1"
ret, num_results, obj, obj_sta, elm, elm_sta, \
load_case, step_type, step_num, \
p, v2, v3, t, m2, m3 = \
sap_model.Results.FrameForce(
"B1", # ชื่อ frame
0, # eItemTypeElm: 0=ObjectElm
)
check(ret, "Results.FrameForce")
# แสดงผล
print(f"\n🏗️ Frame Force - B1 ({num_results} results):")
print(f"{'Station':>10} {'P(kN)':>10} {'V2(kN)':>10} {'M3(kN·m)':>10} {'Case':>12}")
print("" * 55)
for i in range(num_results):
print(f"{obj_sta[i]:>10.3f} {p[i]:>10.2f} {v2[i]:>10.2f} "
f"{m3[i]:>10.2f} {load_case[i]:>12}")

Output ตัวอย่าง:

🏗️ Frame Force - B1 (3 results):
Station P(kN) V2(kN) M3(kN·m) Case
───────────────────────────────────────────────────────
0.000 0.00 25.50 -12.30 DEAD
0.500 0.00 0.00 15.80 DEAD
1.000 0.00 -25.50 -12.30 DEAD

อ่าน Frame Force ทุก Frame → pandas

import pandas as pd
rows = []
for frame_name in frame_names:
ret, nr, _obj, _os, _elm, _es, _lc, _st, _sn, \
_p, _v2, _v3, _t, _m2, _m3 = \
sap_model.Results.FrameForce(frame_name, 0)
if ret != 0 or nr == 0:
continue
for i in range(nr):
rows.append({
"Frame": frame_name,
"Station": _os[i],
"P": _p[i],
"V2": _v2[i],
"V3": _v3[i],
"T": _t[i],
"M2": _m2[i],
"M3": _m3[i],
"LoadCase": _lc[i],
})
df_forces = pd.DataFrame(rows)
print(f"\n📊 Total results: {len(df_forces)}")
print(df_forces.head(10))

หาค่า Max ของแต่ละ Frame

# หาค่า max absolute ของ V2 และ M3 ต่อ Frame
summary = df_forces.groupby("Frame").agg(
MaxV2=("V2", lambda x: x.abs().max()),
MaxM3=("M3", lambda x: x.abs().max()),
).reset_index()
print("\n🏗️ Summary (Top 10):")
print(summary.head(10).to_string(index=False))

Joint Displacement (การเคลื่อนตัวของจุดต่อ)

ret, num_res, j_obj, j_elm, j_case, j_step_type, j_step_num, \
u1, u2, u3, r1, r2, r3 = \
sap_model.Results.JointDispl(
"1", # ชื่อ joint
0, # eItemTypeElm: 0=ObjectElm
)
check(ret, "Results.JointDispl")
print(f"\n📍 Joint Displacement - Joint 1:")
print(f"{'Case':>12} {'U1(mm)':>10} {'U2(mm)':>10} {'U3(mm)':>10}")
print("" * 45)
for i in range(num_res):
print(f"{j_case[i]:>12} {u1[i]*1000:>10.3f} "
f"{u2[i]*1000:>10.3f} {u3[i]*1000:>10.3f}")

Story Drift (การเอียงตัวของชั้น)

ret, drift_results, d_story, d_case, d_direction, \
d_drift, d_displ_x, d_displ_y = \
sap_model.Results.StoryDrifts()
check(ret, "Results.StoryDrifts")
print(f"\n🏢 Story Drifts ({drift_results} results):")
print(f"{'Story':>10} {'Case':>12} {'Dir':>5} {'Drift':>12}")
print("" * 42)
for i in range(drift_results):
print(f"{d_story[i]:>10} {d_case[i]:>12} "
f"{d_direction[i]:>5} {d_drift[i]:>12.3E}")

Story Drift → pandas + ตรวจ Limit

df_drift = pd.DataFrame({
"Story": d_story,
"Case": d_case,
"Direction": d_direction,
"Drift": d_drift,
})
# ตรวจค่า drift ที่เกิน limit (เช่น 0.020)
DRIFT_LIMIT = 0.020
df_fail = df_drift[df_drift["Drift"].abs() > DRIFT_LIMIT]
if len(df_fail) > 0:
print(f"\n⚠️ Drift เกิน {DRIFT_LIMIT}:")
print(df_fail.to_string(index=False))
else:
print(f"\n✅ Drift ทุกชั้นผ่าน (< {DRIFT_LIMIT})")

Base Reactions (แรงปฏิกิริยาที่ฐาน)

ret, num_base_res, br_case, br_step_type, br_step_num, \
gx, gy, gz, mx, my, mz, \
br_x, br_y, br_z = \
sap_model.Results.BaseReact()
check(ret, "Results.BaseReact")
print(f"\n⚓ Base Reactions:")
for i in range(num_base_res):
print(f" {br_case[i]}: Fz={gz[i]:.2f} kN (total vertical reaction)")

Area Force (แรงใน Slab/Wall)

สำหรับ Area elements (พื้น, ผนัง) ใช้ AreaForceShell:

ret, num_area_res, a_obj, a_elm, a_pt_elm, \
a_case, a_step_type, a_step_num, \
f11, f22, f12, f_max, f_min, f_angle, f_vm, \
m11, m22, m12, m_max, m_min, m_angle, \
v13, v23, v_max, v_angle2 = \
sap_model.Results.AreaForceShell(
"F1", # ชื่อ area element
0, # eItemTypeElm: 0=ObjectElm
)
check(ret, "Results.AreaForceShell")
print(f"\n🧱 Area Force - F1 ({num_area_res} results):")
print(f"{'Point':<8} {'M11(kN·m/m)':>14} {'M22(kN·m/m)':>14} {'V13(kN/m)':>12}")
print("" * 50)
for i in range(num_area_res):
print(f"{a_pt_elm[i]:<8} {m11[i]:>14.2f} {m22[i]:>14.2f} {v13[i]:>12.2f}")

ตัวอย่าง: Export Results เป็น CSV/Excel

# Export Frame Force ทั้งหมดเป็น CSV
df_forces.to_csv("frame_forces.csv", index=False)
print("✅ Export frame_forces.csv เสร็จ!")
# Export เป็น Excel (ต้อง pip install openpyxl)
with pd.ExcelWriter("etabs_results.xlsx") as writer:
df_forces.to_excel(writer, sheet_name="FrameForces", index=False)
df_drift.to_excel(writer, sheet_name="StoryDrift", index=False)
print("✅ Export etabs_results.xlsx เสร็จ!")

Visualization with Matplotlib

จุดเด่นของ Python คือการทำ Data Visualization ได้ทันที:

1. ติดตั้ง matplotlib

Terminal window
pip install matplotlib

2. Plot Moment Diagram

import matplotlib.pyplot as plt
# สมมติ df_forces มีข้อมูล Frame Force ของ B1 แล้ว
# กรองเฉพาะ B1 และ Load Case "DEAD"
data = df_forces[
(df_forces["Frame"] == "B1") &
(df_forces["LoadCase"] == "DEAD")
].sort_values("Station")
plt.figure(figsize=(10, 4))
plt.plot(data["Station"], data["M3"], 'b-', label="Moment M3")
plt.fill_between(data["Station"], data["M3"], alpha=0.1)
plt.title("Bending Moment Diagram (B1 - DEAD)")
plt.xlabel("Distance (m)")
plt.ylabel("Moment (kN-m)")
plt.grid(True)
plt.legend()
# Save เป็นรูปภาพ
plt.savefig("BMD_B1.png")
print("✅ Saved BMD plot")
plt.show()

3. Plot Story Drift

# สมมติ df_drift มีข้อมูล Drift
plt.figure(figsize=(6, 8))
# แกน Y คือ Story (ต้องเรียงชั้นให้ถูก)
# แกน X คือ Drift Value
plt.plot(df_drift["Drift"], df_drift["Story"], 'ro-', label="Drift X")
# เส้น Limit
plt.axvline(x=0.02, color='k', linestyle='--', label="Limit (0.02)")
plt.title("Story Drift Ratio")
plt.xlabel("Drift Ratio")
plt.grid(True)
plt.legend()
plt.savefig("StoryDrift.png")
print("✅ Saved Drift plot")
plt.show()

สรุป Results API

Methodอธิบายค่าสำคัญ
Results.FrameForce(...)แรงในชิ้นส่วน frameP, V2, V3, T, M2, M3
Results.AreaForceShell(...)แรงใน area (slab/wall)F11, F22, M11, M22, V13
Results.JointDispl(...)การเคลื่อนตัวของ jointU1, U2, U3, R1, R2, R3
Results.StoryDrifts()drift ของแต่ละชั้นDrift, DisplX, DisplY
Results.BaseReact()แรงปฏิกิริยาที่ฐานGx, Gy, Gz, Mx, My, Mz
Results.JointReact(...)แรงปฏิกิริยาที่ supportF1, F2, F3, M1, M2, M3