Skip to main content

简体中文 | English

pyosis

Python client library for OSIS Bridge & Tunnel Analysis Platform (developed by CCCC Highway Consultants Co., Ltd.).

pyosis provides an object-oriented Python API for automating the creation of bridge/tunnel finite element models, executing analysis solvers, and extracting post-processing results.

Installation

Due to naming conflicts on PyPI, please install using:

pip install osis-python

If your mirror hasn't synced yet, use:

pip install osis-python -i https://pypi.org/simple

Requirements

  • OSIS >= 5.1 (short-form command names like N/Ele/Sec are accepted by both the converter and runtime)
  • Python >= 3.8
  • Solver-only mode additionally requires the solver distribution that ships PySolver.dll (e.g. D:\OSIS_Solver\Rbin64).

OSIS 5.1 HTTP server bug workaround: the /OSIS_Run command-stream splitter does not strip // line comments, so a comment line and the command that follows it are merged into one bad command. The pyosis .out converter already strips comments before sending; if you ever build a raw .out payload yourself, pre-process the file or use osis_run() through the generated main.py.

Quick Start

OSISEngine is the core facade class of pyosis, integrating all module managers and providing a unified project-level entry point:

from pyosis.core.engine import OSISEngine

engine = OSISEngine()

# Clear project
engine.clear()

# Set global parameters
engine.control.set_gravity_acceleration(9.8066)
engine.control.set_calc_tendon(True)
engine.control.set_calc_creep(True)

# Create sections
sec = engine.section.create_circle(no=1, name="CircleSection", d=0.5)

# Create materials
mat = engine.material.create_conc(no=1, name="C30Concrete", code="JTG3362_2018", grade="C30")

# Create nodes
n1 = engine.node.create(no=1, x=0, y=0, z=0)
n2 = engine.node.create(no=2, x=15, y=0, z=0)

# Create elements
elem = engine.element.create_beam3d(
    no=1, node1=n1.no, node2=n2.no, mat=mat.no, sec1=sec.no, sec2=sec.no
)

# Create boundaries
bd = engine.boundary.create_general(no=1, x=1, y=1, z=1, rx=1, ry=1, rz=1, rw=1)
bd.assign("a", [n1.no])

# Create load case and add loads
lc = engine.load.create("Self-weight", load_case_type="D")
lc.create_gravity()

# Solve
engine.solve()

2. Engine Convenience Methods

OSISEngine provides project-level convenience methods:

# Project management
engine.new_project()           # Create new project
engine.save_project()          # Save current project
engine.open_project(path)      # Open existing project

# Model information
summary = engine.model_summary()  # Returns dict with all manager counts

# Import/Export
engine.export_apdl(path)       # Export to APDL format
engine.import_apdl(path)       # Import from APDL format

# Result output for calculation book
engine.output_result_for_calc_book()

# Matrix output
engine.matrix("matrix_1", [[1, 2],[3, 4]])

3. Using Managers Directly

If you don't need the convenience methods of Engine, you can also import individual managers directly:

from pyosis.material import material_manager
from pyosis.node import node_manager

mat = material_manager.create_conc(no=1, name="C30", code="JTG3362_2018", grade="C30")
node = node_manager.create(no=None, x=0, y=0, z=0)

4. Using OSISSolver — Start the Solver Directly (Solver-Only Mode)

By default, OSISEngine() connects to an already-running OSIS GUI process. If you want to drive the solver without opening the GUI (e.g. for headless batch runs, CI, or server-side automation), use OSISSolver to load the solver DLL directly via ctypes and launch its HTTP server:

from pyosis.core.solver import OSISSolver
from pyosis.core.engine import OSISEngine

# Load <install>/PySolver.dll and start the HTTP server (default port 18080)
solver = OSISSolver(osis_install_path=r"D:\OSIS_Solver\Rbin64")
engine = OSISEngine.from_solver(solver)

# Create a project (type 101 = bridge analysis), then build the model as usual
engine.project.create(101, r"D:\work\my_bridge\my_bridge.sis")
engine.control.set_gravity_acceleration(9.8066)
# ... build sections / materials / nodes / elements ...
engine.solve()

Notes on solver-only mode:

  • osis_install_path must be the directory containing PySolver.dll (and its dependency DLLs).
  • The solver needs a project to exist before model commands run: call engine.project.create() / open() first.
  • Crash minidumps are written to <install>\Error\dmp\ (created on startup).

Core Architecture

Manager System

pyosis adopts a Manager pattern to organize code. Each module corresponds to a Manager:

Manager Attribute Description
MaterialManager engine.material Materials (concrete, steel, prestressed, rebar, etc.)
SectionManager engine.section Sections (box girder, T-girder, hollow slab, steel box, etc.)
NodeManager engine.node Nodes
ElementManager engine.element Elements (beam, truss, spring, cable, shell)
BoundaryManager engine.boundary Boundaries (general support, master-slave, elastic support, etc.)
GeometryManager engine.geometry Geometric entities (splines, spatial curves)
PropertyManager engine.prop Properties (coordinate systems, creep/shrinkage, damping, P-U curves, element thickness assignments)
ThicknessManager engine.thickness Shell thickness properties
LoadCaseManager engine.load Load cases
StageManager engine.stage Construction stages
TendonManager engine.tendon Tendons (properties + shapes)
LiveManager engine.live Live loads (grades + lanes + cases)
SettlementManager engine.settlement Settlement analysis
StabilityManager engine.stability Stability analysis
DynamicManager engine.dynamic Dynamic analysis
PostManager engine.post Post-processing (load combinations, design checks)
ResultManager engine.result Result export (load case / envelope / check results)
ControlManager engine.control Global control parameters
ProjectManager engine.project Project operations
DisplayManager engine.display Display control (show/hide boundaries, loads, tendons; view orientation; display switches)

Sub-Managers

Some managers contain sub-managers, accessed via attributes:

# Element groups (create + add elements in one call)
engine.element.group.create("MainGirderElements", "c")            # create empty group
engine.element.group.create("MainGirderElements", "a", "1to3")    # add elements 1-3

# Boundary groups
engine.boundary.group.create("AbutmentBoundaries", "c")
engine.boundary.group.create("AbutmentBoundaries", "a", "1to2")

# Various boundary types
engine.boundary.create_general(no=1, x=1, y=1, z=1, rx=1, ry=1, rz=1, rw=1)           # General support
engine.boundary.create_master_slave(no=1, node=1, dx=1, dy=1, dz=1, rx=0, ry=1, rz=1, coincident=1)  # Master-slave
engine.boundary.create_rigid(no=1, node_i=1)                                               # Rigid link
engine.boundary.create_elstcspt(no=1, coor="", x=0, dx=1e9, y=0, dy=1e9, z=0, dz=1e9)     # Elastic support

# Tendons
prop = engine.tendon.prop.create_in(
    name="15-10", mat=3, code="GBT5224_2014",
    diameter=15.2, num=10, pipe=0.09,
)
shape = engine.tendon.shape.create_arc3d(
    name="N1", n_num=2, prop="15-10",
    element_group="MainGirderElements", curve_name="curve1"
)

# Live loads
grade = engine.live.grade.create(name="HighwayClassI", code="JTGD60_2015", type="HIGHWAY_I")
lane = engine.live.lane.create(name="Lane1", type="VE")
case = engine.live.case.create(name="LiveLoadCase 1", code="JTGD60_2015")

Display Control

# Show/hide boundaries, loads and tendons
engine.display.disp_ctrl("bc", "all", "all", 1)          # Show all boundaries
engine.display.disp_ctrl("lg", "nforce", "all", 0)       # Hide all concentrated forces
engine.display.disp_ctrl("td", "all", ["T1", "T2"], 1)   # Show specific tendons

# View orientation
engine.display.set_view("top")          # standard / top / right / front

# Display switch
engine.display.set_plsm(1)              # 0 = off, 1 = on

Property & Thickness Management

# Coordinate systems (三点定义)
engine.prop.coord.create_three_point(
    no=1, p1x=0, p1y=0, p1z=0,
    p2x=1, p2y=0, p2z=0,
    p3x=0, p3y=1, p3z=0,
)

# Creep and shrinkage(no, name, code, fcuk, avg_humidity,
#                     component_approximate_size, type_coeff, birth_by_shrinking, fly_ash_ratio)
engine.prop.creep_shrink.create(no=1, name="Creep1", avg_humidity=70.0,
                                type_coeff=5.0, birth_by_shrinking=3)

# Damping (Rayleigh 自定义系数)
engine.prop.damping.create_rayleigh_custom(name="Damping1", alpha=0.05, beta=0.005)

# P-U curve (no, name, curve_type, num, *values)
#   curve_type: 0 = force, 1 = moment
engine.prop.pu_curve.create(1, "PU1", 1, 3, 0, 0.01, 1000, 0.02, 1500)

# Element thickness assignment (thickness, op, *elems)
engine.prop.assign_component_thickness(0.3, "a", 1)

# Shell thickness (no, in_plane, out_plane)
engine.thickness.create(no=1, in_plane=0.3, out_plane=0.3)

Geometry Queries

The GeometryManager supports querying geometric entities:

# Get all splines
splines = engine.geometry.all()

# Get a specific spline
spline = engine.geometry.get("curve1")

# Filter by type (General / Natural / Arc3D / Arc2D)
arcs = [s for s in engine.geometry.all() if s.spline_type.name == "Arc3D"]

Data Class Objects

Create and query operations return data class objects (dataclass) instead of raw dictionaries:

elem = engine.element.get(1)
print(elem.no)          # ID
print(elem.node_vec)    # Node list
print(elem.mat)         # Material ID

# Objects support operations (operations下沉 to object)
lc = engine.load.get("Self-weight")
lc.create_gravity()
lc.create_nforce(1, fx=1000)

Explicit Numbering

Some create_* functions support explicit numbering via the no parameter. If not specified, the number is automatically assigned:

# Auto-assigned number
sec = engine.section.create_circle(name="Section1", d=0.5)

# Explicit number
sec = engine.section.create_circle(name="Section1", d=0.5, no=100)

Result Export

After solving, you can export various analysis results using engine.result. All export methods return pandas DataFrames:

# Export load case results (element forces)
df = engine.result.loadcase("Self-weight", "LCEF")

# Export envelope results (element forces)
df = engine.result.env("BasicCombinationEnvelope", "EnvEF")

# Export design check results
df = engine.result.check(
    "混凝土", "正截面抗弯验算", "基本组合"
)

# Batch export all check results from Check folder
results = engine.result.check_all()
for name, df in results.items():
    print(f"{name}: {len(df)} rows")

Supported result types:

  • Load case: LCEF (element force), LCED (element displacement), LCND (node displacement), LCBF (boundary reaction), LCTL (tendon loss), LCS (element stress)
  • Envelope: EnvBF (boundary reaction), EnvEF (element force), EnvES (element strain), EnvS (element stress), EnvND (node displacement)

Requires pandas to be installed: python -m install pandas

Complete Example

from pyosis.core.engine import OSISEngine

engine = OSISEngine()
engine.clear()

# Control parameters
engine.control.set_gravity_acceleration(9.8066)
engine.control.set_calc_tendon(True)
engine.control.set_calc_concurrent_force(True)
engine.control.set_calc_shrink(True)
engine.control.set_calc_creep(True)
engine.control.set_calc_shear(True)
engine.control.set_calc_relaxation(True)
engine.control.set_mod_loc_coor(False)
engine.control.set_inc_tendon(True)
engine.control.set_nonlinear(geom=False, link=False)

# Sections
engine.section.create_circle(no=1, name="CircleSection1", d=0.219, tw=0.012)
engine.section.create_circle(no=2, name="CircleSection2", d=0.180, tw=0.008)

# Materials
engine.material.create_steel(
    no=1, name="Steel1", code="JTGD64_2015", grade="Q345", dmp=0.05
)

# Nodes
engine.node.create(no=1, x=0, y=5, z=0)
engine.node.create(no=2, x=15, y=5, z=0)
engine.node.create(no=3, x=7.5, y=0, z=0)
engine.node.create(no=4, x=20, y=0, z=0)

# Elements
engine.element.create_beam3d(no=1, node1=1, node2=3, mat=1, sec1=1, sec2=1)
engine.element.create_beam3d(no=2, node1=2, node2=3, mat=1, sec1=2, sec2=2)

# Boundaries
engine.boundary.create_general(no=1)
engine.boundary.get(1).assign("a", [1, 2])

# Loads
lc = engine.load.create(
    "CustomLoadCase1",
    load_case_type="USER",
    prompt="Two forces applied at nodes 3 and 4"
)
lc.create_nforce(3, fx=0, fy=-1000000, fz=0)
lc.create_nforce(4, fx=200000, fy=0, fz=0)

# Solve
engine.solve()

End-to-End Demo (Solver-Only Mode)

See tests/pyosis_demo.py for a runnable end-to-end example that:

  • Starts the solver directly via OSISSolver (no GUI required)
  • Builds the 25m 简支小箱梁 example model (10 prep modules)
  • Runs engine.solve()
  • Exports LCND / LCEF / EnvND / EnvEF results to CSV

The demo reuses the prep modules from tests/output/output_py/25m简支小箱梁中梁-solveronly/, so it serves both as a smoke test and a copy-paste template.

Batch Execution

For non-interactive workflows (large models, customer scripts that took tens of minutes per command), wrap your script in with batch(): to merge all OSIS commands into a single OSIS_Run HTTP request when the block exits:

from pyosis import batch

with batch():
    engine.clear()
    engine.clc()
    engine.control.set_gravity_acceleration(9.8066)
    engine.material.create_conc(no=1, name="C50", ...)
    for i in range(1000):
        engine.node.create(no=i + 1, x=i * 0.1, y=0.0, z=0.0)
    for i in range(999):
        engine.element.create_beam3d(no=i + 1, node1=i + 1, node2=i + 2, ...)

Server-side OSIS_Run calls SplitOsisCommands once and then a single Execution(&v), so the network round-trip cost is paid exactly once instead of once per command. Intermediate reads (get, all) auto-flush the buffer first, so cached objects stay correct.

Notes:

  • Nested with batch(): is supported — the inner exit does not flush; only the outermost exit does.
  • If the block raises, the buffered commands added since __enter__ are discarded.
  • flush() can be called inside the block to force an early flush.
  • next_no() (auto-numbering) raises inside batch() because it would need to query the server mid-batch; pass no=... explicitly, or run auto-numbering outside the batch.

Benchmark on the 25m简支小箱梁中梁 project (.out of ~3000 commands): before batch() ~3000 round-trips; with batch() 3 round-trips (clear + clc + one final flush), ~1000x compression.

.out → pyosis Converter

pyosis ships a converter that turns an OSIS command stream (.out) into a clean, runnable pyosis project. This is the easiest way to migrate a legacy APDL/SML script.

python src/pyosis/transfer/out_to_python.py path/to/model.out path/to/output_project

Generated layout:

output_project/
└── prep/
    ├── main.py          # Entry point (batch mode, runs all 10 modules)
    ├── _1_control.py    # Global control parameters
    ├── _2_property.py   # Geometry / coordinate / damping / creep properties
    ├── _3_material.py   # Materials
    ├── _4_section.py    # Sections (incl. mesh)
    ├── _5_node.py       # Nodes
    ├── _6_element.py    # Elements
    ├── _7_boundary.py   # Boundaries
    ├── _8_loadcase.py   # Load cases
    ├── _9_analysis.py   # Analysis settings (settlement / live / dynamic / stability)
    └── _10_stage.py     # Construction stages

The generated main.py wraps the entire modelling flow in with batch():, so the whole project is sent to OSIS in one HTTP request — matching the OSIS server's native batching path.

Run it:

cd output_project
python prep/main.py            # build the model
python prep/main.py --solve    # build + solve

Notes on the converter:

  • Both long-form command names (Node, Element, Section, Material, LoadCase, Boundary, Stage) and OSIS 5.1 short-form aliases (N, Ele, Sec/SecOff/SecMesh, Mat, LC, Bd, Stg) are recognized and normalized.
  • SectionMesh is emitted with the new Index, PartID, MeshMethod, MeshSize layout (Section 7.3.6.2) — PartID = 1 for concrete sections, 2 for templated composite sections.
  • Spline3D is dispatched to engine.geometry.create_general / create_natural / create_arc2d / create_arc3d based on the type field.
  • Commands that are not yet modeled are passed through verbatim via engine.run(...) so the model still runs; rewrite them into pyosis calls manually if needed.

Chained Method Calls

The dataclass returned by get() supports method chaining without server round-trips:

with batch():
    lc = engine.load.create("Self-weight", load_case_type="D")
    lc.create_gravity()
    lc.create_nforce(node=1, fx=0, fy=-1000, fz=0)
    # ↑ all three commands are queued; the OSIS_Run request only fires at exit

Accessing identity attributes (lc.no, lc.name) does not touch the server. Accessing data fields (lc.type, lc.elements) materializes the object (one-time flush + query), then caches it.

OSIS 5.1 HTTP server bug workaround: the /OSIS_Run command-stream splitter does not strip // line comments, so a comment line and the command that follows it are merged into one bad command. The pyosis .out converter already strips comments before sending; if you ever build a raw .out payload yourself, pre-process the file or use osis_run() through the generated main.py.

End-to-End Demo (GUI Mode)

The single-file demo tests/demo_gui.py is a merged version of the project generated from tests/output/xiaoxiangliang.out. Run it against an open OSIS 5.1+ GUI:

python tests/demo_gui.py            # build the model
python tests/demo_gui.py --solve    # build + solve

The file contains the engine setup, all 10 build_* functions (control / property / material / section / node / element / boundary / loadcase / analysis / stage), and a build_model() driver that wraps everything in with batch(): — so ~250 commands hit OSIS in a single OSIS_Run request.

To regenerate both the single-file demo and the multi-module project:

python tests/_merge_demo_gui.py                                    # -> tests/demo_gui.py
python src/pyosis/transfer/out_to_python.py tests/output/xiaoxiangliang.out tests/output/output_py/xiaoxiangliang

Metadata

Release files for osis-python 0.7.5

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

Source distribution (sdist)

Source distribution for osis-python 0.7.5
File Size Uploaded Provenance Actions
osis_python-0.7.5.tar.gz 191.8 kB Without provenance Details for osis_python-0.7.5.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for osis-python 0.7.5
File Interpreter ABI Platform Actions
osis_python-0.7.5-py3-none-any.whl Python 3 none any Details for osis_python-0.7.5-py3-none-any.whl

Total release size: 425.0 kB

Release files / osis_python-0.7.5.tar.gz

Download URL osis_python-0.7.5.tar.gz
Size 191.8 kB
Tags Source
SHA-256 checksum
How to use checksums
12f1aea954e8f458f632fdcefeae1cf27aa02837c9c250fbeadcf139b76eed06
BLAKE2b-256 checksum
How to use checksums
a7e83181b0070d59ad23a57fd164b50d40873914794069ba80c979786134e7ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / osis_python-0.7.5-py3-none-any.whl

Download URL osis_python-0.7.5-py3-none-any.whl
Size 233.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
73a04ec134d3d3ca5fdc3a55b2b9045e86e0d65a2eedb11af9dba09aaf182c31
BLAKE2b-256 checksum
How to use checksums
2314f275165a15ae88b7cf80893fff40b473a60a552a91eb3485849e5d6e4351
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for osis-python 0.7.5

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.7.5 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