Skip to content

Tutorials

This section provides practical examples to help you get started with PyCivil.

Quick Start

Geometry Basics

from pycivil.EXAGeometry.geometry import Point2d, Point3d, Vector2d, Polyline2d, Node2d

# 2D Points
p1 = Point2d(0, 0)
p2 = Point2d(100, 200)
distance = p1.distance(p2)
midpoint = p1.midpoint(p2)

# 2D Vectors
v = Vector2d(p1, p2)
v.normalize()

# Polylines
nodes = [
    Node2d(0.0, 0.0, 1),
    Node2d(300.0, 0.0, 2),
    Node2d(300.0, 500.0, 3),
    Node2d(0.0, 500.0, 4),
]
poly = Polyline2d(nodes)
poly.setClosed()

RC Section Analysis (SLS)

from pycivil.EXAStructural.codes import Code
from pycivil.EXAStructural.materials import Concrete, ConcreteSteel
from pycivil.EXAStructural.templateRCRect import RCTemplRectEC2

# Set code and materials
code = Code("NTC2018")

concrete = Concrete(descr="My concrete")
concrete.setByCode(code, "C25/30")

steel = ConcreteSteel(descr="My steel")
steel.setByCode(code, "B450C")

# Create rectangular RC section
rcSection = RCTemplRectEC2(1, "Beam Section")
rcSection.setDimH(600)  # height in mm
rcSection.setDimW(300)  # width in mm

# Add reinforcement (LINE-MB = bottom, LINE-MT = top)
rcSection.addSteelArea("LINE-MB", dist=50, d=20, nb=4, sd=40)  # 4Ø20 bottom
rcSection.addSteelArea("LINE-MT", dist=50, d=20, nb=4, sd=40)  # 4Ø20 top

# Calculate section properties
print(f"Concrete area: {rcSection.calConcreteArea()} mm²")
print(f"Steel area: {rcSection.calSteelArea():.0f} mm²")
print(f"Ideal area: {rcSection.calIdealArea():.0f} mm²")

# SLS analysis under N and M
KN = 1000
KNm = 1000 * 1000
N = -1000 * KN   # axial force (negative = compression)
M = 150 * KNm    # bending moment

sigmac, sigmas, xi = rcSection.solverSLS_NM(N, M, uncracked=True)
print(f"Concrete stress: {sigmac:.2f} MPa")
print(f"Steel stress: {sigmas:.2f} MPa")
print(f"Neutral axis: {xi:.2f} mm")

Section Modeler

from pycivil.EXAStructural.modeler import SectionModeler

# Create modeler
md = SectionModeler()
md.addSection(1, True)

# Define concrete shape (300x600 rectangle)
md.addNode(1, 0, 0)
md.addNode(2, 300, 0)
md.addNode(3, 300, 600)
md.addNode(4, 0, 600)
md.addTriangle(1, 1, 2, 3)
md.addTriangle(2, 3, 4, 1)

# Add bottom reinforcement (4Ø28)
for i, x in enumerate([60, 120, 180, 240]):
    md.addNode(20 + i, x, 40)
    md.addCircle(20 + i, 20 + i, 28 / 2)

# Add top reinforcement (4Ø16)
for i, x in enumerate([60, 120, 180, 240]):
    md.addNode(10 + i, x, 560)
    md.addCircle(10 + i, 10 + i, 16 / 2)

# Calculate properties
print(f"Solid barycenter: {md.calcSolidBarycenter()}")
print(f"Solid area: {md.calcSolidArea()} mm²")
print(f"Point area (rebars): {md.calcPointArea():.0f} mm²")

ULS Interaction Domain (N-M)

from pycivil.EXAStructural.codes import Code
from pycivil.EXAStructural.materials import Concrete, ConcreteSteel
from pycivil.EXAStructural.templateRCRect import RCTemplRectEC2

# Set code and materials
code = Code("NTC2018")

concrete = Concrete(descr="My concrete")
concrete.setByCode(code, "C25/30")

steel = ConcreteSteel(descr="My steel")
steel.setByCode(code, "B450C")

# Create rectangular RC section
rcSection = RCTemplRectEC2(1, "Beam Section")
rcSection.setDimH(600)  # height in mm
rcSection.setDimW(300)  # width in mm

# Add reinforcement
rcSection.addSteelArea("LINE-MB", dist=50, d=20, nb=4, sd=40)  # 4Ø20 bottom
rcSection.addSteelArea("LINE-MT", dist=50, d=16, nb=4, sd=40)  # 4Ø16 top

# Build ULS interaction domain (N-M)
pointCloud, bounding = rcSection.interactionDomainBuild2d(
    nbPoints=100, SLS=False, bounding=True
)

# Bounding box: [Nmin, Nmax, Mmin, Mmax]
print(f"N range: {bounding[0]/1000:.0f} to {bounding[1]/1000:.0f} kN")
print(f"M range: {bounding[2]/1e6:.0f} to {bounding[3]/1e6:.0f} kNm")

# Check if a load point is inside the domain
N_ed = -200.0 * 1000  # -200 kN (compression)
M_ed = 100.0 * 1e6    # 100 kNm

contained, pintersect, intfactor, pindex = pointCloud.contains(
    N_ed, M_ed, rayFromCenter=True,
    ro=(bounding[1] - bounding[0], bounding[3] - bounding[2])
)

print(f"Load N_Ed={N_ed/1000:.0f} kN, M_Ed={M_ed/1e6:.0f} kNm")
print(f"Inside domain: {contained}")
print(f"Utilization factor: {1/intfactor:.2f}")

Critical Moment (Cracking Moment)

from pycivil.EXAStructural.codes import Code
from pycivil.EXAStructural.materials import Concrete, ConcreteSteel
from pycivil.EXAStructural.templateRCRect import RCTemplRectEC2

# Set code and materials
code = Code("NTC2018")

concrete = Concrete(descr="My concrete")
concrete.setByCode(code, "C25/30")

steel = ConcreteSteel(descr="My steel")
steel.setByCode(code, "B450C")

# Create rectangular RC section
rcSection = RCTemplRectEC2(1, "Beam Section")
rcSection.setDimH(600)  # height in mm
rcSection.setDimW(300)  # width in mm

# Add reinforcement
rcSection.addSteelArea("LINE-MB", dist=50, d=20, nb=4, sd=40)  # 4Ø20 bottom
rcSection.addSteelArea("LINE-MT", dist=50, d=16, nb=4, sd=40)  # 4Ø16 top

# Calculate critical moment (moment that cracks the section)
KN = 1000
KNm = 1000 * 1000

# Without axial force
mcr_pos, mcr_neg = rcSection.calCriticalMoment()
print(f"Mcr+ = {mcr_pos/KNm:.2f} kNm")   # 63.16 kNm
print(f"Mcr- = {mcr_neg/KNm:.2f} kNm")   # -59.87 kNm

# With compressive axial force (N = -500 kN)
mcr_pos, mcr_neg = rcSection.calCriticalMoment(N=-500 * KN)
print(f"Mcr+ (with N) = {mcr_pos/KNm:.2f} kNm")  # 122.59 kNm
print(f"Mcr- (with N) = {mcr_neg/KNm:.2f} kNm")  # -116.19 kNm

RC Section Checker (ucasefe)

from pycivil.EXAUtils.ucasefe import RCRectCalculator

# Create calculator
calc = RCRectCalculator("My Project", "Beam B1")
calc.setLogLevel(0)  # quiet mode
calc.setJobPath("/path/to/output")  # where reports will be saved

# Units
KN = 1000
KNm = 1000000

# Section dimensions (mm)
calc.setDimensions(w=300, h=600)

# Materials
calc.setMaterialConcrete("NTC2018", "C25/30", "not aggressive")
calc.setMaterialRebars("NTC2018", "B450C", "not sensitive")

# Reinforcement
calc.addRebarsFromTop(num=4, diam=20, dist_from_top=40, dist_rebars=40)
calc.addRebarsFromBot(num=4, diam=20, dist_from_bot=40, dist_rebars=40)
calc.setStirrup(area=100, step=150, angle=90)

# Add load cases with checks
calc.addForce(N=-100*KN, M=145*KNm, T=120*KN,
              limit_state="serviceability", frequency="quasi-permanent",
              check_required=["SLE-NM", "SLE-F"], descr="Load case 1")

calc.addForce(N=-200*KN, M=200*KNm, T=200*KN,
              limit_state="ultimate",
              check_required=["SLU-T", "SLU-NM"], descr="Load case 2")

# Run analysis and build report
if calc.run():
    calc.buildReport()  # generates LaTeX report

Marimo Notebook Examples

The following examples are adapted from interactive Marimo notebooks. They demonstrate more advanced use cases of PyCivil.

Material Properties: Concrete

This example shows how to access concrete material properties according to different building codes.

from pycivil.EXAStructural import materials, codes

# Select code and concrete class
code = codes.Code("NTC2018")
concrete = materials.Concrete(1, "Column C1")
concrete.setByCode(code, "C30/37")

# Characteristic values
print(f"Rck = {concrete.get_Rck():.1f} MPa")
print(f"fck = {concrete.get_fck():.1f} MPa")
print(f"fcm = {concrete.get_fcm():.1f} MPa")
print(f"fctm = {concrete.get_fctm():.1f} MPa")
print(f"Ecm = {concrete.get_Ecm():.0f} MPa")

# Design values
print(f"alpha_cc = {concrete.get_alphacc():.2f}")
print(f"gamma_c = {concrete.get_gammac():.1f}")
print(f"fcd = {concrete.cal_fcd():.1f} MPa")
print(f"sigma_c,max (characteristic) = {concrete.get_sigmac_max_c():.1f} MPa")
print(f"sigma_c,max (quasi-permanent) = {concrete.get_sigmac_max_q():.1f} MPa")

Material Properties: Reinforcing Steel

This example shows how to access rebar material properties according to different building codes.

from pycivil.EXAStructural import materials, codes

# Select code and steel class
code = codes.Code("NTC2018")
steel = materials.ConcreteSteel(1, "Rebars")
steel.setByCode(code, "B450C")

# Characteristic values
print(f"fyk = {steel.get_fsy():.1f} MPa")
print(f"ftk = {steel.get_fuk():.1f} MPa")
print(f"Es = {steel.get_Es():.0f} MPa")

# Design values
print(f"gamma_s = {steel.get_gammas():.2f}")
print(f"fyd = {steel.cal_fyd():.1f} MPa")
print(f"sigma_s,max (characteristic) = {steel.get_sigmas_max_c():.1f} MPa")

RC Calculator with Multiple Load Cases

This example demonstrates a complete RC rectangular section check with multiple load combinations.

from pycivil.EXAUtils.ucasefe import RCRectCalculator

calc = RCRectCalculator("python_course", "Section 1")
calc.setDescription("Beam section with multiple load cases")
calc.setLogLevel(3)  # verbose output
calc.setJobPath("./output")

KN = 1000
KNm = 1000000

# Section geometry
calc.setDimensions(300, 600)

# Materials
calc.setMaterialConcrete("NTC2018", "C25/30", "not aggressive")
calc.setMaterialRebars("NTC2018", "B450C", "not sensitive")

# Reinforcement
calc.addRebarsFromTop(dist_from_top=40, dist_rebars=40, num=3, diam=14)
calc.addRebarsFromBot(dist_from_bot=40, dist_rebars=40, num=6, diam=20)
calc.setStirrup(area=100, step=150, angle=90)

# SLS load cases
calc.addForce(N=150*KN, M=150*KNm, T=150*KN, descr="SLS Characteristic 1",
              limit_state="serviceability", frequency="characteristic",
              check_required=["SLE-NM"])

calc.addForce(N=100*KN, M=145*KNm, T=120*KN, descr="SLS Characteristic 2",
              limit_state="serviceability", frequency="quasi-permanent",
              check_required=["SLE-NM"])

calc.addForce(N=-100*KN, M=145*KNm, T=120*KN, descr="SLS Q-P with crack",
              limit_state="serviceability", frequency="quasi-permanent",
              check_required=["SLE-NM", "SLE-F"])

calc.addForce(N=-125*KN, M=125*KNm, T=125*KN, descr="SLS Frequent",
              limit_state="serviceability", frequency="frequent",
              check_required=["SLE-NM", "SLE-F"])

# ULS load cases
calc.addForce(N=-200*KN, M=200*KNm, T=200*KN, descr="ULS Combo 1",
              limit_state="ultimate",
              check_required=["SLU-T", "SLU-NM"])

calc.addForce(N=-200*KN, M=-200*KNm, T=100*KN, descr="ULS Combo 2",
              limit_state="ultimate",
              check_required=["SLU-NM"])

calc.addForce(N=-500*KN, M=350*KNm, T=200*KN, descr="ULS Combo 3",
              limit_state="ultimate",
              check_required=["SLU-NM"])

calc.addForce(N=100*KN, M=-200*KNm, T=70*KN, descr="ULS Combo 4",
              limit_state="ultimate",
              check_required=["SLU-NM"])

# Run and generate report
calc.run()
calc.buildReport()

Generic Section Modeler (RCGenSectionsModeler)

This example shows how to model and analyze generic shaped RC sections with biaxial bending.

from pathlib import Path
from pycivil.EXAStructural.rcgensolver.templateRCGen import (
    RCGenSectionsModeler,
    Analysis,
    ReportBuilder
)
from pycivil.EXAGeometry.geometry import (
    Node2d,
    Point2d,
    twoPointsOffset,
    twoPointsDivide
)
from pycivil.EXAStructural.codes import Code
from pycivil.EXAStructural.materials import Concrete, ConcreteSteel
from pycivil.EXAStructural.loads import (
    ForcesOnSection,
    Frequency_Enum,
    LimiteState_Enum
)

# Initialize modeler
modeler = RCGenSectionsModeler()
modeler.logLevel = 0
modeler.setJobPath("./output")

# Create rectangular section
modeler.addSectionModel(key="section_1", current=True)

# Define section geometry (300x600 centered at origin)
nodeBL = Node2d(x=-150, y=-300)
nodeBR = Node2d(x=+150, y=-300)
nodeTR = Node2d(x=+150, y=+300)
nodeTL = Node2d(x=-150, y=+300)

id_nodeBL = modeler.addNode(nodeBL)
id_nodeBR = modeler.addNode(nodeBR)
id_nodeTR = modeler.addNode(nodeTR)
id_nodeTL = modeler.addNode(nodeTL)

modeler.addTriangle(id_nodeBL, id_nodeBR, id_nodeTL)
modeler.addTriangle(id_nodeBR, id_nodeTR, id_nodeTL)

# Add corner rebars
cc = 50  # cover
rebarsDiameterTOP = 16
rebarsDiameterBOT = 22

rebar_center_BL = nodeBL + Point2d(cc, cc)
rebar_center_BR = nodeBR + Point2d(-cc, cc)
rebar_center_TR = nodeTR + Point2d(-cc, -cc)
rebar_center_TL = nodeTL + Point2d(cc, -cc)

modeler.addRebar(center=rebar_center_BL, diameter=rebarsDiameterBOT)
modeler.addRebar(center=rebar_center_BR, diameter=rebarsDiameterBOT)
modeler.addRebar(center=rebar_center_TR, diameter=rebarsDiameterTOP)
modeler.addRebar(center=rebar_center_TL, diameter=rebarsDiameterTOP)

# Add intermediate rebars along bottom and top edges
barsBOT_1, barsBOT_2 = twoPointsOffset(rebar_center_BL, rebar_center_BR)
barsBOT = twoPointsDivide(barsBOT_1, barsBOT_2, 4, False)
barsTOP_1, barsTOP_2 = twoPointsOffset(rebar_center_TR, rebar_center_TL)
barsTOP = twoPointsDivide(barsTOP_1, barsTOP_2, 4, False)

modeler.addRebarsGroup(diameter=rebarsDiameterBOT, points=barsBOT)
modeler.addRebarsGroup(diameter=rebarsDiameterTOP, points=barsTOP)

# Assign materials
code = Code("NTC2018")

concreteMat = Concrete(descr="Concrete C30/37")
concreteMat.setByCode(code, "C30/37")

rebarMat = ConcreteSteel(descr="Steel B450C")
rebarMat.setByCode(code, "B450C")

idMatCon = modeler.addConcreteLaw(mat=concreteMat, idm=1)
idMatReb = modeler.addRebarLaw(mat=rebarMat, idm=2)

modeler.assignConcreteLawToCurrentModel(idMatCon)
modeler.assignRebarLawToCurrentModel(idMatReb)

# Define load cases with biaxial bending
KN = 1000
KNm = 1000 * 1000

forces = {
    1: ForcesOnSection(
        id=1, Fz=-100.0 * KN, Mx=70 * KNm, My=70 * KNm,
        limitState=LimiteState_Enum.SERVICEABILITY,
        frequency=Frequency_Enum.CHARACTERISTIC
    ),
    2: ForcesOnSection(
        id=2, Fz=-50.0 * KN, Mx=65 * KNm, My=45 * KNm,
        limitState=LimiteState_Enum.SERVICEABILITY,
        frequency=Frequency_Enum.CHARACTERISTIC
    ),
    3: ForcesOnSection(
        id=3, Fz=80.0 * KN, Mx=80 * KNm, My=80 * KNm,
        limitState=LimiteState_Enum.ULTIMATE
    ),
    4: ForcesOnSection(
        id=4, Fz=-30.0 * KN, Mx=-80 * KNm, My=80 * KNm,
        limitState=LimiteState_Enum.ULTIMATE
    ),
}

# Assign forces and run analysis
modeler.assignForces(forces)
modeler.run(opt=Analysis.ELASTIC_SOLVER)
modeler.run(opt=Analysis.CHECK_ELASTIC)
modeler.run(opt=Analysis.CHECK_DOMAIN_SLU)

# Plot results
modeler.plot(onlyWorst=False)

Available Codes

PyCivil supports the following structural codes:

  • EC2 - Eurocode 2-1-1 (concrete in compression)
  • EC2-1-2 - Eurocode 2-1-2 (fire design)
  • NTC2008 - Italian NTC2008 standard
  • NTC2018 - Italian NTC2018 standard
from pycivil.EXAStructural.codes import Code

# List available codes
print(Code.tabKeys)  # ['EC2', 'NTC2008', 'NTC2018', 'CIRC2008', 'CIRC2018']

Check Types

PyCivil supports the following verification types:

Check Code Description
SLE-NM Serviceability Limit State - Normal stress and Moment
SLE-F Serviceability Limit State - Crack width (Fessuration)
SLU-NM Ultimate Limit State - Normal force and Moment
SLU-T Ultimate Limit State - Shear (Taglio)
SLU-NM-FIRE Ultimate Limit State - Fire design