Design Approach
The primary way you run design in Songeya is by writing your own custom design logic. You write Python scripts that access analysis results, perform design calculations, and store the results back into the model. This provides full control over the design process. You can implement any design standard that is appropriate to you region and line of work.
Some checks may take time to set up, especially the first time. But this is no different from what engineers already do. Most engineers build spreadsheets that handle routine design checks. Songeya works the same way, with the added advantage that the bespoke design tools can be directly connected to the Finite Element model results. Since Python is easy to read, you can share your design scripts with other people, or use scripts written by others.
You do not need to set up anything to get started. The program already includes an embedded Python interpreter and a built-in code editor, so you can write and run scripts directly inside the application. The full API is documented here.
An example is shown below for designing a steel member under axial force according to EN 1993-1-1. This script is included with the software. To use it, save it as a file and place it in the designated scripts folder. Then assign it to the frames you want to check. When the design process is initiated, the script will pull the required data, perform the checks, and generate a report in Markdown format, which can easily be converted to other formats.
Example: Axially Loaded Steel Member As Per EN 1993-1-1
import numpy as np
# Everything you need to use to interact with the program is in the module imported below
import songeya
# Get the frame. The variable "name" is available in the global context and represents
# the name of the frame being checked when the script is executed
frame = songeya.model.get_steel_frame(name)
# Only proceed if the model has loads
if not len(songeya.model.list_load_combinations()) > 0:
raise StopIteration("No loads found.")
# Supported section classes
HOT_ROLLED_I_SECTIONS = {
"UB", "UC", "ASB", "W", "IPN", "RSJ", "M", "S", "HP"
}
HOLLOW_SECTIONS = {
"CHS", "RHS", "SHS", "Sqr HSS", "Rect HSS",
"Round HSS", "Pipe STD", "Pipe XS", "Pipe XXS"
}
ANGLE_SECTIONS = {"EA", "UA"}
OTHER_SECTIONS = {
"PFC", "CH", "TUB", "TUC", "SQ", "SQR",
"RB", "MT", "WT", "ST", "C", "MC"
}
# Get the section and other necessary properties
section = frame.section()
dimensions = section.dimensions()
# Section properties
A = section.A()
Iy = section.Iy()
Iz = section.Iz()
It = section.Jt()
Iw = section.Iw()
try:
iz = section.iz()
except AttributeError:
iz = section.iy()
iy = section.iy()
axis1 = "y"
axis2 = "z"
if section.family() in ["EA", "UA"]:
# Angles buckle about minor axes
Iy = section.Iu()
Iz = section.Iv()
iy = section.iu()
iz = section.iv()
axis1 = "u"
axis2 = "v"
# Material
material = section.material()
fy = material.strength()
E = material.youngs_modulus()
G = material.shear_modulus()
gM0 = 1.0
gM1 = 1.0
fy_mpa = fy / 1e6
E_mpa = E / 1e6
L = frame.length()
def imperfection_factors(curve):
# Table 6.1
curves = {"a0": 0.13, "a": 0.21, "b": 0.34, "c": 0.49, "d": 0.76}
return curves[curve]
def buckling_curve_for_compression():
"""
Select buckling curves per EN 1993-1-1 Table 6.2.
"""
family = section.family()
dim = section.dimensions()
if family in HOT_ROLLED_I_SECTIONS:
h = dim["h"]
tf = dim["tf"]
b = dim["bb"]
if h / b > 1.2:
if tf < 0.04:
yy = "a"
zz = "b"
else:
yy = "b"
zz = "c"
else:
if tf <= 0.1:
yy = "b"
zz = "c"
else:
yy = "d"
zz = "d"
return yy, zz
elif family in HOLLOW_SECTIONS:
return "a", "a"
elif family in ["EA", "UA"]:
return "b", "b"
elif family in OTHER_SECTIONS:
return "c", "c"
else:
raise TypeError("Section family is not supported.")
def flexural_buckling_resistance(L_y, L_z):
"""
Flexural buckling resistance Nb,Rd per 6.3.1 (y-y and z-z axes).
Returns (Nb_Rd, Nb_Rd_y, Nb_Rd_z, chi_y, chi_z, lambda_y, lambda_z, phi_y, phi_z).
"""
lambda_1 = np.pi * np.sqrt(E / fy)
lambda_y = (L_y / iy) / lambda_1
lambda_z = (L_z / iz) / lambda_1
curve_yy, curve_zz = buckling_curve_for_compression()
alpha_y = imperfection_factors(curve_yy)
alpha_z = imperfection_factors(curve_zz)
phi_y = 0.5 * (1 + alpha_y * (lambda_y - 0.2) + lambda_y**2)
phi_z = 0.5 * (1 + alpha_z * (lambda_z - 0.2) + lambda_z**2)
chi_y = min(1.0, 1.0 / (phi_y + np.sqrt(max(phi_y**2 - lambda_y**2, 0))))
chi_z = min(1.0, 1.0 / (phi_z + np.sqrt(max(phi_z**2 - lambda_z**2, 0))))
Nb_Rd_y = chi_y * A * fy / gM1
Nb_Rd_z = chi_z * A * fy / gM1
Nb_Rd = min(Nb_Rd_y, Nb_Rd_z)
return (
Nb_Rd,
Nb_Rd_y,
Nb_Rd_z,
curve_yy,
curve_zz,
alpha_y,
alpha_z,
chi_y,
chi_z,
lambda_y,
lambda_z,
phi_y,
phi_z,
)
# Number of positions along the member to check
n_points = 10
positions = [i * 0.999 * L / (n_points - 1) for i in range(n_points)]
# Add some common points
positions.extend((0.24 * L, 0.5 * L, 0.75 * L))
# Add points of discontinuity
disconts = frame.discontinuities()
positions.extend(disconts)
positions = sorted(set(positions))
# Utilisations
ratio = {}
ratio["MAX"] = 0
ratio["Combination"] = ""
forces = {}
buckling_y = {}
buckling_z = {}
buckling_Rd = {}
def find_segment(x, segment_points):
"""
Returns (segment_index, x_start, x_end) for position x.
segment_points must be sorted.
"""
for i in range(len(segment_points) - 1):
x0 = segment_points[i]
x1 = segment_points[i + 1]
if x0 <= x <= x1:
return x0, x1
return None, None
fully_restrained_y, braced_yy = frame.flexural_buckling_restraints(buckling_axis="Y")
fully_restrained_z, braced_zz = frame.flexural_buckling_restraints(buckling_axis="Z")
for combo in songeya.model.list_load_combinations():
for x in positions:
# Determine the segment x falls in
yy_start, yy_end = find_segment(x, braced_yy)
zz_start, zz_end = find_segment(x, braced_zz)
# Determine moments for the yy and zz segments
yy_points = np.linspace(yy_start, yy_end, 20)
zz_points = np.linspace(zz_start, zz_end, 20)
# Find forces at current section
NEd = frame.fx(x=x, combo_name=combo) # - tension, + compression
N_comp = max(NEd, 0.0) # compression magnitude
N_ten = max(-NEd, 0.0) # tension magnitude
NEd = abs(NEd)
# Find section compression resistance
L_y = yy_end - yy_start
L_z = zz_end - zz_start
if fully_restrained_y:
L_y = 0
if fully_restrained_z:
L_z = 0
nc_rd = A * fy / gM0 # This is for class 1,2 and 3.
(
nb_rd,
nb_rd_y,
nb_rd_z,
curve_yy,
curve_zz,
alpha_y,
alpha_z,
chi_y,
chi_z,
lambda_y,
lambda_z,
phi_y,
phi_z,
) = flexural_buckling_resistance(L_y, L_z)
# Find tension resistance
nt_rd = A * fy / gM0
# Section checks
UFS_NT = N_ten / nt_rd # Nt,Ed/Nc,Rd
UFS_NC = N_comp / nc_rd # N,Ed/Nc,Rd
UFB_NB = N_comp / nb_rd
# Maximum utilisation ratio
max_ratio = max([UFS_NT, UFS_NC, UFB_NB])
if max_ratio < ratio["MAX"]:
continue
forces = {}
forces["Nc,Ed"] = N_comp
forces["Nt,Ed"] = N_ten
# Buckling parameters about the y-axis
buckling_y = {}
buckling_y["Curve,y"] = curve_yy # Buckling curve
buckling_y["Lcr,y"] = L_y # Effective buckling length
buckling_y["Lam,y"] = L_y / iy # Slenderness ratio
buckling_y["Lam_nd,y"] = lambda_y # Non-dimensional slenderness for buckling
buckling_y["alpha,y"] = alpha_y # Imperfection factor
buckling_y["phi,y"] = phi_y # Coefficient for calculation of X
buckling_y["X,y"] = chi_y # Reduction factor for buckling
buckling_y["Ny,b,Rd"] = nb_rd_y # Design buckling resistance
# Buckling parameters about the z-axis
buckling_z = {}
buckling_z["Curve,z"] = curve_zz # Buckling curve
buckling_z["Lcr,z"] = L_z # Effective buckling length
buckling_z["Lam,z"] = L_z / iz # Slenderness ratio
buckling_z["Lam_nd,z"] = lambda_z # Non-dimensional slenderness for buckling
buckling_z["alpha,z"] = alpha_z # Imperfection factor
buckling_z["phi,z"] = phi_z # Coefficient for calculation of X
buckling_z["X,z"] = chi_z # Reduction factor for buckling
buckling_z["Nz,b,Rd"] = nb_rd_z # Design buckling resistance
buckling_Rd = {}
buckling_Rd["Nc,Rd"] = nc_rd # Design compression resistance
buckling_Rd["Nt,Rd"] = nt_rd # Tension resistance of member
buckling_Rd["Nb,Rd"] = nb_rd # Design buckling resistance of compression member
# Section capacity
ratio["UFS[Nc]"] = UFS_NC # N,Ed/Nc,Rd
ratio["UFS[Nt]"] = UFS_NT # N,Ed/Nt,Rd
# Global capacity
ratio["UFB[Nb]"] = UFB_NB
ratio["MAX"] = max_ratio
ratio["Combination"] = combo
# Generate report
status = "Meets Criteria" if ratio.get("MAX", 0.0) <= 1.0 else "Fails Criteria"
markdown_text = f"""
# Axial member design to EN 1993-1-1: {name}
## Load combination: {ratio['Combination']}
## Limitations
- Can only be used for steel grades S235, S275, S355 and S420
- Serviceability deflection limits are not checked
- Class 4 cross-sections are not handled
- Torsional nad torsional-flexural buckling are not checked. However, for columns in buildings, these are less onerous than flexural (Euler) buckling
## Material
| Property | Value | Reference | Description |
|--------------------|-------------------|-----------|-------------|
| Name | S{int(fy_mpa)} | - | - |
| Yield strength, fy | {fy_mpa:.1f} MPa | - | - |
| Elastic modulus, E | {E_mpa:.0f} MPa | - | - |
| Shear modulus, G | {G / 1e9:.0f} MPa | - | - |
| gM0 | {gM0} | 2.4 | Partial factor for resistance of cross-section |
| gM1 | {gM1} | 2.4 | Partial factor for buckling resistance |
## Section properties
| Property | Value | Description |
|----------|--------------------|-------------------------------------|
| A | {A * 1e4:.1f} cm² | Cross-sectional area |
| I{axis1} | {Iy * 1e8:.0f} cm⁴ | Moment of inertia about major axis |
| I{axis2} | {Iz * 1e8:.0f} cm⁴ | Moment of inertia about minor axis |
| i{axis1} | {iy * 1e3:.0f} mm | Radius of gyration about major axis |
| i{axis2} | {iz * 1e3:.0f} mm | Radius of gyration about minor axis |
## Applied forces: {ratio['Combination']}
| Action | Value |
|-----------|-----------------------------------|
| Nc,Ed | {forces["Nc,Ed"] / 1e3:.1f} kN |
| Nt,Ed | {forces["Nt,Ed"] / 1e3:.1f} kN |
## Flexural buckling about {axis1}-axis
| Parameter | Value | Formula | Reference | Description |
|---------------|----------------------------------------|-------------------------------------|-------------|-------------|
| Curve | {buckling_y["Curve,y"]} | - | Table 6.2 | Buckling curve
| Lcr | {buckling_y["Lcr,y"]:.2f} m | - | - | Effective buckling length
| Lam | {buckling_y["Lam,y"]:.2f} | Lcr/i{axis1} | - | Slenderness ratio
| Lam_nd | {buckling_y["Lam_nd,y"]:.3f} | sqrt(A*fy/Ncr) | 6.3.1.2 | Non-dimensional slenderness for buckling
| alpha | {buckling_y["alpha,y"]:.3f} | - | Table 6.1 | Imperfection factor
| phi | {buckling_y["phi,y"]:.3f} | 0.5*[1+alpha*(lam_nd-0.2)+lam_nd^2] | 6.3.1.2 | Coefficient for calculation of chi
| chi | {buckling_y["X,y"]:.3f} | 1/[phi+sqrt(phi^2-lam_nd^2)] | 6.3.1.2 | Reduction factor for buckling
| N{axis1},b,Rd | {buckling_y["Ny,b,Rd"] * 1e-3:.1f} kN | chi*A*fy/gM1 | 6.3.1.1 | Design buckling resistance
## Flexural buckling about {axis2}-axis
| Parameter | Value | Formula | Reference | Description |
|---------------|----------------------------------------|-------------------------------------|-------------|-------------|
| Curve | {buckling_z["Curve,z"]} | - | Table 6.2 | Buckling curve
| Lcr | {buckling_z["Lcr,z"]:.2f} m | - | - | Effective buckling length
| Lam | {buckling_z["Lam,z"]:.2f} | Lcr/i{axis1} | - | Slenderness ratio
| Lam_nd | {buckling_z["Lam_nd,z"]:.3f} | sqrt(A*fy/Ncr) | 6.3.1.2 | Non-dimensional slenderness for buckling
| alpha | {buckling_z["alpha,z"]:.3f} | - | Table 6.1 | Imperfection factor
| phi | {buckling_z["phi,z"]:.3f} | 0.5*[1+alpha*(lam_nd-0.2)+lam_nd^2] | 6.3.1.2 | Coefficient for calculation of chi
| chi | {buckling_z["X,z"]:.3f} | 1/[phi+sqrt(phi^2-lam_nd^2)] | 6.3.1.2 | Reduction factor for buckling
| N{axis2},b,Rd | {buckling_z["Nz,b,Rd"] * 1e-3:.1f} kN | chi*A*fy/gM1 | 6.3.1.1 | Design buckling resistance
## Resistances (EN 1993-1-1)
| Parameter | Value | Formula | Reference | Description |
|-----------|-------------------------------------|--------------------|-----------|-------------------------------------|
| Nc,Rd | {buckling_Rd["Nc,Rd"] / 1e3:.2f} kN | A * fy / gM0 | 6.2.4 | Design compression resistance of cross-section |
| Nt,Rd | {buckling_Rd["Nt,Rd"] / 1e3:.2f} kN | A * fy / gM0 | 6.2.3 | Tension resistance of cross-section |
| Nb,Rd | {buckling_Rd["Nb,Rd"] / 1e3:.2f} kN | chi * A * fy / gM1 | 6.3.1.1 | Design flexural buckling resistance |
## Utilisation ratios
| Check | Value | Reference | Description |
|--------------|------------------------|------------|---------------------------|
| UFS[Nc] | {ratio["UFS[Nc]"]:.3f} | 6.2.4 | NEd / Nc,Rd |
| UFS[Nt] | {ratio["UFS[Nt]"]:.3f} | 6.2.3 | NEd / Nt,Rd |
| UFS[Nb] | {ratio["UFB[Nb]"]:.3f} | 6.2.3 | NEd / Nb,Rd |
| MAX | {ratio["MAX"]:.3f} | - | Maximum utilisation ratio |
## Status
**{status}**
---
*Designed to EN 1993-1-1*
*Generated via Songeya*
"""
frame.set_utilisation_ratio(ratio["MAX"])
if ratio["MAX"] > 1:
frame.set_fails_criteria()
else:
frame.set_meets_criteria()
frame.set_design_note(markdown_text)