pystran 0.2.0__tar.gz → 0.2.2__tar.gz
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.
- {pystran-0.2.0 → pystran-0.2.2}/PKG-INFO +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/pyproject.toml +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/pystran/plots.py +33 -52
- {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_planar_frame.py +2 -2
- {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_planar_truss.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_space_frame.py +2 -2
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/00_matrices_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/01_alt_three_bars_tut.py +15 -13
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/01_three_bars_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/02_continuous_beam_2_spans_consist_tut.py +3 -3
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/03_weaver_1_tut.py +6 -5
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/04_supp_settle_tut.py +4 -4
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/05_hinge_frame_tut.py +6 -4
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/07_frame_thermal_tut.py +3 -3
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/08_alt_refine_member_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/08_refine_member_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/09_SDLX_01_89_vibration_tut.py +4 -2
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/10_truss_5_vibration_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/11_samcef_frame_3d_vibration_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/12_timo_beam_on_springs_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/13_hinged_3d_frame_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/14_truss_skew_support_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/15_penalty_supports_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/16_distributed_load_continuous_beam_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/17_arch_out_of_plane_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/18_SSLL05_89_tut.py +1 -1
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/19_garteur_air_frame_vibration_ref_tut.py +3 -2
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/19_garteur_air_frame_vibration_simpl_tut.py +1 -1
- pystran-0.2.0/Job-1.inp +0 -111
- {pystran-0.2.0 → pystran-0.2.2}/.github/workflows/pubflow.yml +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/.github/workflows/sphinx.yml +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/.gitignore +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/LICENSE +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/README.md +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-cl-rb.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-cl.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-ss-rb.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-ss.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_3d_stiffness_check.ipynb +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_3d_stiffness_check.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_curvatures.ipynb +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_curvatures.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_shape.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_shape_-1_+1.ipynb +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_shape_0_1.ipynb +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_stiffness.ipynb +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_stiffness.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_stiffness_via_flexibility.ipynb +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/beams.pdf +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/clamped_beam.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/clamped_beam_w_triangulardl.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/clamped_beam_w_udl.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/context.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/derivations/moment_and_other_releases.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/doc_requirements.txt +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/issues-and-ideas.md +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/make_docs.md +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/source/conf.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/splash.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/ScreenHunter 24.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/console.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/from_existing.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/graphics_settings.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/new_project.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/open_tutorial.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/project_pane.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/spyder.md +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/terminal/folder_and_run.png +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/docs/terminal/terminal.md +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/Abaqus_import.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/__init__.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/assemble.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/beam.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/gauss.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/geometry.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/model.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/rigid.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/rotation.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/section.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/spring.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/pystran/truss.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/requirements.txt +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/scripts/context.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tests/context.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_space_truss.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut.cae +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut.inp +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut2.cae +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_12el.inp +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_12el_bc.inp +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_6el.inp +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_a.inp +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_b.inp +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/19_garteur_air_frame_vibration_tut.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/20_abaqus_import.py +0 -0
- {pystran-0.2.0 → pystran-0.2.2}/tutorials/context.py +0 -0
|
@@ -157,6 +157,12 @@ def setup(m, set_limits=False, fontsize=0):
|
|
|
157
157
|
m['fig'] = fig # plotting objects saved
|
|
158
158
|
if m["dim"] == 3:
|
|
159
159
|
ax = fig.add_subplot(projection="3d")
|
|
160
|
+
if set_limits:
|
|
161
|
+
box = bounding_box(m)
|
|
162
|
+
cd = characteristic_dimension(m)
|
|
163
|
+
ax.set_xlim3d([box[0] - cd / 10, box[3] + cd / 10])
|
|
164
|
+
ax.set_ylim3d([box[1] - cd / 10, box[4] + cd / 10])
|
|
165
|
+
ax.set_zlim3d([box[2] - cd / 10, box[5] + cd / 10])
|
|
160
166
|
else:
|
|
161
167
|
ax = fig.add_subplot()
|
|
162
168
|
if set_limits:
|
|
@@ -164,9 +170,25 @@ def setup(m, set_limits=False, fontsize=0):
|
|
|
164
170
|
cd = characteristic_dimension(m)
|
|
165
171
|
ax.set_xlim([box[0] - cd / 10, box[2] + cd / 10])
|
|
166
172
|
ax.set_ylim([box[1] - cd / 10, box[3] + cd / 10])
|
|
173
|
+
ax.set_aspect("equal")
|
|
167
174
|
m['ax'] = ax # plotting objects saved
|
|
168
175
|
return ax
|
|
169
176
|
|
|
177
|
+
def show(m):
|
|
178
|
+
"""
|
|
179
|
+
Show the plot.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
m
|
|
184
|
+
Model dictionary.
|
|
185
|
+
"""
|
|
186
|
+
if not ('fig' in m):
|
|
187
|
+
raise RuntimeError('Please first call plots.setup(m)')
|
|
188
|
+
fig = m['fig']
|
|
189
|
+
ax = m['ax']
|
|
190
|
+
ax.set_aspect("equal")
|
|
191
|
+
plt.show()
|
|
170
192
|
|
|
171
193
|
def _area_extrema(all_members):
|
|
172
194
|
min_area = numpy.inf
|
|
@@ -410,6 +432,7 @@ def _plot_member_ids_2d(m):
|
|
|
410
432
|
i, j = m["joints"][connectivity[0]], m["joints"][connectivity[1]]
|
|
411
433
|
ci, cj = i["coordinates"], j["coordinates"]
|
|
412
434
|
xm = (ci + cj) / 2.0
|
|
435
|
+
ax.scatter(xm[0], xm[1], alpha=0)
|
|
413
436
|
ax.text(xm[0], xm[1], str(jid),
|
|
414
437
|
bbox=dict(facecolor='white', boxstyle='square'))
|
|
415
438
|
if "beam_members" in m:
|
|
@@ -419,6 +442,7 @@ def _plot_member_ids_2d(m):
|
|
|
419
442
|
i, j = m["joints"][connectivity[0]], m["joints"][connectivity[1]]
|
|
420
443
|
ci, cj = i["coordinates"], j["coordinates"]
|
|
421
444
|
xm = (ci + cj) / 2.0
|
|
445
|
+
ax.scatter(xm[0], xm[1], alpha=0)
|
|
422
446
|
ax.text(xm[0], xm[1], str(jid),
|
|
423
447
|
bbox=dict(facecolor='white', boxstyle='square'))
|
|
424
448
|
return ax
|
|
@@ -433,6 +457,7 @@ def _plot_member_ids_3d(m):
|
|
|
433
457
|
i, j = m["joints"][connectivity[0]], m["joints"][connectivity[1]]
|
|
434
458
|
ci, cj = i["coordinates"], j["coordinates"]
|
|
435
459
|
xm = (ci + cj) / 2.0
|
|
460
|
+
ax.scatter(xm[0], xm[1], xm[2], alpha=0)
|
|
436
461
|
ax.text(xm[0], xm[1], xm[2], str(jid),
|
|
437
462
|
bbox=dict(facecolor='white', boxstyle='square'))
|
|
438
463
|
if "beam_members" in m:
|
|
@@ -442,6 +467,7 @@ def _plot_member_ids_3d(m):
|
|
|
442
467
|
i, j = m["joints"][connectivity[0]], m["joints"][connectivity[1]]
|
|
443
468
|
ci, cj = i["coordinates"], j["coordinates"]
|
|
444
469
|
xm = (ci + cj) / 2.0
|
|
470
|
+
ax.scatter(xm[0], xm[1], xm[2], alpha=0)
|
|
445
471
|
ax.text(xm[0], xm[1], xm[2], str(jid),
|
|
446
472
|
bbox=dict(facecolor='white', boxstyle='square'))
|
|
447
473
|
return ax
|
|
@@ -506,6 +532,10 @@ def plot_joint_ids(m, offsets = None):
|
|
|
506
532
|
ax = m['ax']
|
|
507
533
|
for j in m["joints"].values():
|
|
508
534
|
if m["dim"] == 3:
|
|
535
|
+
ax.scatter(
|
|
536
|
+
j["coordinates"][0] + offsets[0],
|
|
537
|
+
j["coordinates"][1] + offsets[1],
|
|
538
|
+
j["coordinates"][2] + offsets[2], alpha=0)
|
|
509
539
|
ax.text(
|
|
510
540
|
j["coordinates"][0] + offsets[0],
|
|
511
541
|
j["coordinates"][1] + offsets[1],
|
|
@@ -514,6 +544,9 @@ def plot_joint_ids(m, offsets = None):
|
|
|
514
544
|
bbox=dict(facecolor='white', boxstyle='circle')
|
|
515
545
|
)
|
|
516
546
|
else:
|
|
547
|
+
ax.scatter(
|
|
548
|
+
j["coordinates"][0] + offsets[0],
|
|
549
|
+
j["coordinates"][1] + offsets[1], alpha=0)
|
|
517
550
|
ax.text(j["coordinates"][0] + offsets[0],
|
|
518
551
|
j["coordinates"][1] + offsets[1],
|
|
519
552
|
str(j["jid"]),
|
|
@@ -1338,58 +1371,6 @@ def plot_rotation_supports(m, scale=0.0, radius=0.0, shortest_arrow=1.0e-6):
|
|
|
1338
1371
|
)
|
|
1339
1372
|
return ax
|
|
1340
1373
|
|
|
1341
|
-
|
|
1342
|
-
def show(m):
|
|
1343
|
-
"""
|
|
1344
|
-
Show the plot.
|
|
1345
|
-
|
|
1346
|
-
Parameters
|
|
1347
|
-
----------
|
|
1348
|
-
m
|
|
1349
|
-
Model dictionary.
|
|
1350
|
-
|
|
1351
|
-
"""
|
|
1352
|
-
if not ('fig' in m):
|
|
1353
|
-
raise RuntimeError('Please first call plots.setup(m)')
|
|
1354
|
-
fig = m['fig']
|
|
1355
|
-
ax = m['ax']
|
|
1356
|
-
ax.set_aspect("equal")
|
|
1357
|
-
box = bounding_box(m)
|
|
1358
|
-
cd = characteristic_dimension(m)
|
|
1359
|
-
if m["dim"] == 3:
|
|
1360
|
-
ax.set_xlim([box[0] - cd / 10, box[3] + cd / 10])
|
|
1361
|
-
ax.set_ylim([box[1] - cd / 10, box[4] + cd / 10])
|
|
1362
|
-
ax.set_zlim([box[2] - cd / 10, box[5] + cd / 10])
|
|
1363
|
-
ax.set_xlabel("X")
|
|
1364
|
-
ax.set_ylabel("Y")
|
|
1365
|
-
ax.set_zlabel("Z")
|
|
1366
|
-
else:
|
|
1367
|
-
ax.set_xlim([box[0] - cd / 10, box[2] + cd / 10])
|
|
1368
|
-
ax.set_ylim([box[1] - cd / 10, box[3] + cd / 10])
|
|
1369
|
-
ax.set_xlabel("X")
|
|
1370
|
-
ax.set_ylabel("Z")
|
|
1371
|
-
# zoom in 3d will change ticks
|
|
1372
|
-
def update_ticks(ax, n_max=6):
|
|
1373
|
-
dim = m['dim']
|
|
1374
|
-
# set an appropriate number of major ticks for each axis based on span
|
|
1375
|
-
if dim == 2:
|
|
1376
|
-
for axis in (ax.xaxis, ax.yaxis,):
|
|
1377
|
-
axis.set_major_locator(MaxNLocator(n_max))
|
|
1378
|
-
else:
|
|
1379
|
-
for axis in (ax.xaxis, ax.yaxis, ax.zaxis):
|
|
1380
|
-
axis.set_major_locator(MaxNLocator(n_max))
|
|
1381
|
-
fig.canvas.draw_idle()
|
|
1382
|
-
|
|
1383
|
-
def on_limits_change(event_ax):
|
|
1384
|
-
# event_ax is the axis object passed by the callback
|
|
1385
|
-
update_ticks(ax, n_max=6)
|
|
1386
|
-
# Connect per-axis limit-change callbacks
|
|
1387
|
-
ax.callbacks.connect('xlim_changed', on_limits_change)
|
|
1388
|
-
ax.callbacks.connect('ylim_changed', on_limits_change)
|
|
1389
|
-
ax.callbacks.connect('zlim_changed', on_limits_change)
|
|
1390
|
-
plt.show()
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
1374
|
def plot_reaction_forces(m, scale=0.0):
|
|
1394
1375
|
"""
|
|
1395
1376
|
Plot the reaction forces at the joints.
|
|
@@ -293,7 +293,7 @@ class UnitTestsPlanarFrames(unittest.TestCase):
|
|
|
293
293
|
"""
|
|
294
294
|
pystran - Python package for structural analysis with trusses and beams
|
|
295
295
|
|
|
296
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
296
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
297
297
|
|
|
298
298
|
# Two story planar frame vibration
|
|
299
299
|
|
|
@@ -382,7 +382,7 @@ class UnitTestsPlanarFrames(unittest.TestCase):
|
|
|
382
382
|
"""
|
|
383
383
|
pystran - Python package for structural analysis with trusses and beams
|
|
384
384
|
|
|
385
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
385
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
386
386
|
|
|
387
387
|
# Natural Frequency of Mass supported by a Beam on Springs
|
|
388
388
|
|
|
@@ -213,7 +213,7 @@ class UnitTestsPlanarTrusses(unittest.TestCase):
|
|
|
213
213
|
"""
|
|
214
214
|
pystran - Python package for structural analysis with trusses and beams
|
|
215
215
|
|
|
216
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
216
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
217
217
|
|
|
218
218
|
# Truss with a combination of loads
|
|
219
219
|
|
|
@@ -808,7 +808,7 @@ class UnitTestsSpaceFrames(unittest.TestCase):
|
|
|
808
808
|
"""
|
|
809
809
|
pystran - Python package for structural analysis with trusses and beams
|
|
810
810
|
|
|
811
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
811
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
812
812
|
|
|
813
813
|
# Two story 3D Frame vibration
|
|
814
814
|
|
|
@@ -949,7 +949,7 @@ class UnitTestsSpaceFrames(unittest.TestCase):
|
|
|
949
949
|
"""
|
|
950
950
|
pystran - Python package for structural analysis with trusses and beams
|
|
951
951
|
|
|
952
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
952
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
953
953
|
|
|
954
954
|
# Spatial frame with a hinge and spring supports
|
|
955
955
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pystran - Python package for structural analysis with trusses and beams.
|
|
3
3
|
|
|
4
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
4
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
5
5
|
|
|
6
6
|
# Three-bar truss example
|
|
7
7
|
|
|
8
8
|
## Problem description:
|
|
9
9
|
|
|
10
10
|
Structure consisting of three truss members. This tutorial mirrors the tutorial
|
|
11
|
-
01_three_bars_tut.py, but uses the alternative (mixed
|
|
12
|
-
creating the model.
|
|
11
|
+
01_three_bars_tut.py, but uses the alternative (mixed, integers and
|
|
12
|
+
strings) identifiers for creating the model.
|
|
13
13
|
|
|
14
14
|
Displacements and internal forces are provided in the verification manual.
|
|
15
15
|
|
|
@@ -31,7 +31,7 @@ from pystran import plots
|
|
|
31
31
|
|
|
32
32
|
# Now we create the model `m`, which is a dictionary that contains all the
|
|
33
33
|
# constituent parts of the system. The model is created for a planar structure
|
|
34
|
-
# (2). The deformation is assumed to occur in the plane `x-z`.
|
|
34
|
+
# (the 2). The deformation is assumed to occur in the plane `x-z`.
|
|
35
35
|
m = model.create(2)
|
|
36
36
|
freedoms = m["freedoms"]
|
|
37
37
|
|
|
@@ -46,8 +46,7 @@ model.add_joint(m, "B", [0.0, 20.0])
|
|
|
46
46
|
model.add_joint(m, "C", [0.0, 10.0])
|
|
47
47
|
model.add_joint(m, "D", (+10.0, 0.0))
|
|
48
48
|
|
|
49
|
-
#
|
|
50
|
-
# bars.
|
|
49
|
+
# The material parameters and the cross sectional area of the bars.
|
|
51
50
|
E = 30000000.0
|
|
52
51
|
A = 0.65700000
|
|
53
52
|
|
|
@@ -58,6 +57,8 @@ s1 = section.truss_section("steel", E, A)
|
|
|
58
57
|
# lists of [start, end] joints. The section is also provided. Note that one
|
|
59
58
|
# member is called "m1" and the other two are numbered. Also, the connectivity
|
|
60
59
|
# is supplied in one case as tuple, in the other two cases as lists.
|
|
60
|
+
# This is purely to show off the flexibility, there are no actual such requirements.
|
|
61
|
+
|
|
61
62
|
model.add_truss_member(m, "m1", ["A", "B"], s1)
|
|
62
63
|
model.add_truss_member(m, 2, ("A", "C"), s1)
|
|
63
64
|
model.add_truss_member(m, 3, ["A", "D"], s1)
|
|
@@ -74,12 +75,12 @@ ax = plots.setup(m)
|
|
|
74
75
|
plots.plot_members(m)
|
|
75
76
|
plots.plot_member_orientation(m)
|
|
76
77
|
plots.plot_joint_ids(m)
|
|
77
|
-
plots.plot_translation_supports(m)
|
|
78
78
|
ax.set_title("Structure")
|
|
79
79
|
plots.show(m)
|
|
80
80
|
|
|
81
81
|
# At this point we can visualize the supports. The translation supports are
|
|
82
|
-
# shown with arrow heads.
|
|
82
|
+
# shown with arrow heads. Only when the displacements prescribed are non zero,
|
|
83
|
+
# the arrows will have visible shafts.
|
|
83
84
|
ax = plots.setup(m)
|
|
84
85
|
plots.plot_joint_ids(m)
|
|
85
86
|
plots.plot_translation_supports(m)
|
|
@@ -90,8 +91,8 @@ plots.show(m)
|
|
|
90
91
|
model.add_load(jA, 0, -10000.0)
|
|
91
92
|
model.add_load(jA, 1, -10000.0 / 2.0)
|
|
92
93
|
|
|
93
|
-
# The model is shown graphically, members are displayed with the member
|
|
94
|
-
# The applied forces are also shown.
|
|
94
|
+
# The model is shown graphically, members are displayed with the member
|
|
95
|
+
# numbers attached. The applied forces are also shown.
|
|
95
96
|
plots.setup(m)
|
|
96
97
|
plots.plot_members(m)
|
|
97
98
|
plots.plot_applied_forces(m, 1 / 3000.0)
|
|
@@ -119,7 +120,9 @@ if norm(jA["displacements"] - [-0.0033325938, -0.001591621]) > 1.0e-3:
|
|
|
119
120
|
print("Displacement calculation OK")
|
|
120
121
|
|
|
121
122
|
# The forces in the bars can be calculated using the strain-displacement matrix
|
|
122
|
-
# to compute the strain, from which we can evaluate the force.
|
|
123
|
+
# to compute the strain, from which we can evaluate the force. (Note there
|
|
124
|
+
# is a function to do this, here we show how it could be done from
|
|
125
|
+
# individual components.)
|
|
123
126
|
for b in m["truss_members"].values():
|
|
124
127
|
connectivity = b["connectivity"]
|
|
125
128
|
i, j = m["joints"][connectivity[0]], m["joints"][connectivity[1]]
|
|
@@ -129,7 +132,7 @@ for b in m["truss_members"].values():
|
|
|
129
132
|
eps = dot(B, u)
|
|
130
133
|
print("Bar " + str(connectivity) + " force = ", E * A * eps[0])
|
|
131
134
|
|
|
132
|
-
# The
|
|
135
|
+
# The same calculation, made easier with the `truss_axial_force`
|
|
133
136
|
# function. That function does what was described in the loop above.
|
|
134
137
|
for b in m["truss_members"].values():
|
|
135
138
|
connectivity = b["connectivity"]
|
|
@@ -140,7 +143,6 @@ for b in m["truss_members"].values():
|
|
|
140
143
|
# These are the reference values of the forces from the book.
|
|
141
144
|
print("Reference forces: ", -0.656854250e4, -0.48528137e4, -0.15685425e4)
|
|
142
145
|
|
|
143
|
-
|
|
144
146
|
# The solution is visualized with deformed shape.
|
|
145
147
|
plots.setup(m)
|
|
146
148
|
plots.plot_members(m)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pystran - Python package for structural analysis with trusses and beams
|
|
3
3
|
|
|
4
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
4
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
5
5
|
|
|
6
6
|
# Continuous beam with two spans
|
|
7
7
|
|
|
8
8
|
## Problem description:
|
|
9
9
|
|
|
10
10
|
Continuous simply supported beam with two spans. The beam is loaded with
|
|
11
|
-
moments at the
|
|
11
|
+
moments at the joints.
|
|
12
12
|
|
|
13
|
-
Displacements and internal forces are provided in the
|
|
13
|
+
Displacements and internal forces are provided in the literature.
|
|
14
14
|
|
|
15
15
|
## References
|
|
16
16
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pystran - Python package for structural analysis with trusses and beams
|
|
3
3
|
|
|
4
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
4
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
5
5
|
|
|
6
6
|
# Weaver 3D frame benchmark
|
|
7
7
|
|
|
@@ -122,7 +122,8 @@ model.add_beam_member(m, 3, [2, 4], sect_2)
|
|
|
122
122
|
|
|
123
123
|
|
|
124
124
|
# Now we can plot the geometry of the structure. We show the members, the
|
|
125
|
-
# member numbers, and the orientations of the local coordinate systems.
|
|
125
|
+
# member numbers, and the orientations of the local coordinate systems.
|
|
126
|
+
# Also the joint numbers are displayed.
|
|
126
127
|
|
|
127
128
|
ax = plots.setup(m)
|
|
128
129
|
plots.plot_members(m)
|
|
@@ -163,7 +164,7 @@ plots.show(m)
|
|
|
163
164
|
# Now we can solve the static equilibrium of the frame. First we number the
|
|
164
165
|
# degrees of freedom, and then we call the solver that will construct the
|
|
165
166
|
# stiffness matrix, the right-hand side vector of applied generalized forces
|
|
166
|
-
# (forces plus moments), and solve
|
|
167
|
+
# (forces plus moments), and solve the system of equations. The solution is then
|
|
167
168
|
# distributed to the joints.
|
|
168
169
|
model.number_dofs(m)
|
|
169
170
|
model.solve_statics(m)
|
|
@@ -177,12 +178,12 @@ for jid in [1, 2]:
|
|
|
177
178
|
# The displacements of the joints can be compared to the reference values.
|
|
178
179
|
# These are the displacements of joint 1:
|
|
179
180
|
ref1 = [0.22267, 0.00016, -0.17182, -0.00255, 0.00217, -0.00213]
|
|
180
|
-
if norm(m["joints"][1]["displacements"] - ref1) > 1.0e-
|
|
181
|
+
if norm(m["joints"][1]["displacements"] - ref1) > 1.0e-2 * norm(ref1):
|
|
181
182
|
raise ValueError("Displacement calculation error")
|
|
182
183
|
print("Displacement calculation OK")
|
|
183
184
|
# These are the displacements of joint 2:
|
|
184
185
|
ref2 = [0.22202, -0.48119, -0.70161, -0.00802, 0.00101, -0.00435]
|
|
185
|
-
if norm(m["joints"][2]["displacements"] - ref2) > 1.0e-
|
|
186
|
+
if norm(m["joints"][2]["displacements"] - ref2) > 1.0e-2 * norm(ref2):
|
|
186
187
|
raise ValueError("Displacement calculation error")
|
|
187
188
|
print("Displacement calculation OK")
|
|
188
189
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pystran - Python package for structural analysis with trusses and beams
|
|
3
3
|
|
|
4
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
4
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
5
5
|
|
|
6
6
|
# Example of a support-settlement problem
|
|
7
7
|
|
|
@@ -33,7 +33,7 @@ from pystran import plots
|
|
|
33
33
|
E = 2.9e6
|
|
34
34
|
I = 1.0
|
|
35
35
|
A = 1.0 # cross-sectional area does not influence the results
|
|
36
|
-
L = 10 * 12 # span in
|
|
36
|
+
L = 10 * 12 # span in inches
|
|
37
37
|
|
|
38
38
|
# The model is created as two dimensional.
|
|
39
39
|
m = model.create(2)
|
|
@@ -46,7 +46,7 @@ model.add_joint(m, 3, [2 * L, 0.0])
|
|
|
46
46
|
# The left hand side is clamped (all degrees of freedom set to zero), the other
|
|
47
47
|
# joints are simply supported.
|
|
48
48
|
model.add_support(m["joints"][1], freedoms.ALL_DOFS)
|
|
49
|
-
# The middle support moves down by 0.25 inches (notice the non
|
|
49
|
+
# The middle support moves down by 0.25 inches (notice the non-zero value of the
|
|
50
50
|
# enforced displacement).
|
|
51
51
|
model.add_support(m["joints"][2], freedoms.U2, -0.25)
|
|
52
52
|
model.add_support(m["joints"][3], freedoms.U2)
|
|
@@ -61,7 +61,7 @@ model.add_beam_member(m, 2, [2, 3], s1)
|
|
|
61
61
|
# scale doesn't work well in this case).
|
|
62
62
|
ax = plots.setup(m, set_limits=True)
|
|
63
63
|
plots.plot_members(m)
|
|
64
|
-
plots.plot_translation_supports(m, 50)
|
|
64
|
+
plots.plot_translation_supports(m, scale=50)
|
|
65
65
|
ax.set_title("Supports (magnified 50x)")
|
|
66
66
|
plots.show(m)
|
|
67
67
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pystran - Python package for structural analysis with trusses and beams
|
|
3
3
|
|
|
4
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
4
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
5
5
|
|
|
6
6
|
# Example of a frame with a hinge
|
|
7
7
|
|
|
@@ -28,10 +28,10 @@ from pystran import plots
|
|
|
28
28
|
# US customary units, inches, pounds, seconds are assumed.
|
|
29
29
|
|
|
30
30
|
# The book gives the product of the modulus of elasticity and the moment of
|
|
31
|
-
# inertia as 2.
|
|
31
|
+
# inertia as 2.9e8.
|
|
32
32
|
E = 29e6
|
|
33
33
|
I = 100.0
|
|
34
|
-
A = 10.0 # cross-sectional area does not influence the results
|
|
34
|
+
A = 10.0 # cross-sectional area does not influence the results (much)
|
|
35
35
|
L = 10 * 12 # span in inches
|
|
36
36
|
|
|
37
37
|
m = model.create(2)
|
|
@@ -45,9 +45,11 @@ model.add_joint(m, 4, [L, 0.0])
|
|
|
45
45
|
|
|
46
46
|
# There needs to be a hinge (not transferring bending moments, but ensuring
|
|
47
47
|
# continuity of displacements) at the joint 2. We add another joint, 5, at the
|
|
48
|
-
# same location
|
|
48
|
+
# same location.
|
|
49
49
|
model.add_joint(m, 5, [0, L])
|
|
50
50
|
|
|
51
|
+
# Now we link the degrees of freedom that need to be the same --
|
|
52
|
+
# the translations are the same, rotations can be different.
|
|
51
53
|
# We supply the list of joints that need to be linked (2 and 5), and the
|
|
52
54
|
# degrees of freedom that are to be the same.
|
|
53
55
|
model.add_dof_links(m, [2, 5], freedoms.U1)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pystran - Python package for structural analysis with trusses and beams
|
|
3
3
|
|
|
4
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
4
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
5
5
|
|
|
6
6
|
# Example of a two-dimensional frame problem with thermal gradient loading
|
|
7
7
|
|
|
@@ -103,7 +103,7 @@ M_T = CTE * (Ttop - Tbot) / depth * E * I
|
|
|
103
103
|
model.add_load(i, freedoms.UR3, -M_T)
|
|
104
104
|
model.add_load(j, freedoms.UR3, +M_T)
|
|
105
105
|
|
|
106
|
-
# The nodal moments can be visualized with the following plot.
|
|
106
|
+
# The applied nodal moments can be visualized with the following plot.
|
|
107
107
|
ax = plots.setup(m)
|
|
108
108
|
plots.plot_members(m)
|
|
109
109
|
ax = plots.plot_applied_moments(m, 0.0, 50)
|
|
@@ -158,7 +158,7 @@ if abs((f["Qzj"] + 1710) / 1710) > 1e-2:
|
|
|
158
158
|
if abs((f["Myj"] + M_T) / 40171 - 1) > 1e-2:
|
|
159
159
|
raise ValueError("Member 2, joint i, bending moment error")
|
|
160
160
|
|
|
161
|
-
#
|
|
161
|
+
# The diagrams below are for the discrete model that is loaded with the
|
|
162
162
|
# negative reactions at the fixed joints. These resultants are not combined with
|
|
163
163
|
# the thermal forces, they represent the response of the frame with the nodal loads.
|
|
164
164
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pystran - Python package for structural analysis with trusses and beams
|
|
3
3
|
|
|
4
|
-
(C) 2025, Petr Krysl, pkrysl@ucsd.edu
|
|
4
|
+
(C) 2025-2026, Petr Krysl, pkrysl@ucsd.edu
|
|
5
5
|
|
|
6
6
|
# Two story planar frame vibration
|
|
7
7
|
|
|
@@ -32,6 +32,7 @@ B = 4.8e-3
|
|
|
32
32
|
A = H * B
|
|
33
33
|
I = H * B**3 / 12
|
|
34
34
|
|
|
35
|
+
# Create the model in usual fashion.
|
|
35
36
|
m = model.create(2)
|
|
36
37
|
freedoms = m["freedoms"]
|
|
37
38
|
|
|
@@ -65,7 +66,8 @@ plots.show(m)
|
|
|
65
66
|
# All members will now be refined into eight finite elements. Without the
|
|
66
67
|
# refinement, the reference solutions cannot be reproduced: there simply
|
|
67
68
|
# wouldn't be enough degrees of freedom. Unfortunately the reference publication
|
|
68
|
-
# does not mention
|
|
69
|
+
# does not mention with how many finite elements used per member
|
|
70
|
+
# the reference solution was calculated.
|
|
69
71
|
nref = 8
|
|
70
72
|
for i in range(6):
|
|
71
73
|
model.refine_member(m, i + 1, nref)
|
|
@@ -26,8 +26,9 @@ The test-bed was designed and manufactured by ONERA, France.
|
|
|
26
26
|

|
|
27
27
|
|
|
28
28
|
This tutorial includes also the constraining layer of the wing, which
|
|
29
|
-
was not included in the "
|
|
30
|
-
The effect of the constraining layer may be overestimated
|
|
29
|
+
was not included in the "19_garteur_air_frame_statics_tut.py" tutorial.
|
|
30
|
+
The effect of the constraining layer may be overestimated
|
|
31
|
+
(the frequencies may end up a little bit too high) when computing
|
|
31
32
|
the natural frequencies: the flexibility of the viscoelastic layer is omitted.
|
|
32
33
|
|
|
33
34
|
References
|
|
@@ -26,7 +26,7 @@ The test-bed was designed and manufactured by ONERA, France.
|
|
|
26
26
|

|
|
27
27
|
|
|
28
28
|
This tutorial is simplified: no damping, no constraining layer, no
|
|
29
|
-
added masses (not on the drums, no masses for connecting
|
|
29
|
+
added masses (not on the drums, no masses for connecting fixtures).
|
|
30
30
|
|
|
31
31
|
References
|
|
32
32
|
|
pystran-0.2.0/Job-1.inp
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
*Heading
|
|
2
|
-
** Job name: Job-1 Model name: Model-1
|
|
3
|
-
** Generated by: Abaqus/CAE Learning Edition 2025
|
|
4
|
-
*Preprint, echo=NO, model=NO, history=NO, contact=NO
|
|
5
|
-
**
|
|
6
|
-
** PARTS
|
|
7
|
-
**
|
|
8
|
-
*Part, name=Part-frame
|
|
9
|
-
*Node
|
|
10
|
-
1, 0., 0., 180.
|
|
11
|
-
2, 180., 0., 180.
|
|
12
|
-
3, 180., 180., 180.
|
|
13
|
-
4, 180., 0., 0.
|
|
14
|
-
*Element, type=B33
|
|
15
|
-
1, 1, 2
|
|
16
|
-
2, 2, 3
|
|
17
|
-
3, 2, 4
|
|
18
|
-
*Nset, nset=Set-1
|
|
19
|
-
1, 2
|
|
20
|
-
*Elset, elset=Set-1
|
|
21
|
-
1,
|
|
22
|
-
*Nset, nset=Set-2
|
|
23
|
-
1, 2
|
|
24
|
-
*Elset, elset=Set-2
|
|
25
|
-
1,
|
|
26
|
-
*Nset, nset=Set-3
|
|
27
|
-
1, 2
|
|
28
|
-
*Elset, elset=Set-3
|
|
29
|
-
1,
|
|
30
|
-
*Nset, nset=Set-4
|
|
31
|
-
2, 3
|
|
32
|
-
*Elset, elset=Set-4
|
|
33
|
-
2,
|
|
34
|
-
*Nset, nset=Set-5
|
|
35
|
-
2, 3
|
|
36
|
-
*Elset, elset=Set-5
|
|
37
|
-
2,
|
|
38
|
-
*Nset, nset=Set-6
|
|
39
|
-
2, 4
|
|
40
|
-
*Elset, elset=Set-6
|
|
41
|
-
3,
|
|
42
|
-
*Nset, nset=Set-7
|
|
43
|
-
2, 4
|
|
44
|
-
*Elset, elset=Set-7
|
|
45
|
-
3,
|
|
46
|
-
** Section: Section-member Profile: Profile-general
|
|
47
|
-
*Beam General Section, elset=Set-1, material=Material-Steel, section=GENERAL
|
|
48
|
-
7.08, 82.8, 0., 18.3, 0.35
|
|
49
|
-
0.,1.,0.
|
|
50
|
-
** Section: Section-member Profile: Profile-general
|
|
51
|
-
*Beam General Section, elset=Set-4, material=Material-Steel, section=GENERAL
|
|
52
|
-
7.08, 82.8, 0., 18.3, 0.35
|
|
53
|
-
1.,0.,0.
|
|
54
|
-
** Section: Section-member Profile: Profile-general
|
|
55
|
-
*Beam General Section, elset=Set-7, material=Material-Steel, section=GENERAL
|
|
56
|
-
7.08, 82.8, 0., 18.3, 0.35
|
|
57
|
-
0.,1.,0.
|
|
58
|
-
*End Part
|
|
59
|
-
**
|
|
60
|
-
**
|
|
61
|
-
** ASSEMBLY
|
|
62
|
-
**
|
|
63
|
-
*Assembly, name=Assembly
|
|
64
|
-
**
|
|
65
|
-
*Instance, name=Part-frame-1, part=Part-frame
|
|
66
|
-
*End Instance
|
|
67
|
-
**
|
|
68
|
-
*Nset, nset=Set-fixed, instance=Part-frame-1
|
|
69
|
-
1, 3, 4
|
|
70
|
-
*Nset, nset=Set-loaded, instance=Part-frame-1
|
|
71
|
-
2,
|
|
72
|
-
*End Assembly
|
|
73
|
-
**
|
|
74
|
-
** MATERIALS
|
|
75
|
-
**
|
|
76
|
-
*Material, name=Material-Steel
|
|
77
|
-
*Elastic
|
|
78
|
-
2.9e+07, 0.3
|
|
79
|
-
** ----------------------------------------------------------------
|
|
80
|
-
**
|
|
81
|
-
** STEP: Step-statics
|
|
82
|
-
**
|
|
83
|
-
*Step, name=Step-statics, nlgeom=NO, perturbation
|
|
84
|
-
*Static
|
|
85
|
-
**
|
|
86
|
-
** BOUNDARY CONDITIONS
|
|
87
|
-
**
|
|
88
|
-
** Name: BC-fixed Type: Symmetry/Antisymmetry/Encastre
|
|
89
|
-
*Boundary
|
|
90
|
-
Set-fixed, ENCASTRE
|
|
91
|
-
**
|
|
92
|
-
** LOADS
|
|
93
|
-
**
|
|
94
|
-
** Name: Load-moment Type: Moment
|
|
95
|
-
*Cload
|
|
96
|
-
Set-loaded, 5, 492000.
|
|
97
|
-
**
|
|
98
|
-
** OUTPUT REQUESTS
|
|
99
|
-
**
|
|
100
|
-
**
|
|
101
|
-
** FIELD OUTPUT: F-Output-1
|
|
102
|
-
**
|
|
103
|
-
*Output, field
|
|
104
|
-
*Node Output, variable=PRESELECT
|
|
105
|
-
*Element Output, directions=YES
|
|
106
|
-
LE, S, SF
|
|
107
|
-
**
|
|
108
|
-
** HISTORY OUTPUT: H-Output-1
|
|
109
|
-
**
|
|
110
|
-
*Output, history, variable=PRESELECT
|
|
111
|
-
*End Step
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|