civilpy.structural package

Subpackages

Submodules

civilpy.structural.beam_bending module

Beam analysis module for shear force, bending moment, and deflection diagrams.

Sign conventions follow AISC Steel Construction Manual (Table 3-23):
  • Loads: positive = downward (gravity direction)

  • Shear V: positive = left portion of beam has upward resultant (left-face-up)

  • Moment M: positive = sagging (concave up, bottom-fiber tension)

  • Reactions: positive = upward

  • Deflection: negative = downward (shown below zero line)

All units are US customary: lengths in feet (ft), forces in kips, moments in kip·ft. Deflection calculations require E in ksi and I in in⁴; results are in inches.

Overhanging beams (AISC Table 3-23 Cases 24–28) are fully supported. The pinned and rolling supports may be placed anywhere within the beam span — they do not need to coincide with the beam ends. When a support is interior, the beam simply overhangs that support on one or both sides.

Examples

Simply supported beam (supports at ends):

>>> my_beam = Beam(9)
>>> my_beam.pinned_support = 0
>>> my_beam.rolling_support = 9
>>> my_beam.add_loads([PointLoadV(20, 4.5)])
>>> F_Ax, F_Ay, F_By = my_beam.get_reaction_forces()
>>> round(F_Ay, 4), round(F_By, 4)
(10.0, 10.0)

Overhanging beam — AISC Case 26 (P at free overhang end): Beam 0–12 ft, pin at x=0, roller at x=8, 10-kip load at x=12. Expected: R_A = −5 kips (down), R_B = 15 kips (up).

>>> ob = Beam(12)
>>> ob.pinned_support = 0
>>> ob.rolling_support = 8
>>> ob.add_loads([PointLoadV(10, 12)])
>>> F_Ax, F_Ay, F_By = ob.get_reaction_forces()
>>> round(F_Ay, 4), round(F_By, 4)
(-5.0, 15.0)
class civilpy.structural.beam_bending.Beam(span: float = 10)[source]

Bases: object

Represents a one-dimensional beam that can take axial and tangential loads.

Through the method add_loads, a Beam object can accept a list of:

  • PointLoad objects, and/or

  • DistributedLoad objects.

Notes

  • Supports only statically determinate beams with exactly one pinned and one roller support.

  • Supports may be placed at any x-coordinate within the beam span. When a support is interior to the span the beam overhangs that support on one or both sides (AISC Table 3-23 Cases 24–28).

  • Units: lengths in ft, forces in kips, moments in kip·ft. Deflection requires E in ksi and I in in⁴; result is in inches.

__init__(span: float = 10)[source]

Initializes a Beam object of a given length.

Parameters:

span (float or int) – Length of the beam span. Must be positive, and the pinned and rolling supports can only be placed within this span. The default value is 10.

add_loads(loads: list)[source]

Apply an arbitrary list of (point- or distributed) loads to the beam.

Parameters:

loads (list) – An iterable containing DistributedLoad or PointLoad objects to be applied to the Beam object. Note that the load application point (or segment) must be within the Beam span.

Raises:

TypeError – If any of the provided loads is not of a supported type.

get_bending_moment()[source]

Alias for get_moment_function to maintain compatibility with older notebook cells.

get_deflection_function(E_ksi, I_in4)[source]

Returns the symbolic deflection function δ(x) in inches.

Parameters:
  • E_ksi (float) – Modulus of elasticity in ksi (e.g. 29000 for steel).

  • I_in4 (float) – Moment of inertia in in⁴. Can be a Pint quantity — magnitude is used.

get_envelope(loads: list, step_size: float = 0.5)[source]

Calculates the shear and moment envelope for a moving load or set of loads.

Parameters:
  • loads (list) – A list of PointLoadV objects representing the moving load configuration. The coordinates of these loads should be relative to the first load (at 0).

  • step_size (float) – The distance to move the load at each step.

Returns:

  • x_vec (ndarray) – The x-coordinates along the beam.

  • max_shear (ndarray) – Maximum shear at each x.

  • min_shear (ndarray) – Minimum shear at each x.

  • max_moment (ndarray) – Maximum moment at each x.

  • min_moment (ndarray) – Minimum moment at each x.

get_moment_function()[source]
get_reaction_forces()[source]

Calculates the reaction forces at the supports, given the applied loads.

The first and second values correspond to the horizontal and vertical forces of the pinned support. The third one is the vertical force at the rolling support.

Returns:

(F_Ax, F_Ay, F_By) reaction force components for pinned (x,y) and rolling (y) supports respectively.

Return type:

tuple

property length

Length of the beam. Must be positive.

Type:

float or int

property pinned_support

x-coordinate of the beam’s pinned support. Must be within the beam span.

Type:

float or int

plot()[source]

Generates a single figure with 4 plots.

The plots correspond to:
  • a schematic of the loaded beam

  • normal force diagram

  • shear force diagram

  • bending moment diagram

Returns:

figure with the 4 subplots.

Return type:

matplotlib.figure.Figure

plot_all()[source]

Generates a figure with 4 subplots: beam diagram, shear, moment, deflection.

Parameters are obtained from the beam’s existing loads. Deflection is omitted (use plot() or call plot_deflection() separately with E and I values). Returns a figure with shear and moment only alongside the beam diagram.

plot_beam_diagram(ax=None)[source]

Returns a schematic of the beam and all the loads applied on it.

plot_bending_moment(ax=None)[source]

Returns a plot of the bending moment as a function of the x-coordinate.

plot_deflection(E_ksi, I_in4, ax=None)[source]

Plots the deflection diagram in inches.

Parameters:
  • E_ksi (float) – Modulus of elasticity in ksi.

  • I_in4 (float or Pint quantity) – Moment of inertia in in⁴.

plot_envelope(x_vec, max_shear, min_shear, max_moment, min_moment, ax=None)[source]

Plots the shear and moment envelopes.

plot_normal_force(ax=None)[source]

Returns a plot of the normal force as a function of the x-coordinate.

plot_shear_force(ax=None)[source]

Returns a plot of the shear force as a function of the x-coordinate.

property rolling_support

x-coordinate of the beam’s rolling support. Must be within the beam span.

Type:

float or int

class civilpy.structural.beam_bending.CantileverBeam(span: float = 10)[source]

Bases: Beam

A cantilever beam: fixed at x=0, free at x=span.

Loads and coordinates use the same conventions as Beam (kips, ft).

Example

>>> cb = CantileverBeam(10)
>>> cb.add_loads([PointLoadV(-5, 10)])   # 5 kip downward at free end
>>> V, M = cb.get_reaction_forces()
>>> round(float(V), 4), round(float(M), 4)
(5.0, 50.0)
get_deflection_function(E_ksi, I_in4)[source]

Returns the symbolic deflection function δ(x) in inches.

Boundary conditions: δ(0) = 0, δ’(0) = 0 (fixed end).

get_reaction_forces()[source]

Calculates the reaction forces (V_A, M_A) for a cantilever beam.

Returns:

(V_A, M_A) Vertical reaction force (positive upward) and moment (positive counter-clockwise)

at the fixed support (left end).

Return type:

tuple

plot_beam_diagram(ax=None)[source]

Returns a schematic of the cantilever beam.

class civilpy.structural.beam_bending.ContinuousBeam(span: float = 10, intermediate_supports: list = None)[source]

Bases: Beam

A continuous beam with an arbitrary number of intermediate roller supports.

Parameters:
  • span (float) – Length of the beam.

  • intermediate_supports (list of float) – x-coordinates of intermediate roller supports.

__init__(span: float = 10, intermediate_supports: list = None)[source]

Initializes a continuous beam.

Parameters:
  • span (float) – Length of the beam. Defaults to 10.

  • intermediate_supports (list of float, optional) – x-coordinates of intermediate roller supports.

get_reaction_forces()[source]

Returns (F_Ax, F_Ay, F_By) where F_Ay and F_By are the base supports. Intermediate reactions can be retrieved from self._redundant_reactions.

class civilpy.structural.beam_bending.DistributedLoadH(expr, span)[source]

Bases: DistributedLoadH

Distributed horizontal load (kips/ft) over a span interval (ft).

Examples

>>> wind_load = DistributedLoadH("0.5", (0, 20))  # 0.5 kips/ft over full span
class civilpy.structural.beam_bending.DistributedLoadV(expr, span)[source]

Bases: DistributedLoadV

Distributed vertical load (kips/ft) over a span interval (ft). Positive = downward.

Examples

>>> snow_load = DistributedLoadV("2*x+1", (0, 10))  # downward, linearly varying, 0 to 10 ft
class civilpy.structural.beam_bending.FixedFixedBeam(span: float = 10)[source]

Bases: Beam

A fixed-fixed beam: fixed at x=0, fixed at x=span.

Boundary conditions: - x = 0: slope = 0, deflection = 0 - x = span: slope = 0, deflection = 0

get_deflection_function(E_ksi, I_in4)[source]

Returns the symbolic deflection function δ(x) in inches.

Parameters:
  • E_ksi (float) – Modulus of elasticity in ksi (e.g. 29000 for steel).

  • I_in4 (float) – Moment of inertia in in⁴. Can be a Pint quantity — magnitude is used.

get_reaction_forces()[source]

Calculates the reaction forces at the supports, given the applied loads.

The first and second values correspond to the horizontal and vertical forces of the pinned support. The third one is the vertical force at the rolling support.

Returns:

(F_Ax, F_Ay, F_By) reaction force components for pinned (x,y) and rolling (y) supports respectively.

Return type:

tuple

class civilpy.structural.beam_bending.PointLoadH(force, coord)[source]

Bases: PointLoadH

Horizontal point load: (force in kips, coord in ft). Positive = rightward.

Examples

>>> external_force = PointLoadH(10, 9)  # 10 kips to the right at x=9 ft
>>> external_force
PointLoadH(force=10, coord=9)
class civilpy.structural.beam_bending.PointLoadV(force, coord)[source]

Bases: PointLoadV

Vertical point load: (force in kips, coord in ft). Positive = downward.

Examples

>>> external_force = PointLoadV(30, 3)  # 30 kips downwards at x=3 ft
>>> external_force
PointLoadV(force=30, coord=3)
class civilpy.structural.beam_bending.PointTorque(torque, coord)[source]

Bases: PointTorque

Point clockwise torque: (torque in kip·ft, coord in ft).

Examples

>>> applied_moment = PointTorque(30, 4)  # 30 kip·ft clockwise at x=4 ft
class civilpy.structural.beam_bending.ProppedCantileverBeam(span: float = 10)[source]

Bases: Beam

A propped cantilever beam: fixed at x=0, roller at x=span.

Boundary conditions: - x = 0: slope = 0, deflection = 0 - x = span: deflection = 0

Examples

>>> pcb = ProppedCantileverBeam(10)
>>> pcb.add_loads([PointLoadV(5, 5)])  # 5 kip downward at midspan
>>> R_A, V_A, M_A, R_B = pcb.get_reaction_forces()
get_deflection_function(E_ksi, I_in4)[source]

Returns the symbolic deflection function δ(x) in inches. Boundary conditions: δ(0) = 0, δ’(0) = 0.

get_reaction_forces()[source]

Calculates the reaction forces (F_Ax, V_A, M_A, R_B) for a propped cantilever.

Returns:

(F_Ax, V_A, M_A, R_B)
  • F_Ax: Horizontal reaction at fixed end.

  • V_A: Vertical reaction at fixed end (positive upward).

  • M_A: Moment at fixed end (positive counter-clockwise).

  • R_B: Vertical reaction at roller (positive upward).

Return type:

tuple

civilpy.structural.beam_bending.plot_beam_full(beam, E=29000, I=None, title='')[source]

2×2 grid: beam diagram, shear, moment, deflection (if I provided).

Parameters:
  • beam (Beam or CantileverBeam) – A beam object with loads already applied.

  • E (float) – Modulus of elasticity in ksi. Default 29000 (steel).

  • I (float or Pint quantity, optional) – Moment of inertia in in⁴. When omitted the deflection panel is hidden.

  • title (str, optional) – Figure suptitle.

civilpy.structural.midas module

CivilPy Copyright (C) 2019-2026 - Dane Parks

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

exception civilpy.structural.midas.MidasApiError(message, response=None)[source]

Bases: RuntimeError

Raised when the MIDAS API returns an HTTP or application error.

class civilpy.structural.midas.MidasCivil(base_url=None, mapi_key=None, timeout=60, secrets_path=None, analysis_timeout=None, reconnect_retries=None, retry_backoff=None)[source]

Bases: object

A connection to a running MIDAS Civil NX (or Gen NX) instance through the MIDAS API — the same API the MIDAS GH Rhino/Grasshopper extension uses, so anything sent from here lands in the connected session.

Three lines:

from civilpy.structural.midas import MidasCivil

midas = MidasCivil()              # key from ~/secrets.json MIDAS_API_KEY
nodes = midas.nodes()             # GET  /db/NODE
midas.put_nodes({"1": {"X": 0, "Y": 0, "Z": 0}})   # PUT /db/NODE

Coverage:

Unlike the module-level functions above (kept for backwards compatibility), this class holds no global state, supports custom base URLs (regional/local API servers), applies request timeouts, and raises MidasApiError instead of printing.

ANALYSIS_TIMEOUT = 600

Read timeout (s) for long operations — analysis, open, result tables — on large finite-element models (a 10k-element solve exceeds the default). Override per instance with analysis_timeout= for very large models.

DEFAULT_BASE_URL = 'https://moa-engineers.midasit.com:443/civil'
RECONNECT_RETRIES = 2

Default retry policy for transport (connection) failures. A dropped Civil NX session is the failure that clusters mid-batch, so one or two backoff retries recover most blips without masking a real outage.

RETRY_BACKOFF = 0.5
TRIAGE_TABLES = ('NODE', 'ELEM', 'CONS', 'STLD', 'MVLD', 'LCOM-GEN', 'SECT')

Tables read to judge whether a model can be analyzed / rated.

analyze()[source]

POST /doc/ANAL — run the analysis on the current model (long timeout; a large finite-element solve exceeds the default request timeout).

beam_forces(elem_ids, load_case_names, components=('Elem', 'Load', 'Part', 'Axial', 'Shear-y', 'Shear-z', 'Moment-y', 'Moment-z'), unit=None, styles=None, validate=True)[source]

POST /post/TABLE BEAMFORCE in the request shape confirmed against live Civil NX: integer element ids in NODE_ELEMS["KEYS"] plus UNIT, STYLES, and PARTS — omitting any of those returns the "second query is wrong" HTTP 400. elem_ids are integer beam element ids; load_case_names use the result suffixes ("…(ST)" static, "…(MV:all)" moving). Returns the raw /post/TABLE JSON (flatten with civilpy...()/brr.rating.parse_result_table).

When validate is set (default), the returned table is checked for duplicate column headers via duplicate_columns() and a warning is issued if any are found — guarding against the component aliasing that produced identical Axial / Shear-z envelopes on some models.

can_analyze()[source]

True when the current model has enough defined to run an analysis.

capability(summary=None)[source]

(can_analyze, can_rate_live_load, note) for the current model.

A model needs geometry, supports, and at least one load case to solve; live-load rating additionally needs a moving-load case. Pass a cached summarize() result as summary to avoid a second round-trip.

delete_db(table, ids=None)[source]

DELETE /db/{table} — remove ids (everything when ids is None).

static duplicate_columns(response)[source]

Column headers that appear more than once in a /post/TABLE response. A non-empty result flags a component→column aliasing problem (e.g. Axial and Shear-z resolving to the same field, seen on some BEAMFORCE result shapes) — the values under aliased headers are unreliable and should be re-queried.

elements()[source]

All elements — {"ELEM": {id: {TYPE, MATL, SECT, NODE, ...}}}.

export_file(path)[source]

POST /doc/EXPORT — export the model to a file path.

get_db(table)[source]

GET /db/{table} — full contents of any model database table.

groups()[source]

Structure groups — {"GRUP": {...}}.

import_file(path)[source]

POST /doc/IMPORT — import a file (e.g. .mct) into the model.

load_combinations()[source]

General load combinations — {"LCOM-GEN": {...}}.

materials()[source]
new()[source]

POST /doc/NEW — start a blank model (discards unsaved work).

nodes()[source]

All nodes — {"NODE": {id: {X, Y, Z}}}.

open(path)[source]

POST /doc/OPEN — open an .mcb model file on the Civil NX machine (long timeout; large files take time to load).

ping()[source]

True when Civil NX is reachable and the key is accepted.

post_db(table, assign)[source]

POST /db/{table} — create rows (errors when an id exists).

put_db(table, assign)[source]

PUT /db/{table} — create/update rows. assign maps id → fields.

put_elements(assign)[source]

Create/update elements: {id: {"TYPE": "BEAM", "MATL":, "SECT":, "NODE": [i, j]}}.

put_materials(assign)[source]

Create/update materials: {id: {"TYPE": "STEEL"|"CONC"|"USER", "NAME":, ...}}.

put_nodes(assign)[source]

Create/update nodes: {id: {"X":, "Y":, "Z":}}.

put_sections(assign)[source]
put_static_loads(assign)[source]
put_supports(assign)[source]

Create/update supports: {node_id: {"ITEMS": [{"ID": 1, "CONSTRAINT": "1110000"}]}}.

request(method, command, body=None, timeout=None, retries=None)[source]

Send one request to the MIDAS API and return the parsed JSON.

command is the endpoint path, e.g. "/db/NODE" or "/doc/ANAL". timeout overrides the instance default for one call (used by analyze(), open(), and result_table() on large models). retries overrides reconnect_retries for one call (0 disables the backoff retry).

Error handling distinguishes three failure modes so a batch caller can react sensibly:

  • MidasConnectionError — the API was unreachable (dropped session); retried with backoff first, then raised.

  • MidasTimeoutError — the request outran its read timeout (a large solve); raised immediately, not retried.

  • MidasLicenseError — the license tier rejected the model (HTTP 400, e.g. too many construction stages).

All three subclass MidasApiError, as does a generic HTTP or {"error": ...} payload failure.

result_table(table_name, table_type=None, components=None, node_elems=None, load_case_names=None, parts=None, unit=None, styles=None, timeout=None)[source]

POST /post/TABLE — extract an analysis results table.

Example:

midas.result_table(
    "BeamForce", table_type="BEAMFORCE",
    components=["Elem", "Load", "Moment-y"],
    node_elems={"KEYS": ["1to20"]},
    load_case_names=["DL(CB)"],
)

For element-force tables, prefer beam_forces(), which sends the request shape confirmed to work against live Civil NX. timeout overrides the request timeout for large result sets.

save()[source]

POST /doc/SAVE — save the current model.

save_as(path)[source]

POST /doc/SAVEAS — save the model to a new path.

sections()[source]
set_units(force='KIPS', dist='FT', heat='BTU', temper='F')[source]

Set the model unit system (defaults: kips / feet).

static_loads()[source]

Static load cases — {"STLD": {...}}.

summarize()[source]

Counts of the current model’s structural ingredients.

One round-trip per TRIAGE_TABLES entry; returns a dict with nodes, elems, elem_types, sect_types, supports, static_loads, moving_loads and combinations. Feed it to capability() to decide whether a model is worth analyzing before spending a long solve on it.

supports()[source]

Nodal boundary conditions — {"CONS": {...}}.

units()[source]
exception civilpy.structural.midas.MidasConnectionError(message, response=None)[source]

Bases: MidasApiError

The MIDAS API could not be reached — Civil NX is closed, the session dropped, or the network blipped. Transport-level and typically transient, so MidasCivil.request() retries it before giving up. Subclasses MidasApiError so existing except MidasApiError paths still catch it.

exception civilpy.structural.midas.MidasLicenseError(message, response=None)[source]

Bases: MidasApiError

The connected Civil NX license tier rejected the operation — e.g. opening a model with more construction stages than a Plus license allows. Not retryable: skip the model rather than re-sending.

exception civilpy.structural.midas.MidasTimeoutError(message, response=None)[source]

Bases: MidasConnectionError

A request outran its read timeout — usually a large finite-element solve or model open that needs a longer analysis_timeout rather than a retry (re-issuing it just doubles the wait).

civilpy.structural.midas.column_values(rows, column, cast=<class 'float'>)[source]

Pull one column from parsed rows, dropping blanks and un-castable cells.

civilpy.structural.midas.convert_node_units(from_units: str = None, to_units: str = None, in_place: bool = True) None[source]

Converts the existing nodes from one unit system to another, for instance if you import a dxf file that was drawn in feet, but your midas units were set to inches, :param from_units: :type from_units: str = The units the drawing is currently in ie ‘inches’ will grab them from midas if None :param to_units: :type to_units: str = The desired units to convert the drawing to, if None, will not run :param in_place: :type in_place: bool = Whether you want the function to push the data to the midas, or just return the updated values

Returns:

  • None - Converts the units in the open model to the desired units

  • nodes - if in_place is False

civilpy.structural.midas.envelope(rows, column, *, absolute=True)[source]

Largest value of column across rows (by magnitude unless told not to).

Returns 0.0 for no usable values — the controlling demand of an empty set is nothing.

civilpy.structural.midas.get_api_key(secrets_path=None)[source]

Retrieve the API key from the secrets.json file in the civilpy directory

Parameters:

secrets_path (the path where the secrets.json file is located)

Return type:

None - Sets a global variable for the module

civilpy.structural.midas.get_elements()[source]

Retrieve all elements from the active MIDAS Civil model.

Returns:

MIDAS API response containing element definitions keyed by element ID under "ELEM".

Return type:

dict

civilpy.structural.midas.get_elements_by_material_index(material_index: int = None)[source]

Get the elements of a model by specifying a material index value :param material_index: :type material_index: int = Index of the material you want to sort by in str format

Returns:

return_dict

Return type:

dict = The elements of a model that match the material specified

civilpy.structural.midas.get_elements_by_section_index(section_index: int = None)[source]

Returns a dictionary containing all elements of the midas model that match the section index

Parameters:

section_index (int = The index value of the section you want to search the elements for)

Returns:

return_dict – specified

Return type:

A dictionary containing all elements of the midas model that match the section

civilpy.structural.midas.get_materials()[source]

Retrieve all material definitions from the active MIDAS Civil model.

Returns:

MIDAS API response containing material properties keyed by material ID under "MATL".

Return type:

dict

civilpy.structural.midas.get_nodes()[source]

Retrieve all nodes from the active MIDAS Civil model.

Returns:

MIDAS API response containing node coordinates keyed by node ID under "NODE".

Return type:

dict

civilpy.structural.midas.get_sections()[source]

Retrieve all section definitions from the active MIDAS Civil model.

Returns:

MIDAS API response containing section properties keyed by section ID under "SECT".

Return type:

dict

civilpy.structural.midas.get_static_loads()[source]

Retrieve all static load case definitions from the active MIDAS Civil model.

Returns:

MIDAS API response containing static load cases keyed by load case ID under "STLD".

Return type:

dict

civilpy.structural.midas.get_supports()[source]

Retrieve all support (constraint) definitions from the active MIDAS Civil model.

Returns:

MIDAS API response containing nodal boundary conditions keyed by node ID under "CONS".

Return type:

dict

civilpy.structural.midas.get_units()[source]

Retrieve the current unit system settings from the active MIDAS Civil model.

Returns:

MIDAS API response containing force, length, heat, and temperature unit settings.

Return type:

dict

civilpy.structural.midas.midas_api(method, command, body=None)[source]

Make a request to the MIDAS API and return the response as a JSON object

Parameters:
  • method (str - 'GET', 'PUT', 'POST' or 'DELETE')

  • command (str - The particular method within the API you want) – to target, such as ‘db/elem’ for the elements you want to access

  • body (dict - The body of the request you want to send to the api, usually contains) – the values you want MIDAS to update with

Return type:

response.json - the response from the MIDAS API

civilpy.structural.midas.parse_result_table(response, table_name=None)[source]

Flatten a MIDAS POST /post/TABLE response into a list of row dicts.

MIDAS returns {<table>: {"HEAD": [col, ...], "DATA": [[val, ...], ...]}}. When table_name is omitted the first block that carries HEAD/DATA is used, so parse_result_table(resp) works without knowing the key. Cell values are left as MIDAS sent them (usually strings); cast with column_values().

civilpy.structural.midas.setup_output_directory(output_directory: str = '/builds/Dane/civilpy')[source]

Create an output subdirectory inside output_directory if absent.

Parameters:

output_directory (str) – Parent directory path. Defaults to the current working directory.

Note

Prints a status message indicating whether the directory was found or created.

civilpy.structural.section_properties module

CivilPy Copyright (C) 2019-2026 - Dane Parks

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

class civilpy.structural.section_properties.CrossSection(label, dimensions=None, shape=None, y=None, axis='strong')[source]

Bases: object

A class for defining a built-up section by repeatedly adding plate dimensions.

This class allows users to define a built-up cross-section by calling the instance and passing in the dimensions of each plate making up the section. The plates are assumed to be entered in order from the bottom to the top, and all shapes are assumed to be rectangles that do not overlap.

labels

A list of labels identifying each plate in the cross-section.

Type:

list of str

dimensions

A list of tuples (width, height) for each plate.

Type:

list

ys

The centroids of each plate along the y-axis.

Type:

list of float

areas

The areas of each plate.

Type:

list of float

moments

The first moments of area for each plate.

Type:

list of float

I_ys

The second moments of area of each plate about its own centroid.

Type:

list of float

I_gs

The second moments of area of each plate about the global centroid.

Type:

list of float

area

The total area of the cross-section.

Type:

float

moment

The first moment of area of the cross-section.

Type:

float

I_y

The total second moment of area about the local centroid.

Type:

float

I_g

The total second moment of area about the global centroid.

Type:

float

I_n

The net inertia value, adjusted for global centroid.

Type:

int

n

The location of the neutral axis.

Type:

float

Parameters:
  • label (str) – A label to identify the plate in the cross-section (e.g., “A”, “B”).

  • dimensions (tuple) – A tuple representing the plate dimensions (width, height).

  • shape (str, optional) – The shape of the plate (default is None for rectangles).

Returns:

An instance of the CrossSection object.

Return type:

CrossSection

__init__(label, dimensions=None, shape=None, y=None, axis='strong')[source]

Initialise a built-up cross-section with its first plate or shape.

Parameters:
  • label (str) – Identifier for this plate (e.g. "bottom flange").

  • dimensions (tuple[float, float], optional) – (width, height) of a rectangular plate in consistent units. Required when shape is None.

  • shape (W, optional) – A steel wide-flange shape object from civilpy.structural.steel. When supplied, dimensions is derived from the shape’s flange width and depth.

  • y (float, optional) – Distance from the datum to the centroid of this plate. Defaults to half the plate height (i.e. the plate sits with its bottom at y = 0).

  • axis (str) – 'strong' (default) to use I_x and depth, or 'weak' to use I_y and flange width for rolled shapes.

append_value(dimensions=None, y=None, shape=None, axis=None)[source]

Add a plate or rolled shape to the cross-section and update properties.

Four dispatch paths are supported:

  1. Rectangular plate stacked on top (y=None, shape=None): plate sits directly above the current top of section.

  2. Rolled shape at explicit y (shape provided, y provided): uses I_x or I_y depending on axis.

  3. Rolled shape stacked on top (shape provided, y=None): depth/flange width derived from shape; stacked on current top.

  4. Rectangular plate at explicit y (shape=None, y provided): plate placed with centroid at y.

Parameters:
  • dimensions (tuple[float, float], optional) – (width, height) of a rectangular plate.

  • y (float, optional) – Centroid position from datum.

  • shape (W, optional) – Rolled steel shape object.

  • axis (str, optional) – 'strong' or 'weak' for rolled shapes.

Note

_calc_gen_properties() is called automatically after each plate is added.

check_negative_y_values()[source]

Check whether any plate centroid lies below the datum (y < 0).

Returns:

True if at least one y-coordinate key in self.plate_dims is negative, False otherwise.

Return type:

bool

civilpy.structural.section_properties.get_bar_section_properties(d)[source]

Return (I, S, r) for a solid circular bar about its centroidal axis.

Parameters:

d – Diameter of the bar.

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.section_properties.get_hollow_oval_section_properties(a, b, c, d)[source]

Return (I, S, r) for a hollow ellipse (elliptical tube) about its centroidal axis.

Parameters:
  • a – Outer semi-axis height.

  • b – Outer semi-axis width.

  • c – Inner semi-axis height.

  • d – Inner semi-axis width.

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.section_properties.get_oval_section_properties(b, a)[source]

Return (I, S, r) for a solid ellipse about its centroidal axis.

Parameters:
  • b – Semi-axis width (horizontal half-width).

  • a – Semi-axis height (vertical half-height).

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.section_properties.get_pipe_section_properties(D, d)[source]

Return (I, S, r) for a hollow circular pipe about its centroidal axis.

Parameters:
  • D – Outer diameter.

  • d – Inner diameter.

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.section_properties.get_rectangular_section_properties(b, d)[source]

Return (I, S, r) for a rectangle about its neutral axis (centroid).

Parameters:
  • b – Width of the rectangle.

  • d – Height of the rectangle.

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.section_properties.get_rectangular_section_properties_baseline(b, d)[source]

Return (I, S, r) for a rectangle about its baseline (bottom edge).

Parameters:
  • b – Width of the rectangle.

  • d – Height of the rectangle.

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.section_properties.get_triangular_section_properties(b, d)[source]

Return (I, S, r) for a triangle about its neutral axis.

Parameters:
  • b – Base width of the triangle.

  • d – Height of the triangle.

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.section_properties.get_triangular_section_properties_baseline(b, d)[source]

Return (I, S, r) for a triangle about its baseline.

Parameters:
  • b – Base width of the triangle.

  • d – Height of the triangle.

Returns:

(I, S, r) — moment of inertia, section modulus, radius of gyration.

Return type:

tuple

civilpy.structural.steel module

class civilpy.structural.steel.BoltMaterial(designation: str, f_y: float, f_u: float, f_v: float = 48)[source]

Bases: object

Structural bolt material specification.

Parameters:
  • designation (str) – ASTM bolt designation, e.g. 'A325', 'A490', 'F3125GrA325'.

  • f_y (float) – Proof load / yield strength, ksi.

  • f_u (float) – Minimum tensile strength, ksi.

  • f_v (float) – Nominal shear strength (ASD allowable or LRFD nominal), ksi. Defaults to 48 (A325 threads excluded from shear plane).

Example

>>> b = BoltMaterial('A325', f_y=92, f_u=120, f_v=48)
>>> b.f_u
120 kip/inch²
class civilpy.structural.steel.C(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel C s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = C("C15X50")
>>> t.weight
50.0 pound/foot
class civilpy.structural.steel.HP(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel M s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = HP("HP18X204")
>>> t.weight
204.0 pound/foot
class civilpy.structural.steel.HSS(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel HSS sections. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = HSS("HSS20X20X.500")
>>> t.weight
130.52 pound/foot
class civilpy.structural.steel.HistoricSteelSection(label, designation=None)[source]

Bases: object

Main Steel Section Class, the goal is to make the attributes of various steel sections easily accessible in various python scripts.

__init__(label, designation=None)[source]

Initialize a historic steel section from the AISC historic shapes database.

Parameters:
  • label (str) – Shape label, e.g. "18WF96" or "WF36X150". Case and spaces are normalized automatically.

  • designation (str, optional) – AISC historic edition designation used to disambiguate shapes that were published under multiple editions. Example: '18WF_B18b'. If None, returns the first match.

clean_user_input(user_input)[source]

Eliminates value not found errors by removing lower case letters and spaces

>>> t = SteelSection("W 44X335")
>>> print(t.clean_user_input('W 44X335'))
W44X335
>>> print(t.clean_user_input('w40x294'))
W40X294
>>> t.id
'W40X294'
Returns:

cleaned input

get_historical_shape(designation=None)[source]

Searches AISC Steel database table for member label passed to it, returns values from table if it finds a match, or prints an error if it doesn’t

>>> t = SteelSection("W36X150")
>>> t.aisc_value['Type'].values[0]
'W'
>>> t = SteelSection("2L8X4X5/8LLBB")
>>> t.aisc_value['W'].values[0]
48.4
Parameters:

self

Returns:

dataframe of raw values from AISC Shape Table

class civilpy.structural.steel.L(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel L s. Splitting values into multiple classes allows dropping of empty vain the database.

>>> t = L("L12x12x1-3/8")
>>> t.weight
105.0 pound/foot
class civilpy.structural.steel.M(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel M s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = M("M10X9")
>>> t.weight
9.0 pound/foot
class civilpy.structural.steel.MC(label)[source]

Bases: C

Class to provide more specific attributes and functions related to designing with steel MC s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = MC("MC18X58")
>>> t.weight
58.0 pound/foot
class civilpy.structural.steel.MT(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel WT s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = MT("MT5x4")
>>> t.weight
4.0 pound/foot
class civilpy.structural.steel.Pipe(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel Pipe Sections. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = Pipe("Pipe10SCH140")
>>> t.weight
104.0 pound/foot
class civilpy.structural.steel.Rebar(bar_number: int, grade: int = 60)[source]

Bases: object

Standard deformed reinforcing bar per ASTM A615 / A706.

Provides nominal diameter, cross-sectional area, and unit weight for standard US rebar sizes #2 through #18. All dimensional properties carry Pint units.

Parameters:
  • bar_number (int) – Standard bar designator (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, or 18).

  • grade (int) – Yield strength grade in ksi. Common values are 40, 60, 75, or 80 per ASTM A615; 60 or 80 per ASTM A706. Defaults to 60.

Raises:

ValueError – If bar_number is not a standard ASTM size.

Example

>>> bar = Rebar(5)
>>> float(bar.area.magnitude)
0.31
>>> float(bar.weight.magnitude)
1.043
>>> bar.diameter
0.625 inch
>>> bar = Rebar(8, grade=60)
>>> bar.bar_number
8
class civilpy.structural.steel.S(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel M s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = S("S24X121")
>>> t.weight
121.0 pound/foot
class civilpy.structural.steel.ST(label)[source]

Bases: WT

Class to provide more specific attributes and functions related to designing with steel ST s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = ST("ST10x48")
>>> t.weight
48.0 pound/foot
class civilpy.structural.steel.SteelMaterial(designation: str, f_y: float, f_u: float, e_s: float = 29000)[source]

Bases: object

Structural steel material specification.

Stores yield strength, tensile strength, and modulus of elasticity for common ASTM structural steel grades. Properties carry Pint units.

Parameters:
  • designation (str) – ASTM material designation, e.g. 'A36', 'A572Gr50', 'A992'.

  • f_y (float) – Minimum yield strength, ksi.

  • f_u (float) – Minimum tensile strength, ksi.

  • e_s (float) – Modulus of elasticity, ksi. Defaults to 29000.

Example

>>> m = SteelMaterial('A36', f_y=36, f_u=58)
>>> m.f_y
36 kip/inch²
class civilpy.structural.steel.SteelSection(label)[source]

Bases: object

Main Steel Section Class, the goal is to make the attributes of various steel sections easily accessible in various python scripts.

__init__(label)[source]

Initialize a SteelSection from an AISC shape label.

Looks up the label in the AISC Steel Construction Manual shape table and populates standard section properties with Pint units attached.

Parameters:

label (str) – AISC standard nomenclature, e.g. "W36X150", "w40x294", "2L8X4X5/8LLBB". Case and spaces are normalized automatically.

Raises:

KeyError – If the label is not found in the AISC shape database.

Example

>>> s = SteelSection("W36X150")
>>> float(s.I_x.magnitude)
12300.0
clean_user_input(user_input)[source]

Eliminates value not found errors by removing lower case letters and spaces

>>> t = SteelSection("W 44X335")
>>> print(t.clean_user_input('W 44X335'))
W44X335
>>> print(t.clean_user_input('w40x294'))
W40X294
>>> t.id
'W40X294'
Returns:

cleaned input

get_shape()[source]

Searches AISC Steel database table for member label passed to it, returns values from table if it finds a match, or prints an error if it doesn’t

>>> t = SteelSection("W36X150")
>>> t.aisc_value['Type'].values[0]
'W'
>>> t = SteelSection("2L8X4X5/8LLBB")
>>> t.aisc_value['W'].values[0]
48.4
Parameters:

self

Returns:

dataframe of raw values from AISC Shape Table

class civilpy.structural.steel.TwoL(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel 2L s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = TwoL("2L10X10X1-1/4")
>>> t.weight
48.0 pound/foot
class civilpy.structural.steel.W(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel W s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = W("W36X150")
>>> t.weight
150.0 pound/foot
class civilpy.structural.steel.WF(label, designation=None)[source]

Bases: HistoricSteelSection

Historic wide-flange section (pre-AISC W-shape standardization).

Used for evaluating existing bridges and structures built with pre-1970 steel sections. Extends HistoricSteelSection with dimensional attributes (depth, flange width, web thickness, etc.) from the AISC historic shapes table.

Example

>>> t = WF("18WF96", '18WF_B18b')
>>> t.weight
96.0 force_pound/foot
__init__(label, designation=None)[source]

Initialize a historic WF section with full dimensional properties.

Parameters:
  • label (str) – Historic shape label, e.g. "18WF96".

  • designation (str, optional) – AISC edition designation to disambiguate shapes with the same label across multiple editions. Example: '18WF_B18b'.

class civilpy.structural.steel.WT(label)[source]

Bases: SteelSection

Class to provide more specific attributes and functions related to designing with steel WT s. Splitting values into multiple classes allows dropping of empty values in the database.

>>> t = WT("WT22x145")
>>> t.weight
145.0 pound/foot
civilpy.structural.steel.conv_frac_str(fraction_string: str) float[source]
civilpy.structural.steel.get_bolt_weights(length: float, diameter: float, no_of_washers: int) float[source]

Function to get the bolt weights from the A325_bolt_weights dictionary and calculate the weight per bolt if it’s not contained in the table.

Original table from: https://www.portlandbolt.com/print/?table=7587

The A325_bolt_weights dictionary reports the weight indexed by bolt length and diameter, and reports the value in lbs/100 bolts. This function simplifies that by reducing the value to that of a single bolt.

If bolt weights are not contained in the dictionary, the function will utilize the following formula to calculate the weight per bolt, if no_of_washers is greater than 0, it will include the weight of the washers in the calculation with the following values:

Per inch Adder (dia):

0.5: 5.5 0.625: 8.6 0.75: 12.4 0.875: 16.9 1.0: 22.1 1.125: 28 1.25: 34.4 1.375: 42.5 1.5: 49.7

F436 Round Washers

0.5: 2.1 0.625: 3.6 0.75: 4.8 0.875: 7 1.0: 9.4 1.125: 11.3 1.25: 13.8 1.375: 16.8 1.5: 20

Weight in table includes the weight of nuts.

Parameters:
Returns:

Weight

Return type:

float - the weight of the individual bolt

Module contents

CivilPy Copyright (C) 2019 - Dane Parks

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.