osis-python 0.7.0__py3-none-any.whl → 0.7.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: osis-python
3
- Version: 0.7.0
3
+ Version: 0.7.4
4
4
  Summary: A Python client library for Osis APDL
5
5
  Author-email: "CCCC Highway Consultant Co. Ltd." <support@osisbim.com>
6
6
  License-Expression: MIT
@@ -53,10 +53,12 @@ pip install osis-python -i https://pypi.org/simple
53
53
 
54
54
  ## Requirements
55
55
 
56
- - OSIS >= 5.0 (includes the required Python runtime environment)
56
+ - OSIS >= 5.1 (short-form command names like `N`/`Ele`/`Sec` are accepted by both the converter and runtime)
57
57
  - Python >= 3.8
58
58
  - **Solver-only mode** additionally requires the solver distribution that ships `PySolver.dll` (e.g. `D:\OSIS_Solver\Rbin64`).
59
59
 
60
+ > 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`.
61
+
60
62
  ## Quick Start
61
63
 
62
64
  ### 1. Using OSISEngine (Recommended)
@@ -398,7 +400,7 @@ lc.create_nforce(4, fx=200000, fy=0, fz=0)
398
400
  engine.solve()
399
401
  ```
400
402
 
401
- ## End-to-End Demo
403
+ ## End-to-End Demo (Solver-Only Mode)
402
404
 
403
405
  See [`tests/pyosis_demo.py`](tests/pyosis_demo.py) for a runnable end-to-end example that:
404
406
 
@@ -408,3 +410,109 @@ See [`tests/pyosis_demo.py`](tests/pyosis_demo.py) for a runnable end-to-end exa
408
410
  - Exports LCND / LCEF / EnvND / EnvEF results to CSV
409
411
 
410
412
  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.
413
+
414
+ ## Batch Execution
415
+
416
+ 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:
417
+
418
+ ```python
419
+ from pyosis import batch
420
+
421
+ with batch():
422
+ engine.clear()
423
+ engine.clc()
424
+ engine.control.set_gravity_acceleration(9.8066)
425
+ engine.material.create_conc(no=1, name="C50", ...)
426
+ for i in range(1000):
427
+ engine.node.create(no=i + 1, x=i * 0.1, y=0.0, z=0.0)
428
+ for i in range(999):
429
+ engine.element.create_beam3d(no=i + 1, node1=i + 1, node2=i + 2, ...)
430
+ ```
431
+
432
+ 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.
433
+
434
+ Notes:
435
+
436
+ - Nested `with batch():` is supported — the inner exit does not flush; only the outermost exit does.
437
+ - If the block raises, the buffered commands added since `__enter__` are discarded.
438
+ - `flush()` can be called inside the block to force an early flush.
439
+ - `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.
440
+
441
+ 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**.
442
+
443
+ ## .out → pyosis Converter
444
+
445
+ 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.
446
+
447
+ ```bash
448
+ python src/pyosis/transfer/out_to_python.py path/to/model.out path/to/output_project
449
+ ```
450
+
451
+ Generated layout:
452
+
453
+ ```
454
+ output_project/
455
+ └── prep/
456
+ ├── main.py # Entry point (batch mode, runs all 10 modules)
457
+ ├── _1_control.py # Global control parameters
458
+ ├── _2_property.py # Geometry / coordinate / damping / creep properties
459
+ ├── _3_material.py # Materials
460
+ ├── _4_section.py # Sections (incl. mesh)
461
+ ├── _5_node.py # Nodes
462
+ ├── _6_element.py # Elements
463
+ ├── _7_boundary.py # Boundaries
464
+ ├── _8_loadcase.py # Load cases
465
+ ├── _9_analysis.py # Analysis settings (settlement / live / dynamic / stability)
466
+ └── _10_stage.py # Construction stages
467
+ ```
468
+
469
+ 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.
470
+
471
+ Run it:
472
+
473
+ ```bash
474
+ cd output_project
475
+ python prep/main.py # build the model
476
+ python prep/main.py --solve # build + solve
477
+ ```
478
+
479
+ Notes on the converter:
480
+
481
+ - 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.
482
+ - `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.
483
+ - `Spline3D` is dispatched to `engine.geometry.create_general` / `create_natural` / `create_arc2d` / `create_arc3d` based on the type field.
484
+ - 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.
485
+
486
+ ## Chained Method Calls
487
+
488
+ The dataclass returned by `get()` supports method chaining without server round-trips:
489
+
490
+ ```python
491
+ with batch():
492
+ lc = engine.load.create("Self-weight", load_case_type="D")
493
+ lc.create_gravity()
494
+ lc.create_nforce(node=1, fx=0, fy=-1000, fz=0)
495
+ # ↑ all three commands are queued; the OSIS_Run request only fires at exit
496
+ ```
497
+
498
+ 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.
499
+
500
+ > 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`.
501
+
502
+ ## End-to-End Demo (GUI Mode)
503
+
504
+ The single-file demo [`tests/demo_gui.py`](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:
505
+
506
+ ```bash
507
+ python tests/demo_gui.py # build the model
508
+ python tests/demo_gui.py --solve # build + solve
509
+ ```
510
+
511
+ 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.
512
+
513
+ To regenerate both the single-file demo and the multi-module project:
514
+
515
+ ```bash
516
+ python tests/_merge_demo_gui.py # -> tests/demo_gui.py
517
+ python src/pyosis/transfer/out_to_python.py tests/output/xiaoxiangliang.out tests/output/output_py/xiaoxiangliang
518
+ ```
@@ -1,19 +1,18 @@
1
- osis_python-0.7.0.dist-info/licenses/LICENSE,sha256=T4mkSYliXdU9mYe-NfHkqg6GPhzoYaIQO_a630UzpS4,1088
2
- pyosis/__init__.py,sha256=lK6txR1Z728cE5_0PVNruWOq3pizIvynG8kaQKmJuCA,563
1
+ osis_python-0.7.4.dist-info/licenses/LICENSE,sha256=T4mkSYliXdU9mYe-NfHkqg6GPhzoYaIQO_a630UzpS4,1088
2
+ pyosis/__init__.py,sha256=8qi838xbdeE0GHBZUqQMs--vhiCMs-rn1J6GqA_xMuA,440
3
3
  pyosis/boundary/__init__.py,sha256=W5LfF-jugWa-YI8pnfELZaz0pXLa-D8TiGnBn12HGGQ,102
4
4
  pyosis/boundary/interface.py,sha256=obqQUVFuQK9I7S8IaBZ2VBYfyXgNVBS0PQa9LzRlaAc,8990
5
- pyosis/boundary/manager.py,sha256=6D3wxItLBV3HhFfcANgLmosJygD_rDOmGyrayF8q4eI,39563
5
+ pyosis/boundary/manager.py,sha256=AAGdkp0sLV85enT9TQT9iqvWzjJyLzjiw0rC-tajSrI,39576
6
6
  pyosis/control/__init__.py,sha256=98UAXB9Wkf93pGUKIjoGBBrSCblVeAwc_MXeaAB-UIA,119
7
- pyosis/control/control.py,sha256=AUNFhkWhmfvOjNG8_RZuN2Pu80q5ANDpBLeXZTFhsQ0,2279
7
+ pyosis/control/control.py,sha256=4bX92TDJnf1D5A3YY7ZZrU7iUeAxKCjQe9z_F_SEHBs,2816
8
8
  pyosis/control/io.py,sha256=buaut3-W8kwJIe3PgjtgOU0JCSgDfOEd2cS3mxYsfuc,591
9
- pyosis/control/manager.py,sha256=Cn8uOXZIcXmF51q0DTvw-GVOFmDfJ9rmeAq19-4i82E,9843
9
+ pyosis/control/manager.py,sha256=NhxM-geF-STaUATMZgMac8A93hQ7OkN2cFMI7WRPm1Q,10800
10
10
  pyosis/control/nonlinear.py,sha256=26W_2GhD_0cn3YQxJjgbPR1oEopJWyuFWGlgx0q023I,1604
11
11
  pyosis/core/__init__.py,sha256=mte3tkLHfFIJq6HWpE54aM_D7ARvYBVGkM0Qv4H0uGE,629
12
12
  pyosis/core/all_func.py,sha256=VhvAeMJMCQJ1redjqdkm7meTw1PJNDoRdmXXh2LzkVo,521
13
13
  pyosis/core/apdl_sync.py,sha256=rW5Ot6FLpmUzpfMlrbemstnfhxD_0qtPrWgDfj9_4XY,5312
14
14
  pyosis/core/basic_manager.py,sha256=z3Qh5LpHg4AOyTrGffC09mPnW-yUT-UuhKnFe4GLUOM,7204
15
15
  pyosis/core/batch.py,sha256=jPA9U3ahGRZdY8y1wCSZyVpBPmGOtQtvM3vfDgqM2sM,6851
16
- pyosis/core/build.py,sha256=xt8-BLrKB-KMxmQd92rNCaHSsi5EHbcqPpDOVm2DSFc,81573
17
16
  pyosis/core/client.py,sha256=6i0q-yPosip5IzSESvpCxuF-v8iojRuFXyPulMKO8Ac,3285
18
17
  pyosis/core/command.py,sha256=bZ5nS1wvwhjwIsogWQh5-1dAcbsJoyB8MR85WUprZ0s,8863
19
18
  pyosis/core/engine.py,sha256=UnpE_CUQjNk62aFWRQ62lNA9hqaoBcefOmKnua7IE9A,15829
@@ -31,25 +30,25 @@ pyosis/dynamic/modal.py,sha256=__as3Nl7Ks2ntgcZwAA9UhvsvTfBl-1zSUOTsnPVf-Y,640
31
30
  pyosis/dynamic/seismic.py,sha256=8DIh7xkUgl0UwweDq4WoYSNzMxpLnpDaM4W_7u3rg_A,6380
32
31
  pyosis/element/__init__.py,sha256=fZgmxJiNhCe3Ki8vNEdZOhyinxwvlF6Jcu-DgD-c6YM,92
33
32
  pyosis/element/interface.py,sha256=xLd2ljq0qW5uvqV0Lo2e6Ly7NShh_p2I5vQNdcA8P4Q,9872
34
- pyosis/element/manager.py,sha256=xsUhhinu0T_bU7w0r8BV0yFgnkTnuZC8vyBwFdq3vBY,36602
33
+ pyosis/element/manager.py,sha256=YzJEmcs5sx8R-nfucneujouQtwm3o6vUo0CUEw-xing,36615
35
34
  pyosis/general/__init__.py,sha256=dyvge-GgUpT3BeDwm_Lss1xqNlxAQdt63WJ7QcuZ_O4,24
36
35
  pyosis/general/interface.py,sha256=YRXQ-iXYVhiUBiUd7fpA0NOtL5VSueOHcobj625aQeU,5382
37
36
  pyosis/geometry/__init__.py,sha256=mlAXlxaohcEcm8-6anyDo1fevh_IzYz2OXBn0_DIrCY,99
38
37
  pyosis/geometry/interface.py,sha256=OHpsFEgjQok8FXpsOXXbCxfe9PPF6ac2rU6fii91jkY,4444
39
- pyosis/geometry/manager.py,sha256=dnPjyW_ukLeh17XbK0v9So5rlvODJk4tNHRWKb1hi3o,13757
38
+ pyosis/geometry/manager.py,sha256=8sR4GJ6UXSEPM2_4eM6AFlWTj8RGuwmwm0OIT1hPFiQ,13698
40
39
  pyosis/live/__init__.py,sha256=jl0pMkfAGRnukwuCbc6fOJoWo-ufMnFm4lyBV-xQQxc,112
41
40
  pyosis/live/analysis.py,sha256=sI0jE65KS2EylpmBbySNcGsUHvvk9-6SZ0-37ZXsmbk,5486
42
41
  pyosis/live/grade.py,sha256=GjFxV_FImMK_ahfB0DNePGwdifUbiFK8r-cSXlnrVP8,3774
43
42
  pyosis/live/lane.py,sha256=i1-mnKQuo_XLimtcX2ZV4PBC_A0FBneWxJU198X1MMc,5487
44
- pyosis/live/manager.py,sha256=iVJSZ_Ro2RzyVUMtGnw6KWHQrSCtGLoZA1cJRgvQwuw,49272
43
+ pyosis/live/manager.py,sha256=q0w9RVfuwLUqPYo4CS8kc9NchyF7mCiczcrWEzD31NQ,49319
45
44
  pyosis/load/__init__.py,sha256=AdCBsdf4QPVzbKwbj2C24Fnl9sPmlB9h542LjLFcqHM,135
46
45
  pyosis/load/loadcase.py,sha256=5DOty5OBtxHPguw_gYUqL3FFbXRkCjA2IVpCdAzJSJU,2457
47
- pyosis/load/manager.py,sha256=5rc7oK1ZczpgyZPQy6nr-dcLWhOUBSYmKWRo_wV86QQ,81322
46
+ pyosis/load/manager.py,sha256=NVXXxW44eHhAElWSTi9IWjQbvOh9rblcQANzcTf31vg,81453
48
47
  pyosis/load/static.py,sha256=vvwx5WmXUL-M3GvlH9GA-oaTZQmvLaawR76dFNVrwgc,22773
49
48
  pyosis/load/tendon.py,sha256=2AJxvYJU8PEJ-rH-vbLUjd0CwmhIeSFEx9asuWpT_0s,11528
50
49
  pyosis/material/__init__.py,sha256=W0oDx9SY_zngAcrMCO_0sF773-OxCfL1B-w2IeWlZ_g,79
51
50
  pyosis/material/interface.py,sha256=SiHWjLPUDR1f3EMObGlYQUlKgpfoh1VuGJgVAQfariA,5729
52
- pyosis/material/manager.py,sha256=b6pIwi70eOY93IJBhqXZKZdpQEA2DC1SOCCQgVT-Vow,15974
51
+ pyosis/material/manager.py,sha256=4zPVD03QOZ7sSPk4VpZgf1Ug5TTVpqsAIZb4Phj4Ftg,16061
53
52
  pyosis/node/__init__.py,sha256=6BKMR_HhFuvf-wr_U1H4njEj95pqgiHh6ApFl2JWMQ0,71
54
53
  pyosis/node/interface.py,sha256=T0lL1pHD069Qw3PTxufUF6cJl9fAKiclAL_ISgboaz8,1208
55
54
  pyosis/node/manager.py,sha256=fXkmeILs_LUvyv45wKBwzDFB2ssNO4In-bP71Dbrlow,8877
@@ -66,7 +65,7 @@ pyosis/property/component_thickness.py,sha256=fH9jpt2V6w2lSL2jDb1cuk5wylfhvnznxZ
66
65
  pyosis/property/coordinate.py,sha256=xFfuzXCzBWqYsDxHifpYCYgC_to9kC4LKD2yTX2CtvM,2668
67
66
  pyosis/property/creep_shrink.py,sha256=VsBYrMb8LjCWAx8AG7XeiYlww1HaK43gmayG7fcSL10,1469
68
67
  pyosis/property/damping.py,sha256=pasnvd1zua1skO-3lcLydFYT3phIZKqC-28DZn5jsGA,3225
69
- pyosis/property/manager.py,sha256=71Belg0cLZvkCg3wwq7xywqPx2K4dvOiJRCaxy6o6iw,31135
68
+ pyosis/property/manager.py,sha256=BQRI0dTzPiaMjsUnzgjolponJpas7FLMhM9qDE1ULvw,31135
70
69
  pyosis/property/pu_curve.py,sha256=E3oUfe7ERYKX6q9v1U-HnNP1LRbWobNYB8dUC26s8aQ,1534
71
70
  pyosis/quick_building/__init__.py,sha256=QiWapgiZk6pkAdiznKI0bVIc16UcFOIALQuLhupLkqw,48
72
71
  pyosis/quick_building/interface.py,sha256=xdQrORabxmnlhi537pspFokQBaXSmnZMIxA_kxSo_cE,13951
@@ -79,9 +78,9 @@ pyosis/result/result.py,sha256=wUyRaHSwyijLpodWIHPFQVEOn6LP8MfYp7xLhC-RiIo,1194
79
78
  pyosis/section/__init__.py,sha256=VjNbQWgWHtLO6la39oXgbQMnQPR0-b1DPIM52Cj--jg,179
80
79
  pyosis/section/common.py,sha256=yI61YQH8btfkoBGnXF7wp3kFhZVW06XABIJZnvkDk3E,26616
81
80
  pyosis/section/composite.py,sha256=CWNcPagXbL4D8uUouRk8ux7Xv41bE2dXM8JfWX77pBI,9353
82
- pyosis/section/manager.py,sha256=QuL4g2v08C0z9kMmo3DUBzysP9bbcTnn20ff5ttE2Mk,92805
81
+ pyosis/section/manager.py,sha256=WED3yj01gb0gOJ1pwDEJcEFpZhWwLBy62ETQayTEPYM,94343
83
82
  pyosis/section/numeric.py,sha256=lDO1KvSTmzBE56wkfDw5xxDhWi-kM0szXPx6CIymIyQ,1479
84
- pyosis/section/param.py,sha256=BC86XGqxbEHrjVMfwFuILmMExEdzpPwpCJ5XrLaVOOo,4713
83
+ pyosis/section/param.py,sha256=E4ZyJqyPn1xhNchb82ar6K36a_ah8R_66-FruOMlbBM,4944
85
84
  pyosis/section/rebar.py,sha256=9ibcOoMd7HYfzSaO6dMpZFwp1ugmwayOmDqIoWUijNc,8337
86
85
  pyosis/section/rib.py,sha256=p3QfuBz9FiNmc7ePH4zzP3EkP52k8JtzxwCPK6Zjq14,8387
87
86
  pyosis/section/steel.py,sha256=UZ5OmealrvFwwfFSD1Hf67AzuOVAH5OXE4nyv3XNHN0,14960
@@ -99,13 +98,13 @@ pyosis/thickness/__init__.py,sha256=YGYmUPc9TvAlw4eFuEjxaG7HjvwLQJelU_Mx2M6RhW0,
99
98
  pyosis/thickness/interface.py,sha256=o9fwAnPtincBvNB7KZ-Cw67V4mSvoMYgcuLqD_FMLs0,1311
100
99
  pyosis/thickness/manager.py,sha256=JfKNKQnAaqEVnFyr3UwCj9cl4qhHYT_9Pp7HVBYNx6M,5048
101
100
  pyosis/transfer/__init__.py,sha256=OZVxVnjhDGe4fHC6pjtOaKPzAKuoDp3-XkNFzDWepsE,623
102
- pyosis/transfer/generator.py,sha256=T3YLf4TrqAF4FFIa84opclmNDCw5WpvbNIsKC2rvKcU,3541
101
+ pyosis/transfer/generator.py,sha256=hDM2je_3t18_S9mimYi1yB7XD2YKVm98cERLLnx_RFQ,3750
103
102
  pyosis/transfer/matrix.py,sha256=sHw9X34-PUeY1EdoNklgK0LUHwbBPnhkhk0R9ME0XG0,3378
104
- pyosis/transfer/out_to_python.py,sha256=WMzu1GaVvzvO1oq9ihyyp9dn2xY4s6ualW5M7CO98Cg,14464
103
+ pyosis/transfer/out_to_python.py,sha256=oaD5xX2lvMTriQe4LIW43xKYw1kh__W45vQzsLDZ1S0,15223
105
104
  pyosis/transfer/parser.py,sha256=R_aBlYJTe53hD1sX5PBv86bhj88NQwANFRN4pGYudQ8,6774
106
- pyosis/transfer/routes.py,sha256=GAgrx71utq1tToxQKtfYeBwBvy7bktvFWEvWq3FPYIk,8267
105
+ pyosis/transfer/routes.py,sha256=EvJ88cgtulYShvgoDfaDkkxVn3fhYgL0CffmJEtk2sY,9649
107
106
  pyosis/transfer/split.py,sha256=hpBe9D9WbjbKsovx4hM3X5RjTrruWNkuFmZt2ed0fME,1284
108
- osis_python-0.7.0.dist-info/METADATA,sha256=VeDqzmZAhV5L5nz7etlwhRQfmfbPrrbSS18aY7Iaepk,14189
109
- osis_python-0.7.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
110
- osis_python-0.7.0.dist-info/top_level.txt,sha256=6VDNySkQKwipRXcN8ayKVci4vAXi4oPyWLqFhNVcIfM,7
111
- osis_python-0.7.0.dist-info/RECORD,,
107
+ osis_python-0.7.4.dist-info/METADATA,sha256=E7utN9rzJfEKH-lgpIGuz1r6puAeLaF_Mjd2aNYtoIY,20117
108
+ osis_python-0.7.4.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
109
+ osis_python-0.7.4.dist-info/top_level.txt,sha256=6VDNySkQKwipRXcN8ayKVci4vAXi4oPyWLqFhNVcIfM,7
110
+ osis_python-0.7.4.dist-info/RECORD,,
pyosis/__init__.py CHANGED
@@ -7,8 +7,7 @@ A library for extending OSIS functionality.
7
7
  A library that allows users to use CAE with great flexibility.
8
8
  """
9
9
 
10
- __version__ = "0.7.0"
11
- __author__ = "CCCC Highway Consultant Co. Ltd." # 中交公路规划设计院 - 工程技术研究中心 - lzh - wjh - myf
10
+ __version__ = "0.7.4"
12
11
 
13
12
  from .core.engine import OSISEngine
14
13
  from .core.batch import batch, flush, batch_state, BatchError
@@ -536,7 +536,7 @@ class BoundaryGroupManager(BasicManager):
536
536
  Returns:
537
537
  BoundaryGroup: 创建(或刷新后的)边界组对象
538
538
  '''
539
- ok, err = osis_boundary_group(name, op, *param)
539
+ ok, err = osis_boundary_group(name, str(op).lower(), *param)
540
540
  if not ok:
541
541
  raise RuntimeError(f"创建边界组 {name} 失败: {err}")
542
542
  return self.get(name)
pyosis/control/control.py CHANGED
@@ -103,6 +103,32 @@ def osis_mod_loc_coor(bFlag: int=1):
103
103
  '''
104
104
  pass
105
105
 
106
+ @REGISTRY.register("CalcRebarGravity")
107
+ def osis_calc_rebar_gravity(bFlag: int=1):
108
+ '''
109
+ 是否考虑钢筋钢束自重
110
+
111
+ Args:
112
+ bFlag (bool): 1=考虑,0=不考虑
113
+
114
+ Returns:
115
+ tuple (bool, str): 是否成功,失败原因
116
+ '''
117
+ pass
118
+
119
+ @REGISTRY.register("IncRebar")
120
+ def osis_inc_rebar(bFlag: int=1):
121
+ '''
122
+ 是否考虑钢筋对截面几何特性的影响
123
+
124
+ Args:
125
+ bFlag (bool): 1=考虑,0=不考虑
126
+
127
+ Returns:
128
+ tuple (bool, str): 是否成功,失败原因
129
+ '''
130
+ pass
131
+
106
132
  @REGISTRY.register("IncTendon")
107
133
  def osis_inc_tendon(bFlag: int=1):
108
134
  '''
pyosis/control/manager.py CHANGED
@@ -27,6 +27,8 @@ from .control import (
27
27
  osis_calc_shear,
28
28
  osis_calc_rlx,
29
29
  osis_mod_loc_coor,
30
+ osis_calc_rebar_gravity,
31
+ osis_inc_rebar,
30
32
  osis_inc_tendon,
31
33
  )
32
34
  from .io import osis_apdl
@@ -230,6 +232,38 @@ class ControlManager:
230
232
  if not ok:
231
233
  raise RuntimeError(f"设置局部坐标轴修正失败: {err}")
232
234
 
235
+ def set_calc_rebar_gravity(self, enabled: Literal[0,1] = 1) -> None:
236
+ '''设置是否考虑钢筋钢束自重
237
+
238
+ Args:
239
+ enabled (int): 1=考虑,0=不考虑
240
+
241
+ Returns:
242
+ None
243
+
244
+ Raises:
245
+ RuntimeError: 设置失败时抛出异常
246
+ '''
247
+ ok, err = osis_calc_rebar_gravity(enabled)
248
+ if not ok:
249
+ raise RuntimeError(f"设置钢筋钢束自重考虑失败: {err}")
250
+
251
+ def set_inc_rebar(self, enabled: Literal[0,1] = 1) -> None:
252
+ '''设置是否考虑钢筋对截面几何特性的影响
253
+
254
+ Args:
255
+ enabled (int): 1=考虑,0=不考虑
256
+
257
+ Returns:
258
+ None
259
+
260
+ Raises:
261
+ RuntimeError: 设置失败时抛出异常
262
+ '''
263
+ ok, err = osis_inc_rebar(enabled)
264
+ if not ok:
265
+ raise RuntimeError(f"设置钢筋截面特性影响失败: {err}")
266
+
233
267
  def set_inc_tendon(self, enabled: Literal[0,1] = 1) -> None:
234
268
  '''设置是否考虑钢束自重及钢束对截面几何特性的影响
235
269
 
pyosis/element/manager.py CHANGED
@@ -316,7 +316,7 @@ class ElementGroupManager(BasicManager):
316
316
  Returns:
317
317
  ElementGroup: 创建的单元组对象
318
318
  """
319
- ok, err = osis_element_group(name, op, *param)
319
+ ok, err = osis_element_group(name, str(op).lower(), *param)
320
320
  if not ok:
321
321
  raise RuntimeError(f"创建单元组 {name} 失败: {err}")
322
322
  return self.get(name)
@@ -221,7 +221,7 @@ class GeometryManager(BasicManager):
221
221
  self,
222
222
  name: str,
223
223
  owner: Literal["LIVE", "TENDON"],
224
- *coordinates: float,
224
+ coordinates: list[float],
225
225
  ) -> Spline:
226
226
  """创建或修改三维样条曲线(自然边界/NATURAL)。
227
227
 
@@ -240,9 +240,7 @@ class GeometryManager(BasicManager):
240
240
 
241
241
  Examples:
242
242
  >>> geometry_manager.create_natural("Lane1", "LIVE",
243
- ... 0.0, 0.0, 0.0,
244
- ... 10.0, 0.0, 0.0,
245
- ... 20.0, 0.0, 0.0,
243
+ ... [0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 20.0, 0.0, 0.0],
246
244
  ... )
247
245
  """
248
246
  ok, err = osis_spline3d_natural(name, "NATURAL", owner, *coordinates)
@@ -254,7 +252,7 @@ class GeometryManager(BasicManager):
254
252
  self,
255
253
  name: str,
256
254
  owner: str,
257
- *coordinates: float,
255
+ coordinates: list[float],
258
256
  ) -> Spline:
259
257
  """创建或修改三维样条曲线(2D圆弧/ARC2D)。
260
258
 
@@ -273,8 +271,7 @@ class GeometryManager(BasicManager):
273
271
 
274
272
  Examples:
275
273
  >>> geometry_manager.create_arc2d("Arc1", "TENDON",
276
- ... 0.0, 0.0, 10.0,
277
- ... 10.0, 0.0, 10.0,
274
+ ... [0.0, 0.0, 10.0, 10.0, 0.0, 10.0],
278
275
  ... )
279
276
  """
280
277
  ok, err = osis_spline3d_arc2d(name, "ARC2D", owner, *coordinates)
@@ -286,7 +283,7 @@ class GeometryManager(BasicManager):
286
283
  self,
287
284
  name: str,
288
285
  owner: str,
289
- *coordinates: float,
286
+ coordinates: list[float],
290
287
  ) -> Spline:
291
288
  """创建或修改三维样条曲线(3D圆弧/ARC3D)。
292
289
 
@@ -305,8 +302,7 @@ class GeometryManager(BasicManager):
305
302
 
306
303
  Examples:
307
304
  >>> geometry_manager.create_arc3d("Arc3d1", "TENDON",
308
- ... 0.0, 0.0, 0.0, 20.0,
309
- ... 10.0, 0.0, 5.0, 20.0,
305
+ ... [0.0, 0.0, 0.0, 20.0, 10.0, 0.0, 5.0, 20.0],
310
306
  ... )
311
307
  """
312
308
  ok, err = osis_spline3d_arc3d(name, "ARC3D", owner, *coordinates)
pyosis/live/manager.py CHANGED
@@ -265,6 +265,7 @@ class LiveCase:
265
265
  Returns:
266
266
  更新后的 LiveCase 对象
267
267
  """
268
+ op = str(op).lower()
268
269
  if op in ("a", "m"):
269
270
  _MU_PARAM_COUNT = {
270
271
  "SIMPLE": 4,
@@ -278,7 +279,7 @@ class LiveCase:
278
279
  grade_name, scalar, mu_flag = args[0], float(args[1]), int(args[2])
279
280
  rest = args[4:]
280
281
  if mu_flag == 1:
281
- bridge_type = args[3] or "SIMPLE"
282
+ bridge_type = (args[3] or "SIMPLE").strip().upper()
282
283
  mu_count = _MU_PARAM_COUNT.get(bridge_type, 1)
283
284
  mu_params: list[float] = [float(x) for x in rest[:mu_count]]
284
285
  lane_names: list[str] = list(rest[mu_count:])
pyosis/load/manager.py CHANGED
@@ -295,6 +295,8 @@ class LoadCase:
295
295
  elem, e_coord, n_range, *rest = args
296
296
  forces = [list(rest[i: i + 6]) for i in range(0, len(rest), 6)]
297
297
  return self.create_concentrated_force(elem,e_coord,is_moment=(type_key == "PTM"),forces=forces)
298
+ if type_key not in _creator:
299
+ raise ValueError(f"未知荷载类型: {type!r},支持: {', '.join(_creator)}")
298
300
  return _creator[type_key](*args, **kwargs)
299
301
 
300
302
  def create_gravity(
@@ -158,9 +158,10 @@ class MaterialManager(BasicManager):
158
158
  "REBAR": self.create_rebar,
159
159
  "CUSTOM": self.create_custom,
160
160
  }
161
- if type not in _creator:
162
- raise ValueError(f"未知材料类型: {type}")
163
- return _creator[type](no, name, *args, **kwargs)
161
+ type_key = str(type).strip().upper()
162
+ if type_key not in _creator:
163
+ raise ValueError(f"未知材料类型: {type!r},支持: {', '.join(_creator)}")
164
+ return _creator[type_key](no, name, *args, **kwargs)
164
165
 
165
166
  def create_conc(
166
167
  self,
@@ -518,9 +518,9 @@ class DampingManager(BasicManager):
518
518
  raise ValueError(
519
519
  f"未知阻尼类型: {type!r},支持: {', '.join(sorted(_supported_types))}"
520
520
  )
521
- if type_key == "modal":
521
+ if type_key == "MODAL":
522
522
  return self.create_modal(name, *args, **kwargs)
523
- # type_key == "ryl"
523
+ # type_key == "RYL"
524
524
  method = args[0] if args else kwargs.get("method")
525
525
  _supported_methods = {0: "根据公式计算因子", 1: "自定义因子"}
526
526
  if method not in _supported_methods:
pyosis/section/manager.py CHANGED
@@ -274,19 +274,21 @@ class Section:
274
274
  self,
275
275
  mesh_method: Literal[0, 1] = 0,
276
276
  mesh_size: float = 0.0,
277
+ part_id: int = 1,
277
278
  ) -> None:
278
- '''设置截面网格。
279
+ '''设置截面网格(适用于混凝土截面、模板组合截面与自定义组合截面)。
279
280
 
280
281
  Args:
281
282
  mesh_method (int): 网格划分方式
282
283
  * 0 = 自动划分
283
284
  * 1 = 手动划分
284
285
  mesh_size (float): 网格划分尺寸,在 mesh_method=1 时起作用
286
+ part_id (int): 分部编号,混凝土截面输入 1,模板组合截面输入 2
285
287
 
286
288
  Raises:
287
289
  RuntimeError: 设置失败时抛出
288
290
  '''
289
- ok, err = osis_section_mesh(self.no, mesh_method, mesh_size)
291
+ ok, err = osis_section_mesh(self.no, part_id, mesh_method, mesh_size)
290
292
  if not ok:
291
293
  raise RuntimeError(f"设置截面 {self.no} 网格失败: {err}")
292
294
 
@@ -382,15 +384,18 @@ class Section:
382
384
  """添加或修改组合截面 Part(按类型分发)
383
385
 
384
386
  Args:
385
- type: Part 类型
387
+ type: Part 类型(大小写不敏感)
386
388
  * POLYGON = 多边形
387
389
  * LINE = 折线
388
390
  args: 剩余参数透传给对应子方法
389
391
  """
390
- if type == "POLYGON":
392
+ key = str(type).upper()
393
+ if key == "POLYGON":
391
394
  self.add_composite_part_polygon(*args)
392
- elif type == "LINE":
395
+ elif key == "LINE":
393
396
  self.add_composite_part_line(*args)
397
+ else:
398
+ raise ValueError(f"未知 Part 类型: {type!r},支持 POLYGON/LINE")
394
399
 
395
400
  # ── 组合截面材料 ──────────────────────────
396
401
 
@@ -424,15 +429,16 @@ class Section:
424
429
 
425
430
  # ── 应力点 ────────────────────────────────
426
431
 
427
- def set_stress_point(self, n_point: int, d_coord_x: float, d_coord_y: float) -> None:
432
+ def set_stress_point(self, n_part_id: int, n_point: int, d_coord_x: float, d_coord_y: float) -> None:
428
433
  """修改截面应力点
429
434
 
430
435
  Args:
436
+ n_part_id: 分部编号,混凝土截面需输入1
431
437
  n_point: 应力点编号
432
438
  d_coord_x: 应力点 x 坐标
433
439
  d_coord_y: 应力点 y 坐标
434
440
  """
435
- ok, err = osis_stress_point(self.no, n_point, d_coord_x, d_coord_y)
441
+ ok, err = osis_stress_point(self.no, n_part_id, n_point, d_coord_x, d_coord_y)
436
442
  if not ok:
437
443
  raise RuntimeError(f"设置截面 {self.no} 应力点 {n_point} 失败: {err}")
438
444
 
@@ -680,21 +686,26 @@ class Section:
680
686
 
681
687
  Args:
682
688
  rebar_no: 钢筋编号
683
- type: 钢筋输入方式
689
+ type: 钢筋输入方式(大小写不敏感,兼容命令流全大写写法 LINEA 等)
684
690
  * Point = 点输入
685
691
  * LineA = 直线-垂直方式 A
686
692
  * LineB = 直线-垂直方式 B
687
693
  * Circle = 圆周输入
688
694
  args: 剩余参数透传给对应子方法
689
695
  """
690
- if type == "Point":
696
+ key = str(type).upper()
697
+ if key == "POINT":
691
698
  self.add_rebar_point(rebar_no, *args)
692
- elif type == "LineA":
699
+ elif key == "LINEA":
693
700
  self.add_rebar_line_a(rebar_no, *args)
694
- elif type == "LineB":
701
+ elif key == "LINEB":
695
702
  self.add_rebar_line_b(rebar_no, *args)
696
- elif type == "Circle":
703
+ elif key == "CIRCLE":
697
704
  self.add_rebar_circle(rebar_no, *args)
705
+ else:
706
+ raise ValueError(
707
+ f"未知纵向钢筋类型: {type!r},支持 Point/LineA/LineB/Circle"
708
+ )
698
709
 
699
710
  def add_rebar_s(
700
711
  self,
@@ -704,21 +715,26 @@ class Section:
704
715
  """添加或修改抗剪钢筋(按类型分发)
705
716
 
706
717
  Args:
707
- type: 钢筋类型
718
+ type: 钢筋类型(大小写不敏感,兼容 SHEARSTIRRUP 等命令流写法)
708
719
  * BentUpRebar = 弯起钢筋
709
720
  * ShearStirrup = 抗剪箍筋
710
721
  * WebVerticalRebar = 腹板竖筋
711
722
  * TorsionalStirrup = 扭转箍筋
712
723
  args: 剩余参数透传给对应子方法
713
724
  """
714
- if type == "BentUpRebar":
725
+ key = str(type).upper()
726
+ if key == "BENTUPREBAR":
715
727
  self.add_rebar_s_bent_up(*args)
716
- elif type == "ShearStirrup":
728
+ elif key == "SHEARSTIRRUP":
717
729
  self.add_rebar_s_shear_stirrup(*args)
718
- elif type == "WebVerticalRebar":
730
+ elif key == "WEBVERTICALREBAR":
719
731
  self.add_rebar_s_web_vertical(*args)
720
- elif type == "TorsionalStirrup":
732
+ elif key == "TORSIONALSTIRRUP":
721
733
  self.add_rebar_s_torsional_stirrup(*args)
734
+ else:
735
+ raise ValueError(
736
+ f"未知抗剪钢筋类型: {type!r},支持 BentUpRebar/ShearStirrup/WebVerticalRebar/TorsionalStirrup"
737
+ )
722
738
 
723
739
  def add_rib(
724
740
  self,
@@ -728,7 +744,7 @@ class Section:
728
744
  """添加或修改加劲肋(按类型分发)
729
745
 
730
746
  Args:
731
- type: 加劲肋类型
747
+ type: 加劲肋类型(大小写不敏感)
732
748
  * Flat = 扁平加劲肋
733
749
  * T = T 形加劲肋
734
750
  * U = U 形加劲肋
@@ -736,14 +752,19 @@ class Section:
736
752
  * LR = 右 L 形加劲肋
737
753
  args: 剩余参数透传给对应子方法
738
754
  """
739
- if type == "Flat":
755
+ key = str(type).upper()
756
+ if key == "FLAT":
740
757
  self.add_rib_flat(*args)
741
- elif type == "T":
758
+ elif key == "T":
742
759
  self.add_rib_t(*args)
743
- elif type == "U":
760
+ elif key == "U":
744
761
  self.add_rib_u(*args)
745
- elif type in ("LL", "LR"):
746
- self.add_rib_l(args[0], type, *args[1:])
762
+ elif key in ("LL", "LR"):
763
+ self.add_rib_l(args[0], key, *args[1:])
764
+ else:
765
+ raise ValueError(
766
+ f"未知加劲肋类型: {type!r},支持 Flat/T/U/LL/LR"
767
+ )
747
768
 
748
769
  def add_rib_flat(
749
770
  self,
@@ -907,15 +928,22 @@ class Section:
907
928
  '''删除箍筋
908
929
 
909
930
  Args:
910
- rebar_type (str): 钢筋类型
931
+ rebar_type (str): 钢筋类型(大小写不敏感)
911
932
  * BentUpRebar = 弯起钢筋
912
933
  * ShearStirrup = 抗剪箍筋
913
934
  * WebVerticalRebar = 腹板竖筋
914
935
  * TorsionalStirrup = 扭转箍筋
915
936
 
916
937
  Raises:
938
+ ValueError: 未知的钢筋类型
917
939
  RuntimeError: 删除失败时抛出
918
940
  '''
941
+ if str(rebar_type).strip().upper() not in (
942
+ "BENTUPREBAR", "SHEARSTIRRUP", "WEBVERTICALREBAR", "TORSIONALSTIRRUP",
943
+ ):
944
+ raise ValueError(
945
+ f"未知抗剪钢筋类型: {rebar_type!r},支持 BentUpRebar/ShearStirrup/WebVerticalRebar/TorsionalStirrup"
946
+ )
919
947
  ok, err = osis_rebar_s_del(self.no, rebar_type)
920
948
  if not ok:
921
949
  raise RuntimeError(f"删除截面 {self.no} 箍筋 {rebar_type} 失败: {err}")