Skip to main content

alt text

What's PyCivil

A Python library for structural engineers that aims to make them as free as possible from commercial software while preserving their knowledge.

Version: 0.3.4 | Python: 3.10 - 3.14 | License: BSD-3-Clause

Source Code: GitLab

Features

  1. EXAGeometry - Low-level geometry classes for 2D/3D spatial calculations: Point2d, Point3d, Vector2d, Vector3d, Polyline2d, Polyline3d, Edge, Node, ShapeRect, ShapeCircle, ShapePoly

  2. EXAStructural - Core structural engineering domain models:

    • sections.py - Reinforced concrete section models (RectangularShape, TShape, IShape, polygonal shapes) with reinforcement disposers
    • materials.py - Concrete and Steel material definitions with code-based properties
    • loads.py - Load and force representations with limit state enums
    • codes.py - Code management system for EC2, NTC2008, NTC2018
    • templateRCRect.py - RC rectangular section template with SLS/SLU analysis and fire design
    • fireFiberDomain.py - Hot N-M interaction domain with fibres on the thermal map (EN 1992-1-2 hot laws), alternative to the 500 °C isotherm method
  3. EXAStructural/lawcodes - Implementation of structural codes with rules, strength formulas, loads and materials:

    • codeEC211.py - Eurocode 2-1-1 (concrete in compression, minimum reinforcement, shear resistance with and without shear reinforcement per 6.2.2 / 6.2.3)
    • codeEC212.py - Eurocode 2-1-2 (fire design rules)
    • codeEC22.py - Eurocode 2-2 (cracking criterion of membrane elements, LL.101-LL.112)
    • codeNTC2018.py - Italian NTC2018 standard
  4. EXAStructural/rcrecsolver - Solver for checking rectangular reinforced concrete sections under bending, axial and shear forces

  5. EXAStructural/rcgensolver - Solver for checking generic shaped reinforced concrete sections under bending, axial and shear forces

  6. EXAStructural/rcplatesolver - Sandwich-model solver for reinforced concrete plates and shells (EC2-2 Annex LL): SLU design of inner layer shear and outer layers, SLS stresses and crack widths with the compatible cracked membrane (compatible_membrane.py)

  7. EXAStructuralModel - FEM-agnostic finite element modeler (FEModel) with support for various load types, materials, section shapes, GMSH mesh generation, and MIDAS export

    • femfromdxf.py - DXF import (FEModel.importDxf): 3D geometry (frames and shells in any plane), names, loads, constraints and mesh rules drawn with the HC_ CAD tools (LISP commands and toolbar shipped in pycivil/res/lisp)
    • femtodxf.py - DXF export of geometry and mesh (FEModel.exportDxf); hcmesh.py - hc-mesh CLI used by the HC_MESH_BUILD / HC_MESH_IMPORT CAD commands
  8. EXAStructuralCheckable - Structural verification against design codes with multiple criteria: SLE-NM, SLE-F, SLU-NM, SLU-T, SLU-NM-FIRE (hot domain by 500 °C isotherm or by fibres), and crack severity classification

  9. EXAParametric - Parametric structural analysis for box and tube sections

  10. EXAGeotechnical - Geotechnical formulas and soil mechanics: Young's modulus tables, Poisson's ratio tables, Winkler foundation model, Bussinesque formulas

  11. EXAUtils - Utilities and tools:

    • strand7PostPro.py - Post-processor for Strand7 FEM results
    • ucasefe.py - High-level RC section calculator API
    • latexReportMakers.py - LaTeX-based report generation (PDF output)
    • typstReportMakers.py - Typst-based report generation (PDF output, no LaTeX required)
    • report.py - Report infrastructure with Reporter (LaTeX), MarkdownReporter (Markdown/HTML), and TypstReporter (Typst/PDF)
    • latexCheatSheets.py - Quick reference sheet generation
    • vtk.py - VTK visualization wrapper
    • gmsh.py - GMSH mesh generation wrapper

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():
    # Choose your preferred output format:
    calc.buildReport()          # LaTeX/PDF report (requires LaTeX installation)
    calc.buildMarkdownReport()  # Markdown report (no external dependencies)
    calc.buildHtmlReport()      # HTML report with MathJax for formulas
    calc.buildTypstReport()     # Typst/PDF report (no LaTeX required)

Install

For production with Windows or Linux

PyCivil releases are available as wheel packages for Windows and Linux on PyPI:

pip install pycivil

For development in Windows

Install uv

$installDir = "$env:USERPROFILE\.local\bin"
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
$env:UV_NATIVE_TLS = "true"
setx UV_NATIVE_TLS true

Prerequisites

  1. LaTeX installation (optional - only needed for PDF reports via LaTeX; Markdown/HTML reports work without it)
  2. Docker Engine (optional - useful if you need to generate thermal maps or use Code Aster)

Changelog

See CHANGELOG.md for version history.

Docs

The documentation is built with MkDocs and the Material theme.

Serve documentation locally

Start a local development server with live-reload:

task docs

This will start a server at http://127.0.0.1:8000 where you can browse the documentation.

Build static documentation

To build the static HTML documentation:

uv run --only-group docs mkdocs build

The output will be generated in the site/ directory.

NOTE: The documentation is still being written. In the meantime, check the tutorials and the tests for practical examples.

Development

  • Install task
  • run task init do initialize the python environment and install the pre-commit hooks
  • before committing code changes, you can run task to perform automated checks. You can also run them separately:
    • task lint fixes and checks the code and documentation
    • task mypy performs type checking
    • task test runs the tests with pytest
    • task security scans the dependencies for known vulnerabilities

NOTE: the lint task is executed automatically when you commit the changes to ensure that only good quality code is added to the repository.

Docker container

If you're a docker-compose guy, you can run the docker-compose.yml file with:

docker-compose up --build

This will also create Code_Aster containers, and you will be able to use Code_Aster as FEM solver.

Remove all volumes

This remove all volumes and data. Next relaunch the volumes will be build

docker-compose down -v

Metadata

Release files for pycivil 0.3.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pycivil 0.3.4
File Size Uploaded Provenance Actions
pycivil-0.3.4.tar.gz 8.5 MB Without provenance Details for pycivil-0.3.4.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pycivil 0.3.4
File Interpreter ABI Platform Actions
pycivil-0.3.4-py3-none-any.whl Python 3 none any Details for pycivil-0.3.4-py3-none-any.whl

Total release size: 9.0 MB

Release files / pycivil-0.3.4.tar.gz

Download URL pycivil-0.3.4.tar.gz
Size 8.5 MB
Tags Source
SHA-256 checksum
How to use checksums
74b99b3156d6822fd06603b39d57e649d58dbfce55b3481e2e50523399b23d85
BLAKE2b-256 checksum
How to use checksums
bc1489351171eda42bd030a4a3167bc78e6e29b93722f25d1f9bdea6d7cba721
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / pycivil-0.3.4-py3-none-any.whl

Download URL pycivil-0.3.4-py3-none-any.whl
Size 524.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7d15681aa9bc5ad5bc68bc037b3b0a8f4860c22636f8a3cb0a9822d559f93634
BLAKE2b-256 checksum
How to use checksums
009d7eefe02670242f6460519d5d7d5cfdf2dc3493d93827f4c56d9ff85670e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for pycivil 0.3.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.3.4 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page