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/Secare 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_Runcommand-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.outconverter already strips comments before sending; if you ever build a raw.outpayload yourself, pre-process the file or useosis_run()through the generatedmain.py.
Quick Start
1. Using OSISEngine (Recommended)
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_pathmust be the directory containingPySolver.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, avg_humidity, birth_time, type_coeff, shrink_birth)
engine.prop.creep_shrink.create(no=1, name="Creep1", avg_humidity=70.0,
birth_time=7, type_coeff=5.0, shrink_birth=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 insidebatch()because it would need to query the server mid-batch; passno=...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. SectionMeshis emitted with the newIndex, PartID, MeshMethod, MeshSizelayout (Section 7.3.6.2) —PartID = 1for concrete sections,2for templated composite sections.Spline3Dis dispatched toengine.geometry.create_general/create_natural/create_arc2d/create_arc3dbased 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_Runcommand-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.outconverter already strips comments before sending; if you ever build a raw.outpayload yourself, pre-process the file or useosis_run()through the generatedmain.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.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| osis_python-0.7.4.tar.gz | 190.2 kB | Without provenance | Details for osis_python-0.7.4.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| osis_python-0.7.4-py3-none-any.whl | Python 3 | none | any | Details for osis_python-0.7.4-py3-none-any.whl |
Total release size: 421.4 kB
Release files / osis_python-0.7.4.tar.gz
| Download URL | osis_python-0.7.4.tar.gz |
|---|---|
| Size | 190.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fbb60e246d70a7c1472ef27a7263d556281d6aa7a9283d83f046e757e293665c
|
|
BLAKE2b-256 checksum How to use checksums |
890a4c16b3f28659900711b0903f4f0a68d03e7c35ff438fd18b356aef90eb99
|
| 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.4-py3-none-any.whl
| Download URL | osis_python-0.7.4-py3-none-any.whl |
|---|---|
| Size | 231.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c03197c07c79ebbf196519327bc9be5267c01368225bd8c4fb4301492599b763
|
|
BLAKE2b-256 checksum How to use checksums |
53822fc5246a4156c22dd52e9ae3cb0675a970d0f92861cc54aeffc8dd20c1d8
|
| 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.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.