บทที่ 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 ต่อ Framesummary = 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.020df_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 ทั้งหมดเป็น CSVdf_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
pip install matplotlib2. 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 มีข้อมูล Driftplt.figure(figsize=(6, 8))
# แกน Y คือ Story (ต้องเรียงชั้นให้ถูก)# แกน X คือ Drift Valueplt.plot(df_drift["Drift"], df_drift["Story"], 'ro-', label="Drift X")
# เส้น Limitplt.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(...) | แรงในชิ้นส่วน frame | P, V2, V3, T, M2, M3 |
Results.AreaForceShell(...) | แรงใน area (slab/wall) | F11, F22, M11, M22, V13 |
Results.JointDispl(...) | การเคลื่อนตัวของ joint | U1, U2, U3, R1, R2, R3 |
Results.StoryDrifts() | drift ของแต่ละชั้น | Drift, DisplX, DisplY |
Results.BaseReact() | แรงปฏิกิริยาที่ฐาน | Gx, Gy, Gz, Mx, My, Mz |
Results.JointReact(...) | แรงปฏิกิริยาที่ support | F1, F2, F3, M1, M2, M3 |