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.
Files changed (98) hide show
  1. {pystran-0.2.0 → pystran-0.2.2}/PKG-INFO +1 -1
  2. {pystran-0.2.0 → pystran-0.2.2}/pyproject.toml +1 -1
  3. {pystran-0.2.0 → pystran-0.2.2}/pystran/plots.py +33 -52
  4. {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_planar_frame.py +2 -2
  5. {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_planar_truss.py +1 -1
  6. {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_space_frame.py +2 -2
  7. {pystran-0.2.0 → pystran-0.2.2}/tutorials/00_matrices_tut.py +1 -1
  8. {pystran-0.2.0 → pystran-0.2.2}/tutorials/01_alt_three_bars_tut.py +15 -13
  9. {pystran-0.2.0 → pystran-0.2.2}/tutorials/01_three_bars_tut.py +1 -1
  10. {pystran-0.2.0 → pystran-0.2.2}/tutorials/02_continuous_beam_2_spans_consist_tut.py +3 -3
  11. {pystran-0.2.0 → pystran-0.2.2}/tutorials/03_weaver_1_tut.py +6 -5
  12. {pystran-0.2.0 → pystran-0.2.2}/tutorials/04_supp_settle_tut.py +4 -4
  13. {pystran-0.2.0 → pystran-0.2.2}/tutorials/05_hinge_frame_tut.py +6 -4
  14. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut.py +1 -1
  15. {pystran-0.2.0 → pystran-0.2.2}/tutorials/07_frame_thermal_tut.py +3 -3
  16. {pystran-0.2.0 → pystran-0.2.2}/tutorials/08_alt_refine_member_tut.py +1 -1
  17. {pystran-0.2.0 → pystran-0.2.2}/tutorials/08_refine_member_tut.py +1 -1
  18. {pystran-0.2.0 → pystran-0.2.2}/tutorials/09_SDLX_01_89_vibration_tut.py +4 -2
  19. {pystran-0.2.0 → pystran-0.2.2}/tutorials/10_truss_5_vibration_tut.py +1 -1
  20. {pystran-0.2.0 → pystran-0.2.2}/tutorials/11_samcef_frame_3d_vibration_tut.py +1 -1
  21. {pystran-0.2.0 → pystran-0.2.2}/tutorials/12_timo_beam_on_springs_tut.py +1 -1
  22. {pystran-0.2.0 → pystran-0.2.2}/tutorials/13_hinged_3d_frame_tut.py +1 -1
  23. {pystran-0.2.0 → pystran-0.2.2}/tutorials/14_truss_skew_support_tut.py +1 -1
  24. {pystran-0.2.0 → pystran-0.2.2}/tutorials/15_penalty_supports_tut.py +1 -1
  25. {pystran-0.2.0 → pystran-0.2.2}/tutorials/16_distributed_load_continuous_beam_tut.py +1 -1
  26. {pystran-0.2.0 → pystran-0.2.2}/tutorials/17_arch_out_of_plane_tut.py +1 -1
  27. {pystran-0.2.0 → pystran-0.2.2}/tutorials/18_SSLL05_89_tut.py +1 -1
  28. {pystran-0.2.0 → pystran-0.2.2}/tutorials/19_garteur_air_frame_vibration_ref_tut.py +3 -2
  29. {pystran-0.2.0 → pystran-0.2.2}/tutorials/19_garteur_air_frame_vibration_simpl_tut.py +1 -1
  30. pystran-0.2.0/Job-1.inp +0 -111
  31. {pystran-0.2.0 → pystran-0.2.2}/.github/workflows/pubflow.yml +0 -0
  32. {pystran-0.2.0 → pystran-0.2.2}/.github/workflows/sphinx.yml +0 -0
  33. {pystran-0.2.0 → pystran-0.2.2}/.gitignore +0 -0
  34. {pystran-0.2.0 → pystran-0.2.2}/LICENSE +0 -0
  35. {pystran-0.2.0 → pystran-0.2.2}/README.md +0 -0
  36. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-cl-rb.png +0 -0
  37. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-cl.png +0 -0
  38. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-ss-rb.png +0 -0
  39. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d-ss.png +0 -0
  40. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam2d.png +0 -0
  41. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_3d_stiffness_check.ipynb +0 -0
  42. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_3d_stiffness_check.py +0 -0
  43. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_curvatures.ipynb +0 -0
  44. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_curvatures.py +0 -0
  45. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_shape.py +0 -0
  46. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_shape_-1_+1.ipynb +0 -0
  47. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_shape_0_1.ipynb +0 -0
  48. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_stiffness.ipynb +0 -0
  49. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_stiffness.py +0 -0
  50. {pystran-0.2.0 → pystran-0.2.2}/derivations/beam_stiffness_via_flexibility.ipynb +0 -0
  51. {pystran-0.2.0 → pystran-0.2.2}/derivations/beams.pdf +0 -0
  52. {pystran-0.2.0 → pystran-0.2.2}/derivations/clamped_beam.py +0 -0
  53. {pystran-0.2.0 → pystran-0.2.2}/derivations/clamped_beam_w_triangulardl.py +0 -0
  54. {pystran-0.2.0 → pystran-0.2.2}/derivations/clamped_beam_w_udl.py +0 -0
  55. {pystran-0.2.0 → pystran-0.2.2}/derivations/context.py +0 -0
  56. {pystran-0.2.0 → pystran-0.2.2}/derivations/moment_and_other_releases.py +0 -0
  57. {pystran-0.2.0 → pystran-0.2.2}/doc_requirements.txt +0 -0
  58. {pystran-0.2.0 → pystran-0.2.2}/docs/issues-and-ideas.md +0 -0
  59. {pystran-0.2.0 → pystran-0.2.2}/docs/make_docs.md +0 -0
  60. {pystran-0.2.0 → pystran-0.2.2}/docs/source/conf.py +0 -0
  61. {pystran-0.2.0 → pystran-0.2.2}/docs/splash.png +0 -0
  62. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/ScreenHunter 24.png +0 -0
  63. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/console.png +0 -0
  64. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/from_existing.png +0 -0
  65. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/graphics_settings.png +0 -0
  66. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/new_project.png +0 -0
  67. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/open_tutorial.png +0 -0
  68. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/project_pane.png +0 -0
  69. {pystran-0.2.0 → pystran-0.2.2}/docs/spyder/spyder.md +0 -0
  70. {pystran-0.2.0 → pystran-0.2.2}/docs/terminal/folder_and_run.png +0 -0
  71. {pystran-0.2.0 → pystran-0.2.2}/docs/terminal/terminal.md +0 -0
  72. {pystran-0.2.0 → pystran-0.2.2}/pystran/Abaqus_import.py +0 -0
  73. {pystran-0.2.0 → pystran-0.2.2}/pystran/__init__.py +0 -0
  74. {pystran-0.2.0 → pystran-0.2.2}/pystran/assemble.py +0 -0
  75. {pystran-0.2.0 → pystran-0.2.2}/pystran/beam.py +0 -0
  76. {pystran-0.2.0 → pystran-0.2.2}/pystran/gauss.py +0 -0
  77. {pystran-0.2.0 → pystran-0.2.2}/pystran/geometry.py +0 -0
  78. {pystran-0.2.0 → pystran-0.2.2}/pystran/model.py +0 -0
  79. {pystran-0.2.0 → pystran-0.2.2}/pystran/rigid.py +0 -0
  80. {pystran-0.2.0 → pystran-0.2.2}/pystran/rotation.py +0 -0
  81. {pystran-0.2.0 → pystran-0.2.2}/pystran/section.py +0 -0
  82. {pystran-0.2.0 → pystran-0.2.2}/pystran/spring.py +0 -0
  83. {pystran-0.2.0 → pystran-0.2.2}/pystran/truss.py +0 -0
  84. {pystran-0.2.0 → pystran-0.2.2}/requirements.txt +0 -0
  85. {pystran-0.2.0 → pystran-0.2.2}/scripts/context.py +0 -0
  86. {pystran-0.2.0 → pystran-0.2.2}/tests/context.py +0 -0
  87. {pystran-0.2.0 → pystran-0.2.2}/tests/unittests_space_truss.py +0 -0
  88. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut.cae +0 -0
  89. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut.inp +0 -0
  90. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut2.cae +0 -0
  91. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_12el.inp +0 -0
  92. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_12el_bc.inp +0 -0
  93. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_6el.inp +0 -0
  94. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_a.inp +0 -0
  95. {pystran-0.2.0 → pystran-0.2.2}/tutorials/06_sennett_tut_b.inp +0 -0
  96. {pystran-0.2.0 → pystran-0.2.2}/tutorials/19_garteur_air_frame_vibration_tut.py +0 -0
  97. {pystran-0.2.0 → pystran-0.2.2}/tutorials/20_abaqus_import.py +0 -0
  98. {pystran-0.2.0 → pystran-0.2.2}/tutorials/context.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pystran
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Python Structural Analysis package
5
5
  Project-URL: Homepage, https://github.com/PetrKryslUCSD/pystran
6
6
  Project-URL: Issues, https://github.com/PetrKryslUCSD/pystran/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pystran"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  authors = [
9
9
  { name="Petr Krysl", email="pkrysl@ucsd.edu" },
10
10
  ]
@@ -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,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
  # A gentle introduction to matrices in Python
7
7
 
@@ -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) identifiers for
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
- # For instance, the material parameters and the cross sectional area of the
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 numbers attached.
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 forces in the bars can be simply calculated using the `truss_axial_force`
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,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
  # Three-bar truss example
7
7
 
@@ -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 joint.
11
+ moments at the joints.
12
12
 
13
- Displacements and internal forces are provided in the verification manual.
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 a system of equations. The solution is then
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-1 * norm(ref1):
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-1 * norm(ref2):
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 inchesc
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 zero value of the
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.9e6.
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, and we link the degrees of freedom that needs to be the same.
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 three dimensional frame problem
7
7
 
@@ -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
- # There are diagrams below are for the discrete model that is loaded with the
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
  # Continuous beam with two spans: refine a member into multiple elements
7
7
 
@@ -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
  # Continuous beam with two spans: refine a member into multiple elements
7
7
 
@@ -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 the numbers of finite elements used per member.
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)
@@ -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
  # Statically-determinate truss vibration
7
7
 
@@ -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 3D Frame vibration
7
7
 
@@ -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
  # Natural Frequency of Mass supported by a Beam on Springs
7
7
 
@@ -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
  # Spatial frame with a hinge and spring supports
7
7
 
@@ -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
  # Truss with a combination of loads
7
7
 
@@ -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
  # Penalty enforcement of supports
7
7
 
@@ -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
  # Continuous beam with distributed loading
7
7
 
@@ -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
  # Bending of a quarter circle under out-of-plane force
7
7
 
@@ -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
  # Bending of a two incompressible cantilevers rigidly linked at the free end
7
7
 
@@ -26,8 +26,9 @@ The test-bed was designed and manufactured by ONERA, France.
26
26
  ![](IMAC97photo.png)
27
27
 
28
28
  This tutorial includes also the constraining layer of the wing, which
29
- was not included in the "19_garteur_air_frame_statics_ref_tut.py" tutorial.
30
- The effect of the constraining layer may be overestimated when computing
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
  ![](IMAC97photo.png)
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 metal).
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